mirror of https://github.com/xSmurf/oz.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
3.6 KiB
162 lines
3.6 KiB
package network
|
|
|
|
import (
|
|
//Builtin
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"time"
|
|
|
|
// Internal
|
|
"github.com/op/go-logging"
|
|
|
|
//External
|
|
"github.com/j-keck/arping"
|
|
"github.com/milosgajdos83/tenus"
|
|
)
|
|
|
|
// Setup the networking inside the child
|
|
// Namely setup the loopback interface
|
|
// and the veth interface if requested
|
|
func NetSetup(stn *SandboxNetwork) error {
|
|
if os.Getpid() != 1 {
|
|
panic(errors.New("Cannot use NetSetip from parent."))
|
|
}
|
|
|
|
if err := setupLoopback(stn); err != nil {
|
|
return fmt.Errorf("Unable to setup loopback interface: %+v", err)
|
|
}
|
|
|
|
// If required configure veth
|
|
if stn.VethGuest != "" {
|
|
if err := setupVEth(stn); err != nil {
|
|
return fmt.Errorf("Unable to setup veth interface: %+v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func setupLoopback(stn *SandboxNetwork) error {
|
|
// Bring loopback interface up
|
|
lo, err := tenus.NewLinkFrom("lo")
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to fetch loopback interface, %s.", err)
|
|
}
|
|
|
|
// Bring the link up
|
|
err = lo.SetLinkUp()
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to bring loopback interface up, %s.", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func setupVEth(stn *SandboxNetwork) error {
|
|
ifc, err := tenus.NewLinkFrom(stn.VethGuest)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to fetch inteface %s, %s.", stn.VethGuest, err)
|
|
}
|
|
|
|
// Bring the link down to prepare for renaming
|
|
if err = ifc.SetLinkDown(); err != nil {
|
|
return fmt.Errorf("Unable to bring interface %s down, %s.", stn.VethGuest, err)
|
|
}
|
|
|
|
// Rename the interface to a standard eth0 (not really a necessity)
|
|
if err = tenus.RenameInterface(stn.VethGuest, ozDefaultInterfaceInternal); err != nil {
|
|
return fmt.Errorf("Unable to rename interface %s, %s.", stn.VethGuest, err)
|
|
}
|
|
|
|
// Refetch the interface again as it has changed
|
|
ifc, err = tenus.NewLinkFrom(ozDefaultInterfaceInternal)
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to fetch interface %s, %s.", ozDefaultInterfaceInternal, err)
|
|
}
|
|
|
|
// Bring the link back up
|
|
if err = ifc.SetLinkUp(); err != nil {
|
|
return fmt.Errorf("Unable to bring interface %s up, %s.", ozDefaultInterfaceInternal, err)
|
|
}
|
|
|
|
// Set the link's default gateway
|
|
if err = ifc.SetLinkDefaultGw(&stn.Gateway); err != nil {
|
|
return fmt.Errorf("Unable to set default route %s.", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Try to find an unassigned IP address
|
|
// Do this by first trying two 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 ""
|
|
|
|
}
|