|
|
|
@ -11,15 +11,16 @@ import (
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
//Internal
|
|
|
|
|
"github.com/op/go-logging"
|
|
|
|
|
|
|
|
|
|
//External
|
|
|
|
|
"github.com/op/go-logging"
|
|
|
|
|
"github.com/j-keck/arping"
|
|
|
|
|
"github.com/milosgajdos83/tenus"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func BridgeInit(bridgeMAC string, nmIgnoreFile string, log *logging.Logger) (*HostNetwork, error) {
|
|
|
|
|
if os.Getpid() == 1 {
|
|
|
|
|
panic(errors.New("Cannot use netinit from child."))
|
|
|
|
|
panic(errors.New("Cannot use BridgeInit from child."))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htn := &HostNetwork{
|
|
|
|
@ -39,8 +40,9 @@ func BridgeInit(bridgeMAC string, nmIgnoreFile string, log *logging.Logger) (*Ho
|
|
|
|
|
return nil, fmt.Errorf("Unable to create bridge %+v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
htn.Interface = br
|
|
|
|
|
|
|
|
|
|
if err := htn.configureBridgeInterface(br, log); err != nil {
|
|
|
|
|
if err := htn.configureBridgeInterface(log); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -56,7 +58,17 @@ func BridgeInit(bridgeMAC string, nmIgnoreFile string, log *logging.Logger) (*Ho
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return htn, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (htn *HostNetwork) BridgeReconfigure(log *logging.Logger) error {
|
|
|
|
|
if os.Getpid() == 1 {
|
|
|
|
|
panic(errors.New("Cannot use BridgeReconfigure from child."))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htn.Gateway = nil
|
|
|
|
|
return htn.configureBridgeInterface(log)
|
|
|
|
|
|
|
|
|
|
// TODO: Reconfigure guest networks
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func PrepareSandboxNetwork(htn *HostNetwork, log *logging.Logger) (*SandboxNetwork, error) {
|
|
|
|
@ -79,25 +91,25 @@ func PrepareSandboxNetwork(htn *HostNetwork, log *logging.Logger) (*SandboxNetwo
|
|
|
|
|
|
|
|
|
|
func NetInit(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.Logger) error {
|
|
|
|
|
if os.Getpid() == 1 {
|
|
|
|
|
panic(errors.New("Cannot use netSetup from child."))
|
|
|
|
|
panic(errors.New("Cannot use NetInit from child."))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Seed random number generator (poorly but we're not doing crypto)
|
|
|
|
|
rand.Seed(time.Now().Unix() ^ int64((os.Getpid() + childPid)))
|
|
|
|
|
|
|
|
|
|
log.Info("Configuring host veth pair '%s' with: %s", stn.VethHost, stn.Ip+"/"+htn.Class)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// Fetch the bridge from the ifname
|
|
|
|
|
br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to attach to bridge interface %, %s.", ozDefaultInterfaceBridge, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
// Make sure the bridge is configured and the link is up
|
|
|
|
|
// This really shouldn't be needed, but Network-Manager is a PITA
|
|
|
|
|
// and even if you actualy ignore the interface there's a race
|
|
|
|
|
// between the interface being created and setting it's hwaddr
|
|
|
|
|
//if err := htn.configureBridgeInterface(br, log); err != nil {
|
|
|
|
|
//if err := htn.configureBridgeInterface(log); err != nil {
|
|
|
|
|
// return fmt.Errorf("Unable to reconfigure bridge: %+v", err)
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
@ -114,7 +126,7 @@ func NetInit(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.L
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the host side veth to the bridge
|
|
|
|
|
if err := br.AddSlaveIfc(vethIf); err != nil {
|
|
|
|
|
if err := htn.Interface.AddSlaveIfc(vethIf); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to add veth pair %s to bridge, %s.", stn.VethHost, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -124,8 +136,7 @@ func NetInit(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.L
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assign the veth path to the namespace
|
|
|
|
|
pid := childPid
|
|
|
|
|
if err := veth.SetPeerLinkNsPid(pid); err != nil {
|
|
|
|
|
if err := veth.SetPeerLinkNsPid(childPid); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to add veth pair %s to namespace, %s.", stn.VethHost, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -136,14 +147,35 @@ func NetInit(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.L
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set interface address in the namespace
|
|
|
|
|
if err := veth.SetPeerLinkNetInNs(pid, vethGuestIp, vethGuestIpNet, nil); err != nil {
|
|
|
|
|
if err := veth.SetPeerLinkNetInNs(childPid, vethGuestIp, vethGuestIpNet, nil); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to parse ip link in namespace, %s.", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stn.Veth = veth
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NetReconfigure(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.Logger) error {
|
|
|
|
|
if os.Getpid() == 1 {
|
|
|
|
|
panic(errors.New("Cannot use NetInit from child."))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse the ip/class into the the appropriate formats
|
|
|
|
|
vethGuestIp, vethGuestIpNet, err := net.ParseCIDR(stn.Ip + "/" + htn.Class)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to parse ip %s, %s.", stn.Ip, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set interface address in the namespace
|
|
|
|
|
if err := stn.Veth.SetPeerLinkNetInNs(childPid, vethGuestIp, vethGuestIpNet, nil); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to parse ip link in namespace, %s.", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (stn *SandboxNetwork) Cleanup(log *logging.Logger) {
|
|
|
|
|
if os.Getpid() == 1 {
|
|
|
|
|
panic(errors.New("Cannot use Cleanup from child."))
|
|
|
|
@ -157,10 +189,10 @@ func (stn *SandboxNetwork) Cleanup(log *logging.Logger) {
|
|
|
|
|
tenus.DeleteLink(stn.VethHost)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (htn *HostNetwork) configureBridgeInterface(br tenus.Bridger, log *logging.Logger) error {
|
|
|
|
|
func (htn *HostNetwork) configureBridgeInterface(log *logging.Logger) error {
|
|
|
|
|
// Set the bridge mac address so it can be fucking ignored by Network-Manager.
|
|
|
|
|
if htn.BridgeMAC != "" {
|
|
|
|
|
if err := br.SetLinkMacAddress(htn.BridgeMAC); err != nil {
|
|
|
|
|
if err := htn.Interface.SetLinkMacAddress(htn.BridgeMAC); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to set MAC address for gateway", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -176,7 +208,7 @@ func (htn *HostNetwork) configureBridgeInterface(br tenus.Bridger, log *logging.
|
|
|
|
|
log.Info("Found available range: %+v", htn.GatewayNet.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := br.SetLinkIp(htn.Gateway, htn.GatewayNet); err != nil {
|
|
|
|
|
if err := htn.Interface.SetLinkIp(htn.Gateway, htn.GatewayNet); err != nil {
|
|
|
|
|
if os.IsExist(err) {
|
|
|
|
|
log.Info("Bridge IP appears to be already assigned")
|
|
|
|
|
} else {
|
|
|
|
@ -185,7 +217,7 @@ func (htn *HostNetwork) configureBridgeInterface(br tenus.Bridger, log *logging.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bridge the interface up
|
|
|
|
|
if err := br.SetLinkUp(); err != nil {
|
|
|
|
|
if err := htn.Interface.SetLinkUp(); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to bring bridge '%+v' up: %+v", ozDefaultInterfaceBridge, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -227,6 +259,10 @@ func (htn *HostNetwork) buildBridgeNetwork(addrs []net.Addr) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func FindEmptyRange() (net.IP, *net.IPNet, error) {
|
|
|
|
|
return findEmptyRange()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Look at all the assigned IP address and try to find an available range
|
|
|
|
|
// Returns a ip range in the CIDR form if found or an empty string
|
|
|
|
|
func findEmptyRange() (net.IP, *net.IPNet, error) {
|
|
|
|
@ -246,7 +282,8 @@ func findEmptyRange() (net.IP, *net.IPNet, error) {
|
|
|
|
|
for _, netif := range ifs {
|
|
|
|
|
// Disable loopback and our bridge
|
|
|
|
|
if netif.Name == ozDefaultInterfaceBridge ||
|
|
|
|
|
strings.HasPrefix(netif.Name, "lo") {
|
|
|
|
|
strings.HasPrefix(netif.Name, "lo") ||
|
|
|
|
|
strings.HasPrefix(netif.Name, ozDefaultInterfacePrefix) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -307,3 +344,73 @@ func findEmptyRange() (net.IP, *net.IPNet, error) {
|
|
|
|
|
return nil, nil, errors.New("Could not find an available range")
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to find an unassigned IP address
|
|
|
|
|
// Do this by first trying ozMaxRandTries random IPs or, if that fails, sequentially
|
|
|
|
|
func getFreshIP(min, max uint64, log *logging.Logger) string {
|
|
|
|
|
var newIP string
|
|
|
|
|
|
|
|
|
|
for i := 0; i < ozMaxRandTries; i++ {
|
|
|
|
|
newIP = getRandIP(min, max)
|
|
|
|
|
if newIP != "" {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if newIP == "" {
|
|
|
|
|
log.Notice("Random IP lookup failed %d times, reverting to sequential select", ozMaxRandTries)
|
|
|
|
|
|
|
|
|
|
newIP = getScanIP(min, max)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newIP
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate a random ip and arping it to see if it is available
|
|
|
|
|
// Returns the ip on success or an ip string is the ip is already taken
|
|
|
|
|
func getRandIP(min, max uint64) string {
|
|
|
|
|
if min > max {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dstIP := inet_ntoa(uint64(rand.Int63n(int64(max-min))) + min)
|
|
|
|
|
|
|
|
|
|
arping.SetTimeout(time.Millisecond * 150)
|
|
|
|
|
|
|
|
|
|
_, _, err := arping.PingOverIfaceByName(dstIP, ozDefaultInterfaceBridge)
|
|
|
|
|
|
|
|
|
|
if err == arping.ErrTimeout {
|
|
|
|
|
return dstIP.String()
|
|
|
|
|
} else if err != nil {
|
|
|
|
|
return dstIP.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Go through all possible ips between min and max
|
|
|
|
|
// and arping each one until a free one is found
|
|
|
|
|
func getScanIP(min, max uint64) string {
|
|
|
|
|
if min > max {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := min; i < max; i++ {
|
|
|
|
|
dstIP := inet_ntoa(i)
|
|
|
|
|
|
|
|
|
|
arping.SetTimeout(time.Millisecond * 150)
|
|
|
|
|
|
|
|
|
|
_, _, err := arping.PingOverIfaceByName(dstIP, ozDefaultInterfaceBridge)
|
|
|
|
|
|
|
|
|
|
if err == arping.ErrTimeout {
|
|
|
|
|
return dstIP.String()
|
|
|
|
|
} else if err != nil {
|
|
|
|
|
return dstIP.String()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|