Working networking and minor fixes (mainly config flags)

networking
user 10 years ago
parent 6a4f04721a
commit 48c95599e6

@ -9,6 +9,8 @@ type Config struct {
ProfileDir string `json:"profile_dir"`
ShellPath string `json:"shell_path"`
SandboxPath string `json:"sandbox_path"`
BridgeMACAddr string `json:"bridge_mac"`
NMIgnoreFile string `json:"nm_ignore_file"`
AllowRootShell bool `json:"allow_root_shell"`
LogXpra bool `json:"log_xpra"`
}
@ -20,6 +22,8 @@ func NewDefaultConfig() *Config {
ProfileDir: "/var/lib/oz/cells.d",
ShellPath: "/bin/bash",
SandboxPath: "/srv/oz",
NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf",
BridgeMACAddr: "6A:A8:2E:56:E8:9C",
AllowRootShell: false,
LogXpra: false,
}

@ -116,7 +116,7 @@ func (mi *mountItem) bindItem() error {
target := mi.targetPath()
_, err = os.Stat(target)
if err == nil || !os.IsNotExist(err) {
mi.fs.log.Warning("Target (%s) already exists, ignoring", target)
mi.fs.log.Warning("Target (%s > %s) already exists, ignoring", src, target)
return nil
}
if sinfo.IsDir() {

@ -11,16 +11,16 @@ import (
)
var basicBindDirs = []string{
"/bin", "/lib", "/lib64", "/usr", "/etc", "/var/lib/oz",
"/bin", "/lib", "/lib64", "/usr", "/etc",
}
var basicEmptyDirs = []string{
"/sbin", "/var", "/var/lib",
"/var/cache", "/home", "/boot",
"/tmp", "/run", "/run/user",
"/run/lock", "/root", "/opt",
"/srv", "/dev", "/proc", "/sys",
"/mnt", "/media",
"/run/shm", "/run/lock", "/root",
"/opt", "/srv", "/dev", "/proc",
"/sys", "/mnt", "/media",
}
var basicBlacklist = []string{
@ -39,7 +39,19 @@ var basicSymlinks = [][2]string{
{"/run/lock", "/var/lock"},
}
func (fs *Filesystem) Setup() error {
func (fs *Filesystem) Setup(profilesPath string) error {
profilePathInBindDirs := false
for _, bd := range basicBindDirs {
if bd == profilesPath {
profilePathInBindDirs = true
break;
}
}
if profilePathInBindDirs == false {
basicBindDirs = append(basicBindDirs, profilesPath)
}
if fs.xpra != "" {
if err := fs.createXpraDir(); err != nil {
return err

@ -4,122 +4,232 @@ import(
//Builtin
"errors"
"fmt"
//"math"
"math/rand"
"net"
"os"
//"os/exec"
"strings"
"time"
//Internal
"github.com/op/go-logging"
//External
"github.com/milosgajdos83/tenus"
"github.com/op/go-logging"
)
func BridgeInit(log *logging.Logger) (*HostNetwork, error) {
htn := new(HostNetwork)
func BridgeInit(bridgeMAC string, nmIgnoreFile string, log *logging.Logger) (*HostNetwork, error) {
if os.Getpid() == 1 {
panic(errors.New("Cannot use netinit from child."))
}
// Fetch the bridge interface by ifname
brL, err := net.InterfaceByName(ozDefaultInterfaceBridge)
htn := &HostNetwork{
BridgeMAC: bridgeMAC,
}
if _, err := os.Stat(nmIgnoreFile); os.IsNotExist(err) {
log.Warning("Warning! Network Manager may not properly configured to ignore the bridge interface! This may result in management conflicts!")
}
br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge)
if err != nil {
log.Info("Bridge not found, attempting to create a new one")
_, err = createNewBridge(log)
br, err = tenus.NewBridgeWithName(ozDefaultInterfaceBridge)
if err != nil {
return nil, fmt.Errorf("Unable to create bridge %+v", err)
}
}
// Load the new interface
brL, _ = net.InterfaceByName(ozDefaultInterfaceBridge)
} else {
log.Info("Bridge already exists attempting to reuse it")
if err:= htn.configureBridgeInterface(br, log); err != nil {
return nil, err
}
// Lookup the bridge ip addresses
addrs, _ := brL.Addrs()
if len(addrs) == 0 {
return nil, errors.New("Host bridge does not have an IP address assigned")
brL := br.NetInterface()
addrs, err := brL.Addrs()
if err != nil {
return nil, fmt.Errorf("Unable to get bridgre interface addresses: %+v", err)
}
// Try to build the network config from the bridge's address
addrIndex := -1
for i, addr := range addrs {
bIP, brIP, _ := net.ParseCIDR(addr.String())
// Build the ip range which we will use for the network
if err := htn.buildBridgeNetwork(addrs); err != nil {
return nil, err
}
// Discard IPv6 (TODO...)
if bIP.To4() != nil {
addrIndex = i
return htn, nil
bMask := []byte(brIP.Mask)
}
htn.netmask = net.IPv4(bMask[0], bMask[1], bMask[2], bMask[3])
htn.gateway = net.ParseIP(strings.Split(addr.String(), "/")[0])
htn.class = strings.Split(addr.String(), "/")[1]
htn.broadcast = net_getbroadcast(bIP, brIP.Mask)
func PrepareSandboxNetwork(htn *HostNetwork, log *logging.Logger) (*SandboxNetwork, error) {
stn := new(SandboxNetwork)
htn.min = inet_aton(bIP)
htn.min++
stn.VethHost = tenus.MakeNetInterfaceName(ozDefaultInterfacePrefix)
stn.VethGuest = stn.VethHost + "1"
htn.max = inet_aton(htn.broadcast)
htn.max--
stn.Gateway = htn.Gateway
stn.Class = htn.Class
break
// Allocate a new IP address
stn.Ip = getFreshIP(htn.Min, htn.Max, log)
if stn.Ip == "" {
return nil, errors.New("Unable to acquire random IP")
}
return stn, nil
}
func NetInit(stn *SandboxNetwork, htn *HostNetwork, childPid int, log *logging.Logger) error {
if os.Getpid() == 1 {
panic(errors.New("Cannot use netSetup from child."))
}
if addrIndex < 0 {
return nil, errors.New("Could not find IPv4 for bridge interface")
// 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)
}
return htn, nil
}
// 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 {
// return fmt.Errorf("Unable to reconfigure bridge: %+v", err)
//}
// Create the veth pair
veth, err := tenus.NewVethPairWithOptions(stn.VethHost, tenus.VethOptions{PeerName: stn.VethGuest})
if err != nil {
return fmt.Errorf("Unable to create veth pair %s, %s.", stn.VethHost, err)
}
// Create a new bridge on the host
// Assign it an unused range
// And bring the interface up
func createNewBridge(log *logging.Logger) (tenus.Bridger, error) {
if os.Getpid() == 1 {
panic(errors.New("Cannot use netinit from child."))
// Fetch the newly created hostside veth
vethIf, err := net.InterfaceByName(stn.VethHost)
if err != nil {
return fmt.Errorf("Unable to fetch veth pair %s, %s.", stn.VethHost, err)
}
// Add the host side veth to the bridge
if err := br.AddSlaveIfc(vethIf); err != nil {
return fmt.Errorf("Unable to add veth pair %s to bridge, %s.", stn.VethHost, err)
}
// Bring the host side veth interface up
if err := veth.SetLinkUp(); err != nil {
return fmt.Errorf("Unable to bring veth pair %s up, %s.", stn.VethHost, err)
}
// Assign the veth path to the namespace
pid := childPid
if err := veth.SetPeerLinkNsPid(pid); err != nil {
return fmt.Errorf("Unable to add veth pair %s to namespace, %s.", stn.VethHost, err)
}
// Create the bridge
br, err := tenus.NewBridgeWithName(ozDefaultInterfaceBridge)
// Parse the ip/class into the the appropriate formats
vethGuestIp, vethGuestIpNet, err := net.ParseCIDR(stn.Ip + "/" + htn.Class)
if err != nil {
return nil, err
return fmt.Errorf("Unable to parse ip %s, %s.", stn.Ip, err)
}
// Set interface address in the namespace
if err := veth.SetPeerLinkNetInNs(pid, 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."))
}
if _, err := net.InterfaceByName(stn.VethHost); err != nil {
log.Info("No veth found to cleanup")
return
}
tenus.DeleteLink(stn.VethHost)
}
func (htn *HostNetwork) configureBridgeInterface(br tenus.Bridger, 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 {
return fmt.Errorf("Unable to set MAC address for gateway", err)
}
}
if htn.Gateway == nil {
// Lookup an empty ip range
brIp, brIpNet, err := findEmptyRange(log)
brIp, brIpNet, err := findEmptyRange()
if err != nil {
return nil, errors.New("Could not find an ip range to assign to the bridge")
return fmt.Errorf("Could not find an ip range to assign to the bridge")
}
htn.Gateway = brIp
htn.GatewayNet = brIpNet
log.Info("Found available range: %+v", htn.GatewayNet.String())
}
// Setup the bridge's address
if err := br.SetLinkIp(brIp, brIpNet); err != nil {
return nil, err
if err := br.SetLinkIp(htn.Gateway, htn.GatewayNet); err != nil {
if os.IsExist(err) {
log.Info("Bridge IP appears to be already assigned")
} else {
return fmt.Errorf("Unable to set gateway IP", err)
}
}
// Bridge the interface up
if err = br.SetLinkUp(); err != nil {
return nil, fmt.Errorf("Unable to bring bridge '%+v' up: %+v", ozDefaultInterfaceBridge, err)
if err := br.SetLinkUp(); err != nil {
return fmt.Errorf("Unable to bring bridge '%+v' up: %+v", ozDefaultInterfaceBridge, err)
}
return br, nil
return nil
}
func (htn *HostNetwork)buildBridgeNetwork(addrs []net.Addr) error {
// Try to build the network config from the bridge's address
addrIndex := -1
for i, addr := range addrs {
bIP, brIP, _ := net.ParseCIDR(addr.String())
// Discard IPv6 (TODO...)
if bIP.To4() != nil {
addrIndex = i
bMask := []byte(brIP.Mask)
htn.Netmask = net.IPv4(bMask[0], bMask[1], bMask[2], bMask[3])
htn.Gateway = net.ParseIP(strings.Split(addr.String(), "/")[0])
htn.Class = strings.Split(addr.String(), "/")[1]
htn.Broadcast = net_getbroadcast(bIP, brIP.Mask)
htn.Min = inet_aton(bIP)
htn.Min++
htn.Max = inet_aton(htn.Broadcast)
htn.Max--
break
}
}
if addrIndex < 0 {
return errors.New("Could not find IPv4 for bridge interface")
}
return nil
}
// 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(log *logging.Logger) (net.IP, *net.IPNet, error) {
func findEmptyRange() (net.IP, *net.IPNet, error) {
type localNet struct {
min uint64
max uint64
@ -186,10 +296,9 @@ func findEmptyRange(log *logging.Logger) (net.IP, *net.IPNet, error) {
bMin = bMax - 0xFE
}
// XXX
availableRange = inet_ntoa(bMin).String() + "/24"
log.Info("Found available range: %+v", availableRange)
return net.ParseCIDR(availableRange)
}

@ -2,9 +2,12 @@ package network
import (
//Builtin
"fmt"
"net"
"strings"
"strconv"
"github.com/op/go-logging"
)
const (
@ -16,32 +19,35 @@ const (
)
type HostNetwork struct {
// Host bridge IP address
hostip net.IP
// Gateway ip (bridge ip)
gateway net.IP
Gateway net.IP
// Gateway ip (bridge ip)
GatewayNet *net.IPNet
// Bridge netmask
netmask net.IP
Netmask net.IP
// Broadcast ip
broadcast net.IP
Broadcast net.IP
// IP class (ie: /24)
class string
Class string
// Minimum longip available ip
min uint64
Min uint64
// Maximum longip available ip
max uint64
Max uint64
// Bridge interface MAC Address
BridgeMAC string
}
type SandboxNetwork struct {
// Name of the veth in the host
vethHost string
VethHost string
// Temporary name of the guest' veth in the host
vethGuest string
VethGuest string
// Guest ip address
ip string
host *HostNetwork
Ip string
// Gateway ip (bridge ip)
Gateway net.IP
// IP class (ie: /24)
Class string
}
var privateNetworkRanges []string
@ -66,6 +72,74 @@ func init() {
}
// Print status of the network interfaces
func NetPrint(log *logging.Logger) {
strLine := ""
ifs, _ := net.Interfaces()
strHeader := fmt.Sprintf("%-15.15s%-30.30s%-16.16s%-6.6s", "Interface", "IP", "Mask", "Status")
strHr := ""
ii := len(strHeader)
for i := 0; i < ii; i++ {
strHr += "-"
}
log.Info(strHr)
log.Info(strHeader)
for _, netif := range ifs {
addrs, _ := netif.Addrs()
strLine = fmt.Sprintf("%-15.14s", netif.Name)
if len(addrs) > 0 {
strLine += fmt.Sprintf("%-30.30s", addrs[0])
bIP, brIP, _ := net.ParseCIDR(addrs[0].String())
if bIP.To4() != nil {
bMask := []byte(brIP.Mask)
strLine += fmt.Sprintf("%-16.16s", net.IPv4(bMask[0], bMask[1], bMask[2], bMask[3]).String())
} else {
strLine += fmt.Sprintf("%-16.16s", "")
}
} else {
strLine += fmt.Sprintf("%-30.30s%-16.16s", "", "")
}
if netif.Flags&net.FlagUp == 1 {
strLine += fmt.Sprintf("%-6.6s", "up")
} else {
strLine += fmt.Sprintf("%-6.6s", "down")
}
if len(addrs) > 1 {
strLine += fmt.Sprintf("")
for _, addr := range addrs[1:] {
strLine += fmt.Sprintf("%-15.15s%-30.30s", "", addr)
bIP, brIP, _ := net.ParseCIDR(addr.String())
if bIP.To4() != nil {
bMask := []byte(brIP.Mask)
strLine += fmt.Sprintf("%-20.20s", net.IPv4(bMask[0], bMask[1], bMask[2], bMask[3]).String())
} else {
strLine += fmt.Sprintf("%-16.16s", "")
}
}
}
strLine += fmt.Sprintf("\n")
log.Info(strLine)
}
log.Info(strHr)
}
// Convert longip to net.IP
func inet_ntoa(ipnr uint64) net.IP {
var bytes [4]byte

@ -4,96 +4,41 @@ import (
//Builtin
"errors"
"fmt"
//"math"
"math/rand"
"net"
"os"
"time"
// Internal
"github.com/op/go-logging"
//External
"github.com/j-keck/arping"
"github.com/milosgajdos83/tenus"
"github.com/op/go-logging"
)
func NetInit(log *logging.Logger, htn *HostNetwork, childPid int) (*SandboxNetwork, error) {
if os.Getpid() == 1 {
panic(errors.New("Cannot use netSetup from child."))
}
stn := new(SandboxNetwork)
stn.vethHost = tenus.MakeNetInterfaceName(ozDefaultInterfacePrefix)
stn.vethGuest = stn.vethHost + "1"
// 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", stn.vethHost)
// Fetch the bridge from the ifname
br, err := tenus.BridgeFromName(ozDefaultInterfaceBridge)
if err != nil {
return nil, fmt.Errorf("Unable to attach to bridge interface %, %s.", ozDefaultInterfaceBridge, err)
}
// Create the veth pair
veth, err := tenus.NewVethPairWithOptions(stn.vethHost, tenus.VethOptions{PeerName: stn.vethGuest})
if err != nil {
return nil, fmt.Errorf("Unable to create veth pair %s, %s.", stn.vethHost, err)
}
// Fetch the newly created hostside veth
vethIf, err := net.InterfaceByName(stn.vethHost)
if err != nil {
return nil, fmt.Errorf("Unable to fetch veth pair %s, %s.", stn.vethHost, err)
}
// Add the host side veth to the bridge
if err = br.AddSlaveIfc(vethIf); err != nil {
return nil, fmt.Errorf("Unable to add veth pair %s to bridge, %s.", stn.vethHost, err)
}
// Bring the host side veth interface up
if err = veth.SetLinkUp(); err != nil {
return nil, fmt.Errorf("Unable to bring veth pair %s up, %s.", stn.vethHost, err)
}
// Assign the veth path to the namespace
pid := childPid
if err := veth.SetPeerLinkNsPid(pid); err != nil {
return nil, fmt.Errorf("Unable to add veth pair %s to namespace, %s.", stn.vethHost, err)
// 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."))
}
// Allocate a new IP address
stn.ip = getFreshIP(htn.min, htn.max, log)
if stn.ip == "" {
return nil, errors.New("Unable to acquire random IP")
if err := setupLoopback(stn); err != nil {
return fmt.Errorf("Unable to setup loopback interface: %+v", err)
}
// Parse the ip/class into the the appropriate formats
vethGuestIp, vethGuestIpNet, err := net.ParseCIDR(stn.ip + "/" + htn.class)
if err != nil {
return nil, fmt.Errorf("Unable to parse ip %s, %s.", stn.ip, err)
// If required configure veth
if stn.VethGuest != "" {
if err := setupVEth(stn); err != nil {
return fmt.Errorf("Unable to setup veth interface: %+v", err)
}
// Set interface address in the namespace
if err := veth.SetPeerLinkNetInNs(pid, vethGuestIp, vethGuestIpNet, nil); err != nil {
return nil, fmt.Errorf("Unable to parse ip link in namespace, %s.", err)
}
return stn, nil
return nil
}
// Setup the networking inside the child
// Namely setup the loopback interface
// and the veth interface if requested
func NetSetup(stn *SandboxNetwork, htn *HostNetwork) error {
if os.Getpid() != 1 {
panic(errors.New("Cannot use netChildSetup from child."))
}
func setupLoopback(stn *SandboxNetwork) error {
// Bring loopback interface up
lo, err := tenus.NewLinkFrom("lo")
if err != nil {
@ -106,18 +51,24 @@ func NetSetup(stn *SandboxNetwork, htn *HostNetwork) error {
return fmt.Errorf("Unable to bring loopback interface up, %s.", err)
}
// If required configure veth
if stn.vethGuest != "" {
ifc, err := tenus.NewLinkFrom(stn.vethGuest)
if err == nil {
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)
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)
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
@ -132,17 +83,11 @@ func NetSetup(stn *SandboxNetwork, htn *HostNetwork) error {
}
// Set the link's default gateway
if err = ifc.SetLinkDefaultGw(&htn.gateway); err != nil {
if err = ifc.SetLinkDefaultGw(&stn.Gateway); err != nil {
return fmt.Errorf("Unable to set default route %s.", err)
}
} else {
return fmt.Errorf("Unable to fetch inteface %s, %s.", stn.vethGuest, err)
}
}
return nil
}
// Try to find an unassigned IP address

@ -33,7 +33,6 @@ func Main() {
d.handlePing,
d.handleListProfiles,
d.handleLaunch,
d.handleInitBridgeNetwork,
d.handleListSandboxes,
d.handleClean,
d.handleLogs,
@ -64,14 +63,23 @@ func initialize() *daemonState {
d.nextSboxId = 1
d.nextDisplay = 100
for _, pp := range d.profiles {
if pp.Networking.Nettype == "bridge" {
d.log.Info("Initializing bridge networking")
htn, err := network.BridgeInit(d.log)
htn, err := network.BridgeInit(d.config.BridgeMACAddr, d.config.NMIgnoreFile, d.log)
if err != nil {
d.log.Fatalf("Failed to initialize bridge networking: %+v", err)
return nil
}
d.network = htn
network.NetPrint(d.log)
break;
}
}
return d
}
@ -80,7 +88,7 @@ func (d *daemonState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
for _, sbox := range d.sandboxes {
if sbox.init.Process.Pid == pid {
sbox.remove()
sbox.remove(d.log)
return
}
}
@ -117,7 +125,7 @@ func (d *daemonState) handleLaunch(msg *LaunchMsg, m *ipc.Message) error {
return m.Respond(&ErrorMsg{err.Error()})
}
d.Debug("Would launch %s", p.Name)
_, err = d.launch(p, m.Ucred.Uid, m.Ucred.Gid)
_, err = d.launch(p, m.Ucred.Uid, m.Ucred.Gid, d.log)
if err != nil {
d.Warning("launch of %s failed: %v", p.Name, err)
return m.Respond(&ErrorMsg{err.Error()})
@ -125,12 +133,6 @@ func (d *daemonState) handleLaunch(msg *LaunchMsg, m *ipc.Message) error {
return m.Respond(&OkMsg{})
}
func (d *daemonState) handleInitBridgeNetwork(msg *InitNetworkMsg, m *ipc.Message) error {
d.Debug("Network bridge init message received: %+v", msg)
return m.Respond(&OkMsg{})
}
func (d *daemonState) getProfileByIdxOrName(index int, name string) (*oz.Profile, error) {
if len(name) == 0 {
if index < 1 || index > len(d.profiles) {

@ -3,10 +3,6 @@ package daemon
import (
"bufio"
"fmt"
"github.com/subgraph/oz"
"github.com/subgraph/oz/fs"
"github.com/subgraph/oz/xpra"
"github.com/subgraph/oz/network"
"io"
"os"
"os/exec"
@ -14,6 +10,13 @@ import (
"path"
"sync"
"syscall"
"github.com/subgraph/oz"
"github.com/subgraph/oz/fs"
"github.com/subgraph/oz/xpra"
"github.com/subgraph/oz/network"
"github.com/op/go-logging"
)
const initPath = "/usr/local/bin/oz-init"
@ -43,9 +46,10 @@ func findSandbox(id int) *Sandbox {
return nil
}
*/
const initCloneFlags = syscall.CLONE_NEWNS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWUTS | syscall.CLONE_NEWNET
func createInitCommand(name, chroot string, uid uint32, display int) *exec.Cmd {
func createInitCommand(name, chroot string, uid uint32, display int, stn *network.SandboxNetwork) *exec.Cmd {
cmd := exec.Command(initPath)
cmd.Dir = "/"
cmd.SysProcAttr = &syscall.SysProcAttr{
@ -56,38 +60,59 @@ func createInitCommand(name, chroot string, uid uint32, display int) *exec.Cmd {
"INIT_PROFILE=" + name,
fmt.Sprintf("INIT_UID=%d", uid),
}
if stn.Ip != "" {
cmd.Env = append(cmd.Env, "INIT_ADDR=" + stn.Ip)
cmd.Env = append(cmd.Env, "INIT_VHOST=" + stn.VethHost)
cmd.Env = append(cmd.Env, "INIT_VGUEST=" + stn.VethGuest)
cmd.Env = append(cmd.Env, "INIT_GATEWAY=" + stn.Gateway.String() + "/" + stn.Class)
}
if display > 0 {
cmd.Env = append(cmd.Env, fmt.Sprintf("INIT_DISPLAY=%d", display))
}
return cmd
}
func (d *daemonState) launch(p *oz.Profile, uid, gid uint32) (*Sandbox, error) {
func (d *daemonState) launch(p *oz.Profile, uid, gid uint32, log *logging.Logger) (*Sandbox, error) {
u, err := user.LookupId(fmt.Sprintf("%d", uid))
if err != nil {
return nil, fmt.Errorf("failed to lookup user for uid=%d: %v", uid, err)
}
fs := fs.NewFromProfile(p, u, d.config.SandboxPath, d.log)
if err := fs.Setup(); err != nil {
if err := fs.Setup(d.config.ProfileDir); err != nil {
return nil, err
}
display := 0
if p.XServer.Enabled {
if p.XServer.Enabled && p.Networking.Nettype == "host" {
display = d.nextDisplay
d.nextDisplay += 1
}
cmd := createInitCommand(p.Name, fs.Root(), uid, display)
stn := new(network.SandboxNetwork)
if p.Networking.Nettype == "bridge" {
stn, err = network.PrepareSandboxNetwork(d.network, log)
if err != nil {
return nil, fmt.Errorf("Unable to prepare veth network: %+v", err)
}
}
cmd := createInitCommand(p.Name, fs.Root(), uid, display, stn)
log.Debug("Command environment: %+v", cmd.Env)
pp, err := cmd.StderrPipe()
if err != nil {
fs.Cleanup()
return nil, fmt.Errorf("error creating stderr pipe for init process: %v", err)
}
if err := cmd.Start(); err != nil {
fs.Cleanup()
return nil, err
return nil, fmt.Errorf("Unable to start process: %+v", err)
}
sbox := &Sandbox{
daemon: d,
id: d.nextSboxId,
@ -98,7 +123,17 @@ func (d *daemonState) launch(p *oz.Profile, uid, gid uint32) (*Sandbox, error) {
fs: fs,
addr: path.Join(fs.Root(), "tmp", "oz-init-control"),
stderr: pp,
network: stn,
}
if p.Networking.Nettype == "bridge" {
if err := network.NetInit(stn, d.network, cmd.Process.Pid, log); err != nil {
cmd.Process.Kill()
fs.Cleanup()
return nil, fmt.Errorf("Unable to create veth networking: %+v", err)
}
}
sbox.ready.Add(1)
go sbox.logMessages()
if sbox.profile.XServer.Enabled {
@ -112,11 +147,14 @@ func (d *daemonState) launch(p *oz.Profile, uid, gid uint32) (*Sandbox, error) {
return sbox, nil
}
func (sbox *Sandbox) remove() {
func (sbox *Sandbox) remove(log *logging.Logger) {
sboxes := []*Sandbox{}
for _, sb := range sbox.daemon.sandboxes {
if sb == sbox {
sb.fs.Cleanup()
if sb.profile.Networking.Nettype == "bridge" {
sb.network.Cleanup(log)
}
} else {
sboxes = append(sboxes, sb)
}

@ -35,11 +35,6 @@ type LaunchMsg struct {
Name string
}
type InitNetworkMsg struct {
Index int "NetworkBridge"
Name string
}
type ListSandboxesMsg struct {
_ string "ListSandboxes"
}

@ -3,13 +3,8 @@ package ozinit
import (
"bufio"
"fmt"
"github.com/kr/pty"
"github.com/op/go-logging"
"github.com/subgraph/oz"
"github.com/subgraph/oz/fs"
"github.com/subgraph/oz/ipc"
"github.com/subgraph/oz/xpra"
"io"
"net"
"os"
"os/exec"
"os/user"
@ -17,6 +12,15 @@ import (
"strings"
"sync"
"syscall"
"github.com/subgraph/oz"
"github.com/subgraph/oz/fs"
"github.com/subgraph/oz/ipc"
"github.com/subgraph/oz/xpra"
"github.com/subgraph/oz/network"
"github.com/kr/pty"
"github.com/op/go-logging"
)
const SocketAddress = "/tmp/oz-init-control"
@ -31,6 +35,7 @@ type initState struct {
display int
fs *fs.Filesystem
xpraReady sync.WaitGroup
network *network.SandboxNetwork
}
// By convention oz-init writes log messages to stderr with a single character
@ -63,6 +68,11 @@ func parseArgs() *initState {
uidval := getvar("INIT_UID")
dispval := os.Getenv("INIT_DISPLAY")
stnip := os.Getenv("INIT_ADDR")
stnvhost := os.Getenv("INIT_VHOST")
stnvguest := os.Getenv("INIT_VGUEST")
stngateway := os.Getenv("INIT_GATEWAY")
var config *oz.Config
config, err := oz.LoadConfig(oz.DefaultConfigPath)
if err != nil {
@ -100,6 +110,20 @@ func parseArgs() *initState {
display = d
}
stn := new(network.SandboxNetwork)
if stnip != "" {
gateway, _, err := net.ParseCIDR(stngateway)
if err != nil {
log.Error("Unable to parse network configuration gateway (%s): %v", stngateway, err)
os.Exit(1)
}
stn.Ip = stnip
stn.VethHost = stnvhost
stn.VethGuest = stnvguest
stn.Gateway = gateway
}
return &initState{
log: log,
config: config,
@ -109,11 +133,23 @@ func parseArgs() *initState {
user: u,
display: display,
fs: fs.NewFromProfile(p, u, config.SandboxPath, log),
network: stn,
}
}
func (st *initState) runInit() {
st.log.Info("Starting oz-init for profile: %s", st.profile.Name)
if st.profile.Networking.Nettype != "host" {
//NetSetup(stn *SandboxNetwork, htn *HostNetwork) error
err := network.NetSetup(st.network)
if err != nil {
st.log.Error("Unable to setup networking: %+v", err)
os.Exit(1)
}
}
network.NetPrint(st.log)
if syscall.Sethostname([]byte(st.profile.Name)) != nil {
st.log.Error("Failed to set hostname to (%s)", st.profile.Name)
}
@ -204,7 +240,7 @@ func (st *initState) readXpraOutput(r io.ReadCloser) {
}
func (st *initState) launchApplication() {
cmd := exec.Command(st.profile.Path)
cmd := exec.Command(st.profile.Path + ".unsafe")
stdout, err := cmd.StdoutPipe()
if err != nil {
st.log.Warning("Failed to create stdout pipe: %v", err)
@ -260,7 +296,7 @@ func (st *initState) handleRunShell(rs *RunShellMsg, msg *ipc.Message) error {
if msg.Ucred == nil {
return msg.Respond(&ErrorMsg{"No credentials received for RunShell command"})
}
if msg.Ucred.Uid == 0 || msg.Ucred.Gid == 0 && !st.config.AllowRootShell {
if (msg.Ucred.Uid == 0 || msg.Ucred.Gid == 0) && st.config.AllowRootShell != true {
return msg.Respond(&ErrorMsg{"Cannot open shell because allowRootShell is disabled"})
}
st.log.Info("Starting shell with uid = %d, gid = %d", msg.Ucred.Uid, msg.Ucred.Gid)

Loading…
Cancel
Save