2021-12-21 20:48:07 +01:00
package cmd
import (
2022-07-10 20:48:24 +02:00
"os"
2022-04-24 16:49:54 +02:00
"fmt"
"net"
2023-06-25 23:07:53 +02:00
"sync"
2022-11-20 20:19:37 +01:00
"time"
2022-07-10 20:48:24 +02:00
"errors"
2021-12-21 20:48:07 +01:00
"regexp"
2022-06-26 20:02:28 +02:00
"reflect"
2022-04-18 13:52:44 +02:00
"strconv"
2022-04-24 16:49:54 +02:00
"strings"
2022-07-10 20:48:24 +02:00
"io/ioutil"
2022-06-26 20:02:28 +02:00
"crypto/rand"
"gocage/jail"
"encoding/hex"
2022-07-10 20:48:24 +02:00
"github.com/c-robinson/iplib"
log "github.com/sirupsen/logrus"
2021-12-21 20:48:07 +01:00
)
2022-04-02 14:18:50 +02:00
func mountProcFs ( jail * Jail ) error {
2022-04-02 15:38:24 +02:00
cmd := fmt . Sprintf ( "mount -t procfs proc %s/proc" , jail . RootPath )
2022-04-02 14:18:50 +02:00
_ , err := executeCommand ( cmd )
if err != nil {
return errors . New ( fmt . Sprintf ( "Error mounting procfs on %s/proc: %s" , jail . RootPath , err . Error ( ) ) )
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
return nil
}
func mountLinProcFs ( jail * Jail ) error {
ldir := fmt . Sprintf ( "%s/compat/linux/proc" , jail . RootPath )
_ , err := os . Stat ( ldir )
if os . IsNotExist ( err ) {
errDir := os . MkdirAll ( ldir , 0755 )
if errDir != nil {
return errors . New ( fmt . Sprintf ( "Error creating directory %s: %s" , ldir , errDir . Error ( ) ) )
}
}
2022-04-02 15:38:24 +02:00
cmd := fmt . Sprintf ( "mount -t linprocfs linproc %s" , ldir )
2022-04-02 14:18:50 +02:00
_ , err = executeCommand ( cmd )
if err != nil {
return errors . New ( fmt . Sprintf ( "Error mounting linprocfs on %s: %s" , ldir , err . Error ( ) ) )
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
return nil
}
func mountDevFs ( jail * Jail ) error {
2022-04-02 15:38:24 +02:00
cmd := fmt . Sprintf ( "mount -t devfs dev %s/dev" , jail . RootPath )
2022-04-02 14:18:50 +02:00
_ , err := executeCommand ( cmd )
if err != nil {
return errors . New ( fmt . Sprintf ( "Error mounting devfs on %s/dev: %s" , jail . RootPath , err . Error ( ) ) )
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
return nil
}
func mountFdescFs ( jail * Jail ) error {
// FreeBSD <= 9.3 do not support fdescfs
2022-06-26 20:02:28 +02:00
if gJailHost . version . major < 9 || ( gJailHost . version . major == 9 && gJailHost . version . minor <= 3 ) {
//fmt.Printf(" FreeBSD <= 9.3 does not support fdescfs, disabling in config\n")
2022-04-02 14:18:50 +02:00
jail . Config . Mount_fdescfs = 0
// Tag config so it will be synced on disk
2022-06-26 20:02:28 +02:00
if err := setJailConfigUpdated ( jail ) ; err != nil {
//fmt.Printf(fmt.Sprintf("Error updating config for jail %s: %s", jail.Name, err.Error()))
return err
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
// Should we consider this an error?
return nil
}
2022-04-24 16:49:54 +02:00
2022-04-02 15:38:24 +02:00
cmd := fmt . Sprintf ( "mount -t fdescfs descfs %s/dev/fd" , jail . RootPath )
2022-04-02 14:18:50 +02:00
_ , err := executeCommand ( cmd )
if err != nil {
return errors . New ( fmt . Sprintf ( "Error mounting fdescfs on %s/dev/fd: %s" , jail . RootPath , err . Error ( ) ) )
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
return nil
}
2021-12-21 20:48:07 +01:00
2022-06-26 20:02:28 +02:00
// devfs & fdescfs are automatically mounted by jail binary (seen on FreeBSD 13.1)
2021-12-21 20:48:07 +01:00
func mountAllJailFsFromHost ( jail * Jail ) error {
procfsFound := false
linProcfsFound := false
2022-04-24 16:49:54 +02:00
cmd := "mount -p"
out , err := executeCommand ( cmd )
if err != nil {
return errors . New ( fmt . Sprintf ( "Error executing mount: %s" , err . Error ( ) ) )
}
2021-12-21 20:48:07 +01:00
var outclean [ ] string
2022-04-24 16:49:54 +02:00
remSpPtrn := regexp . MustCompile ( ` \s+ ` )
for _ , l := range strings . Split ( out , "\n" ) {
2021-12-21 20:48:07 +01:00
outclean = append ( outclean , remSpPtrn . ReplaceAllString ( l , " " ) )
}
// Check if these FS are already mounted
for _ , l := range outclean {
2022-04-24 16:49:54 +02:00
f := strings . Split ( l , " " )
if len ( f ) > 2 {
2021-12-21 20:48:07 +01:00
if strings . EqualFold ( f [ 1 ] , fmt . Sprintf ( "%s/proc" , jail . RootPath ) ) {
procfsFound = true
}
if strings . EqualFold ( f [ 1 ] , fmt . Sprintf ( "%s/compat/linux/proc" , jail . RootPath ) ) {
linProcfsFound = true
}
}
}
// Mount wanted FS
if jail . Config . Mount_procfs > 0 && procfsFound == false {
2022-04-02 14:18:50 +02:00
err := mountProcFs ( jail )
2022-04-24 16:49:54 +02:00
if err != nil {
return err
}
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
2021-12-21 20:48:07 +01:00
if jail . Config . Mount_linprocfs > 0 && linProcfsFound == false {
2022-04-02 14:18:50 +02:00
err = mountLinProcFs ( jail )
2022-04-24 16:49:54 +02:00
if err != nil {
return err
}
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
// Ces montages doivent-ils etre effectués une fois le jail démarré?
// FreeBSD <= 9.3 do not support fdescfs
2022-06-26 20:02:28 +02:00
if gJailHost . version . major < 9 || ( gJailHost . version . major == 9 && gJailHost . version . minor <= 3 ) {
if jail . Config . Allow_mount_tmpfs > 0 {
//fmt.Printf(" FreeBSD <= 9.3 does not support tmpfs, disabling in config\n")
jail . Config . Allow_mount_tmpfs = 0
// Tag config so it will be synced on disk
jail . ConfigUpdated = true
err = setJailConfigUpdated ( jail )
if err != nil {
fmt . Printf ( fmt . Sprintf ( "Error updating config for jail %s: %s" , jail . Name , err . Error ( ) ) )
return err
}
2022-04-02 14:18:50 +02:00
}
}
2022-06-26 20:02:28 +02:00
if gJailHost . version . major < 12 {
2022-04-02 14:18:50 +02:00
if jail . Config . Allow_mlock > 0 {
2022-04-24 16:49:54 +02:00
jail . Config . Allow_mlock = 0
2022-06-26 20:02:28 +02:00
if err = setJailConfigUpdated ( jail ) ; err != nil {
//fmt.Printf(fmt.Sprintf("Error updating config for jail %s: %s", jail.Name, err.Error()))
2022-04-02 14:18:50 +02:00
return err
2022-06-26 20:02:28 +02:00
}
2022-04-02 14:18:50 +02:00
}
if jail . Config . Allow_mount_fusefs > 0 {
2022-06-26 20:02:28 +02:00
jail . Config . Allow_mount_fusefs = 0
if err = setJailConfigUpdated ( jail ) ; err != nil {
//fmt.Printf(fmt.Sprintf("Error updating config for jail %s: %s", jail.Name, err.Error()))
return err
}
2022-04-02 14:18:50 +02:00
}
if jail . Config . Allow_vmm > 0 {
2022-06-26 20:02:28 +02:00
jail . Config . Allow_vmm = 0
if err = setJailConfigUpdated ( jail ) ; err != nil {
//fmt.Printf(fmt.Sprintf("Error updating config for jail %s: %s", jail.Name, err.Error()))
return err
}
2022-04-02 14:18:50 +02:00
}
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
return nil
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
// TODO
2022-04-02 14:18:50 +02:00
func prepareJailedZfsDatasets ( jail * Jail ) error {
2021-12-21 20:48:07 +01:00
if jail . Config . Jail_zfs > 0 {
2022-04-02 14:18:50 +02:00
// For jail to mount filesystem, enforce_statfs should be 1 or lower (2 is the default)
2022-06-19 14:48:55 +02:00
if jail . Config . Allow_mount != 1 {
jail . Config . Allow_mount = 1
setJailConfigUpdated ( jail )
}
if jail . Config . Allow_mount_zfs != 1 {
jail . Config . Allow_mount_zfs = 1
setJailConfigUpdated ( jail )
}
2022-04-02 14:18:50 +02:00
// TODO : Overload Json Unmarshalling to fix bad typed values, keeping iocage compatibility
if jail . Config . Enforce_statfs > "1" {
jail . Config . Enforce_statfs = "1"
2022-06-19 14:48:55 +02:00
setJailConfigUpdated ( jail )
2022-04-02 14:18:50 +02:00
}
2021-12-21 20:48:07 +01:00
for _ , d := range strings . Split ( jail . Config . Jail_zfs_dataset , " " ) {
2022-04-02 14:18:50 +02:00
// Check if dataset exist, create if necessary
2023-06-03 11:18:37 +02:00
// Support jailing datasets on differents pools : dataset should be specified with pool name
cmd := fmt . Sprintf ( "zfs get -H creation %s" , d )
2022-04-02 14:18:50 +02:00
out , err := executeCommand ( cmd )
if err != nil {
if strings . HasSuffix ( out , "dataset does not exist" ) {
2023-06-03 11:18:37 +02:00
// Support jailing datasets on differents pools : dataset should be specified with pool name
cmd = fmt . Sprintf ( "zfs create -o compression=lz4 -o mountpoint=none %s" , d )
2022-04-02 14:18:50 +02:00
_ , err = executeCommand ( cmd )
if err != nil {
2023-06-03 11:18:37 +02:00
return errors . New ( fmt . Sprintf ( "Error creating dataset %s: %s" , d , err . Error ( ) ) )
2022-04-02 14:18:50 +02:00
}
} else {
return errors . New ( fmt . Sprintf ( "Error getting zfs dataset %s: %s" , d , err . Error ( ) ) )
}
}
2023-06-03 11:18:37 +02:00
cmd = fmt . Sprintf ( "zfs set jailed=on %s" , d )
2022-04-02 14:18:50 +02:00
out , err = executeCommand ( cmd )
if err != nil {
2023-06-03 11:18:37 +02:00
return errors . New ( fmt . Sprintf ( "Error executing \"zfs set jailed=on %s\": %s" , d , err . Error ( ) ) )
2022-04-02 14:18:50 +02:00
}
2021-12-21 20:48:07 +01:00
}
}
return nil
}
2022-04-02 14:18:50 +02:00
2022-06-26 20:02:28 +02:00
func jailZfsDatasets ( jail * Jail ) error {
2022-07-10 14:16:24 +02:00
if jail . Config . Jail_zfs > 0 {
for _ , d := range strings . Split ( jail . Config . Jail_zfs_dataset , " " ) {
// Jail dataset
2023-06-03 11:18:37 +02:00
// Support jailing datasets on differents pools : dataset should be specified with pool name
cmd := fmt . Sprintf ( "zfs jail %d %s" , jail . JID , d )
2022-07-10 14:16:24 +02:00
out , err := executeCommand ( cmd )
if err != nil {
return errors . New ( fmt . Sprintf ( "Error jailling zfs dataset %s: %v: out" , d , err , out ) )
}
// Mount from inside jail if mountpoint is set
2023-06-03 11:18:37 +02:00
cmd = fmt . Sprintf ( "zfs get -H -o value mountpoint %s" , d )
2022-07-10 14:16:24 +02:00
out , err = executeCommand ( cmd )
2022-06-26 20:02:28 +02:00
if err != nil {
2023-06-03 11:18:37 +02:00
return errors . New ( fmt . Sprintf ( "Error getting zfs dataset %s mountpoint: %v: %s" , d , err , out ) )
2022-07-10 14:16:24 +02:00
}
if len ( out ) > 0 && out != "-" && ( false == strings . EqualFold ( out , "none" ) ) {
2023-06-03 11:18:37 +02:00
// Should we "mount -a" ? cmd = fmt.Sprintf("zfs mount -a")
cmd = fmt . Sprintf ( "zfs mount %s" , d )
2022-07-10 14:16:24 +02:00
out , err = executeCommandInJail ( jail , cmd )
if err != nil {
2022-07-10 16:29:26 +02:00
// If already mounted, continue processing
if ! strings . HasSuffix ( out , "filesystem already mounted\n" ) {
2023-06-03 11:18:37 +02:00
return errors . New ( fmt . Sprintf ( "Error mounting zfs dataset %s from inside jail: %v: %s" , d , err , out ) )
2022-07-10 16:29:26 +02:00
}
2022-07-10 14:16:24 +02:00
}
2022-06-26 20:02:28 +02:00
}
}
}
return nil
}
2022-04-18 13:52:44 +02:00
// tcp(80:8080),tcp(3300-3310:33060-33070)
func getNatForwardsArray ( nat_forwards string , decompose_range bool ) ( [ ] NatDesc , error ) {
var res [ ] NatDesc
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
regx := ` (tcp|udp)\(([0-9] { 1,5}(?:-[0-9] { 1,5})?):([0-9] { 1,5}(?:-[0-9] { 1,5})?)\) `
re := regexp . MustCompile ( regx )
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
for _ , match := range re . FindAllStringSubmatch ( nat_forwards , - 1 ) {
if strings . Contains ( match [ 2 ] , "-" ) == true && decompose_range == true {
sjrange , err := strconv . Atoi ( strings . Split ( match [ 2 ] , "-" ) [ 0 ] )
if err != nil {
return res , err
}
ejrange , err := strconv . Atoi ( strings . Split ( match [ 2 ] , "-" ) [ 1 ] )
if err != nil {
return res , err
}
shrange , err := strconv . Atoi ( strings . Split ( match [ 3 ] , "-" ) [ 0 ] )
if err != nil {
return res , err
}
ehrange , err := strconv . Atoi ( strings . Split ( match [ 3 ] , "-" ) [ 1 ] )
if err != nil {
return res , err
}
if ( ejrange - sjrange ) != ( ehrange - shrange ) {
return res , errors . New ( fmt . Sprintf ( "Invalid port range in nat_forwards: %s" , match [ 0 ] ) )
}
2022-04-24 16:49:54 +02:00
for i := sjrange ; i <= ejrange ; i ++ {
2022-04-18 13:52:44 +02:00
nd := NatDesc { Proto : match [ 1 ] ,
JailPort : strconv . Itoa ( i ) ,
HostPort : strconv . Itoa ( shrange + ( i - sjrange ) ) ,
}
res = append ( res , nd )
}
} else {
nd := NatDesc { Proto : match [ 1 ] ,
2022-04-24 16:49:54 +02:00
JailPort : match [ 2 ] ,
HostPort : match [ 3 ] ,
2022-04-18 13:52:44 +02:00
}
res = append ( res , nd )
}
}
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
return res , nil
}
2021-12-21 20:48:07 +01:00
2022-04-24 16:49:54 +02:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Enable or disables DHCP or accept_rtadv for interfaces declared with this
* option
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
func configureDhcpOrAcceptRtadv ( jail * Jail , ipproto int , enable bool ) error {
var nics [ ] string
// Iocage legacy behavior to enable on all interfaces if Config.Dhcp is set...
if ipproto == IPv4 && jail . Config . Dhcp > 0 || enable == false {
nic_list := strings . Split ( jail . Config . Interfaces , "," )
for _ , n := range nic_list {
nics = append ( nics , strings . Split ( n , ":" ) [ 0 ] )
}
// ...else enable for selected interface in Config.IpX_addr
} else {
if ipproto == IPv4 {
for _ , i := range strings . Split ( jail . Config . Ip4_addr , "," ) {
if strings . EqualFold ( strings . ToLower ( strings . Split ( i , "|" ) [ 1 ] ) , "dhcp" ) {
nics = append ( nics , i )
}
}
} else {
for _ , i := range strings . Split ( jail . Config . Ip6_addr , "," ) {
if strings . EqualFold ( strings . ToLower ( strings . Split ( i , "|" ) [ 1 ] ) , "accept_rtadv" ) {
nics = append ( nics , i )
}
}
}
}
for _ , n := range nics {
// vnet0 is epair0b inside jail
2023-08-05 19:49:59 +02:00
//if strings.Contains(n, "vnet") {
if strings . HasPrefix ( n , "vnet" ) {
splitd := strings . Split ( n , "|" )
n = fmt . Sprintf ( "%sb" , strings . Replace ( splitd [ 0 ] , "vnet" , "epair" , 1 ) )
2022-04-24 16:49:54 +02:00
}
key := fmt . Sprintf ( "ifconfig_%s" , n )
value := "SYNCDHCP"
if ipproto == IPv6 {
key = fmt . Sprintf ( "%s_ipv6" , key )
2024-02-11 11:14:28 +01:00
value = "\"inet6 auto_linklocal accept_rtadv autoconf\""
2022-04-24 16:49:54 +02:00
}
if enable == true {
2023-08-05 19:49:59 +02:00
err := enableRcKeyValue ( fmt . Sprintf ( "%s/etc/rc.conf" , jail . RootPath ) , key , value )
2022-04-24 16:49:54 +02:00
if err != nil {
return fmt . Errorf ( "ERROR setting %s=%s with sysrc for jail %s: %s\n" , key , value , jail . Name , err )
}
} else {
2023-08-05 19:49:59 +02:00
err := disableRcKey ( fmt . Sprintf ( "%s/etc/rc.conf" , jail . RootPath ) , key )
2022-04-24 16:49:54 +02:00
if err != nil {
2022-06-26 20:02:28 +02:00
return fmt . Errorf ( "ERROR deleting %s with sysrc for jail %s: %v\n" , key , jail . Name , err )
2022-04-24 16:49:54 +02:00
}
}
}
return nil
}
func checkRtsold ( jail * Jail ) error {
if strings . Contains ( jail . Config . Ip6_addr , "accept_rtadv" ) == false {
return fmt . Errorf ( "Must set at least one ip6_addr to accept_rtadv!\n" )
}
2024-02-11 11:14:28 +01:00
err := enableRcKeyValue ( fmt . Sprintf ( "%s/etc/rc.conf" , jail . RootPath ) , "rtsold_enable" , "yes" )
2022-04-24 16:49:54 +02:00
if err != nil {
return fmt . Errorf ( "ERROR setting rtsold_enable=YES with sysrc for jail %s: %s\n" , jail . Name , err )
}
return nil
}
func checkNat ( backend string ) error {
cmd := "/sbin/sysctl -q net.inet.ip.forwarding=1"
_ , err := executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "ERROR executing \"/sbin/sysctl -q net.inet.ip.forwarding=1\": %s" , err )
}
if strings . EqualFold ( backend , "pf" ) {
// Load module and enable pf
out , err := executeCommand ( "/sbin/kldload -n pf" )
if err != nil {
if false == strings . Contains ( out , "module already loaded or in kernel" ) {
return fmt . Errorf ( "ERROR executing \"/sbin/kldload pf\": %s" , err )
}
}
out , err = executeCommand ( "/sbin/pfctl -e" )
if err != nil {
if false == strings . Contains ( out , "pf already enabled" ) {
return fmt . Errorf ( "ERROR executing \"/sbin/pfctl -e\": %s" , err )
}
}
} else if strings . EqualFold ( backend , "ipwf" ) {
// Check if module loaded
out , err := executeCommand ( "/sbin/sysctl net.inet.ip.fw.enable=1" )
if err != nil {
if false == strings . Contains ( out , "unknown oid 'net.inet.ip.fw.enable'" ) {
return fmt . Errorf ( "ERROR executing \"/sbin/sysctl net.inet.ip.fw.enable=1\": %s" , err )
}
}
_ , _ = executeCommand ( "/bin/kenv net.inet.ip.fw.default_to_accept=1" )
_ , _ = executeCommand ( "/sbin/kldload -n ipfw" )
_ , _ = executeCommand ( "/sbin/kldload -n ipfw_nat" )
_ , err = executeCommand ( "/sbin/sysctl -q net.inet.ip.fw.enable=1" )
if err != nil {
return fmt . Errorf ( "ERROR executing \"/sbin/sysctl -q net.inet.ip.fw.enable=1\": %s" , err )
}
}
return nil
}
2022-06-26 20:02:28 +02:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Get IPv4 in use in all running jails
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2022-04-24 16:49:54 +02:00
func getJailsInUseIPv4 ( ) ( [ ] string , error ) {
var ips [ ] string
re := regexp . MustCompile ( ifconfigipv4re )
for _ , j := range gJails {
2022-06-26 20:02:28 +02:00
if j . Running == true {
out , err := executeCommandInJail ( & j , "/sbin/ifconfig" )
if err != nil {
return ips , fmt . Errorf ( "ERROR executing \"/sbin/ifconfig\" in jail %s: %s" , j . Name , err )
}
2022-04-24 16:49:54 +02:00
2022-06-26 20:02:28 +02:00
for _ , line := range strings . Split ( out , "\n" ) {
if re . MatchString ( line ) {
ips = append ( ips , re . FindStringSubmatch ( line ) [ 1 ] )
}
2022-04-24 16:49:54 +02:00
}
}
}
return ips , nil
}
func genNatIpv4 ( jail * Jail ) ( [ ] string , error ) {
var ippair [ ] string
// Get all IP in use, host and jails
inuseip4 , err := getHostInUseIPv4 ( )
if err != nil {
return ippair , err
}
ij , err := getJailsInUseIPv4 ( )
if err != nil {
return ippair , err
}
inuseip4 = append ( inuseip4 , ij ... )
// TODO : Voir https://github.com/iocage/iocage/blob/e94863d4c54f02523fb09e62e48be7db9ac92eda/iocage_lib/ioc_common.py#L1026
for i := 0 ; i < 256 ; i ++ {
for j := 0 ; j < 256 ; j += 4 {
n := iplib . NewNet4 ( net . ParseIP ( fmt . Sprintf ( "172.16.%d.%d" , i , j ) ) , 30 )
for _ , ip := range n . Enumerate ( 0 , 0 ) {
ippair = append ( ippair , ip . String ( ) )
}
found := false
for _ , ip := range inuseip4 {
for _ , ipn := range ippair {
if ip == ipn {
found = true
}
}
}
if found == false {
return ippair , nil
}
}
}
return ippair , nil
}
2023-06-25 23:32:15 +02:00
// FIXME : Must lock this function so parallel start do not
func buildDevfsRuleSet ( jail * Jail , m * sync . Mutex ) ( error , int ) {
2022-06-18 11:10:06 +02:00
rulesets := [ ] int { }
2022-06-19 14:48:55 +02:00
2023-06-25 23:32:15 +02:00
m . Lock ( )
//defer m.Unlock()
2022-06-18 11:10:06 +02:00
// Get known rulesets
out , err := executeCommand ( "devfs rule showsets" )
if err != nil {
2023-06-25 23:32:15 +02:00
m . Unlock ( )
2022-06-18 16:10:10 +02:00
return errors . New ( fmt . Sprintf ( "Error executing command \"devfs rule showsets\": %v; command returned: %s\n" , err , out ) ) , 0
2022-06-18 11:10:06 +02:00
}
srs := strings . Split ( out , "\n" )
for _ , i := range srs {
2022-06-26 20:02:28 +02:00
if len ( i ) > 0 {
j , err := strconv . Atoi ( i )
if err != nil {
panic ( err )
}
rulesets = append ( rulesets , j )
2022-06-18 11:10:06 +02:00
}
}
// Build a dynamic ruleset
ruleset := MIN_DYN_DEVFS_RULESET
for _ , r := range rulesets {
if ruleset == r {
ruleset ++
}
}
2023-08-05 19:49:59 +02:00
log . Debugf ( "buildDevfsRuleSet: Build ruleset %d\n" , ruleset )
2022-06-19 14:48:55 +02:00
2022-06-18 20:08:12 +02:00
// Get default devfs_ruleset for the datastore
2022-06-19 14:48:55 +02:00
// UPDATE: We don't need this as every jail have a default Devfs_ruleset value
/ * ds , err := getDatastoreFromArray ( jail . Datastore , gDatastores )
2022-06-18 20:08:12 +02:00
if err != nil {
2023-06-25 23:32:15 +02:00
m . Unlock ( )
2022-06-18 20:08:12 +02:00
return errors . New ( fmt . Sprintf ( "Error getting datastore %s for jail %s" , jail . Datastore , jail . Name ) ) , 0
}
defaultrs , err := strconv . ParseInt ( ds . DefaultJailConfig . Devfs_ruleset , 10 , 64 )
if err != nil {
2023-06-25 23:32:15 +02:00
m . Unlock ( )
2022-06-18 20:08:12 +02:00
return errors . New ( fmt . Sprintf ( "Error parsing default devfs_ruleset for datastore %s" , jail . Datastore ) ) , 0
2022-06-19 14:48:55 +02:00
} * /
2022-06-18 20:08:12 +02:00
2022-06-19 14:48:55 +02:00
// Clone configured devfs_ruleset to a dynamic ruleset
2022-06-18 20:08:12 +02:00
if false == isStringInArray ( srs , jail . Config . Devfs_ruleset ) {
2023-06-25 23:32:15 +02:00
m . Unlock ( )
2022-06-18 20:08:12 +02:00
return errors . New ( fmt . Sprintf ( "Unknown ruleset: %s" , jail . Config . Devfs_ruleset ) ) , 0
}
rs , _ := strconv . Atoi ( jail . Config . Devfs_ruleset )
2022-06-19 14:48:55 +02:00
err = copyDevfsRuleset ( ruleset , rs )
2023-06-25 23:32:15 +02:00
m . Unlock ( )
2022-06-18 20:08:12 +02:00
if err != nil {
return err , 0
}
// Add rules for enabled options
if jail . Config . Allow_mount_fusefs > 0 {
err := addDevfsRuleToRuleset ( "path fuse unhide" , ruleset )
if err != nil {
return err , 0
2022-06-18 11:10:06 +02:00
}
2022-06-18 20:08:12 +02:00
}
if jail . Config . Bpf > 0 {
err := addDevfsRuleToRuleset ( "path bpf* unhide" , ruleset )
2022-06-18 11:10:06 +02:00
if err != nil {
2022-06-18 20:08:12 +02:00
return err , 0
2022-06-18 11:10:06 +02:00
}
2022-06-18 20:08:12 +02:00
}
if jail . Config . Allow_tun > 0 {
err := addDevfsRuleToRuleset ( "path tun* unhide" , ruleset )
if err != nil {
return err , 0
2022-06-18 11:10:06 +02:00
}
}
2022-06-18 20:08:12 +02:00
return nil , ruleset
2022-06-18 11:10:06 +02:00
}
2022-06-19 14:48:55 +02:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Build the file containing jail start parameters , in
* / var / run / jail . $ { jail_internal_name } . conf
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
func buildJailParameters ( jail * Jail , dynruleset int ) error {
parameterFilePath := fmt . Sprintf ( "/var/run/jail.%s.conf" , jail . InternalName )
pfile , err := os . Create ( parameterFilePath )
if err != nil {
return errors . New ( fmt . Sprintf ( "Unable to create file /var/run/jail.%d.conf" , jail . InternalName ) )
}
defer pfile . Close ( )
if _ , err = pfile . WriteString ( fmt . Sprintf ( "%s {\n" , jail . InternalName ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if jail . Config . Vnet > 0 {
if _ , err = pfile . WriteString ( " vnet;\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
// FreeBSD 9.3 and under do not support these 2 options
if gJailHost . version . major > 9 || ( gJailHost . version . major == 9 && gJailHost . version . minor > 3 ) {
if _ , err = pfile . WriteString ( " mount.fdescfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if jail . Config . Allow_mount_tmpfs > 0 {
if _ , err = pfile . WriteString ( " allow.mount.tmpfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
}
if gJailHost . version . major >= 12 {
if jail . Config . Allow_mlock > 0 {
if _ , err = pfile . WriteString ( " allow.mlock = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_mount_fusefs > 0 {
if _ , err = pfile . WriteString ( " allow.mount.fusefs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_vmm > 0 {
if _ , err = pfile . WriteString ( " allow.vmm = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
}
if jail . Config . Allow_set_hostname > 0 {
if _ , err = pfile . WriteString ( " allow.set_hostname = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Mount_devfs > 0 {
if _ , err = pfile . WriteString ( " mount.devfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_raw_sockets > 0 {
if _ , err = pfile . WriteString ( " allow.raw_sockets = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_sysvipc > 0 {
if _ , err = pfile . WriteString ( " allow.sysvipc = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_quotas > 0 {
if _ , err = pfile . WriteString ( " allow.quotas = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_socket_af > 0 {
if _ , err = pfile . WriteString ( " allow.socket_af = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_chflags > 0 {
if _ , err = pfile . WriteString ( " allow.chflags = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_mount > 0 {
if _ , err = pfile . WriteString ( " allow.mount = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_mount_devfs > 0 {
if _ , err = pfile . WriteString ( " allow.mount.devfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_mount_nullfs > 0 {
if _ , err = pfile . WriteString ( " allow.mount.nullfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_mount_procfs > 0 {
if _ , err = pfile . WriteString ( " allow.mount.procfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if jail . Config . Allow_mount_zfs > 0 {
if _ , err = pfile . WriteString ( " allow.mount.zfs = \"1\";\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if gJailHost . version . major > 10 || ( gJailHost . version . major == 10 && gJailHost . version . minor > 3 ) {
if _ , err = pfile . WriteString ( fmt . Sprintf ( " sysvmsg = \"%s\";\n" , jail . Config . Sysvmsg ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " sysvsem = \"%s\";\n" , jail . Config . Sysvsem ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " sysvshm = \"%s\";\n" , jail . Config . Sysvshm ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if gJailHost . version . major >= 12 {
if _ , err = pfile . WriteString ( fmt . Sprintf ( " exec.created = \"%s\";\n" , jail . Config . Exec_created ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " host.domainname = \"%s\";\n" , jail . Config . Host_domainname ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " host.hostname = \"%s\";\n" , jail . Config . Host_hostname ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " path = \"%s\";\n" , jail . RootPath ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " securelevel = \"%s\";\n" , jail . Config . Securelevel ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
// FIXME : Handle the same name jail on different datastores
if _ , err = pfile . WriteString ( fmt . Sprintf ( " host.hostuuid = \"%s\";\n" , jail . Config . Host_hostuuid ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " devfs_ruleset = \"%d\";\n" , dynruleset ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " enforce_statfs = \"%s\";\n" , jail . Config . Enforce_statfs ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " children.max = \"%s\";\n" , jail . Config . Children_max ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " exec.clean = \"%d\";\n" , jail . Config . Exec_clean ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " exec.timeout = \"%s\";\n" , jail . Config . Exec_timeout ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( fmt . Sprintf ( " stop.timeout = \"%s\";\n" , jail . Config . Stop_timeout ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
splits := strings . Split ( jail . RootPath , "/" )
fstabPath := strings . Join ( append ( splits [ : len ( splits ) - 1 ] ,
strings . Replace ( splits [ len ( splits ) - 1 ] , "root" , "fstab" , 1 ) ) , "/" )
if _ , err = pfile . WriteString ( fmt . Sprintf ( " mount.fstab = \"%s\";\n" , fstabPath ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( " allow.dying;\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
// get current datastore to get mountpoint
ds , err := getDatastoreFromArray ( jail . Datastore , gDatastores )
if err != nil {
return errors . New ( fmt . Sprintf ( "Unable to get datastore %s for jail %s" , jail . Datastore , jail . Name ) )
}
consolelog := fmt . Sprintf ( "%s/log/%s-console.log" , ds . Mountpoint , jail . InternalName )
if _ , err = pfile . WriteString ( fmt . Sprintf ( " exec.consolelog = \"%s\";\n" , consolelog ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if jail . Config . Ip_hostname > 0 {
if _ , err = pfile . WriteString ( fmt . Sprintf ( " ip_hostname = \"%s\";\n" , jail . Config . Ip_hostname ) ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
}
if _ , err = pfile . WriteString ( " persist;\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
if _ , err = pfile . WriteString ( "}\n" ) ; err != nil {
return errors . New ( fmt . Sprintf ( "Unable to write to file /var/run/jail.%d.conf: %v" , jail . InternalName , err ) )
}
return nil
}
2022-06-26 20:02:28 +02:00
func setJailVnetIp ( jail * Jail , nic string , ip string ) error {
if strings . Contains ( ip , ":" ) {
if jail . Config . Dhcp == 0 && false == strings . EqualFold ( ip , "dhcp" ) {
cmd := fmt . Sprintf ( "/sbin/ifconfig %s inet6 %s up" , nic , ip )
_ , err := executeCommandInJail ( jail , cmd )
if err != nil {
return fmt . Errorf ( "Error setting network inside jail: %v" , err )
}
}
} else {
if jail . Config . Dhcp == 0 && false == strings . EqualFold ( ip , "dhcp" ) {
// vnetX is epairXb inside the jail
cmd := fmt . Sprintf ( "/sbin/ifconfig %s %s up" , nic , ip )
_ , err := executeCommandInJail ( jail , cmd )
if err != nil {
return fmt . Errorf ( "Error setting network inside jail: %v" , err )
}
}
}
return nil
}
// Generate a MAC address for the jail and save in config
// Returns host-side MAC, jail-side MAC, error
func generateMAC ( jail * Jail , nic string ) ( [ ] byte , [ ] byte , error ) {
var prefix [ ] byte
var err error
if len ( jail . Config . Mac_prefix ) > 0 {
prefix , err = hex . DecodeString ( jail . Config . Mac_prefix )
if err != nil {
return [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , err
}
} else {
ds , err := getDatastoreFromArray ( jail . Datastore , gDatastores )
if err != nil {
return [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , err
}
prefix , err = hex . DecodeString ( ds . DefaultJailConfig . Mac_prefix )
if err != nil {
return [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , err
}
}
// Set the local bit, ensure unicast address
//prefix[0] = (prefix[0] | 2) & 0xfe
suffix := make ( [ ] byte , ( 6 - len ( prefix ) ) )
_ , err = rand . Read ( suffix )
if err != nil {
return [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , err
}
hsmac := append ( prefix , suffix ... )
2024-02-11 10:17:31 +01:00
jsmac := make ( [ ] byte , 6 )
copy ( jsmac , hsmac )
jsmac [ 5 ] = jsmac [ 5 ] + 1
2022-06-26 20:02:28 +02:00
// Save MACs to config
pname := fmt . Sprintf ( "Config.%s_mac" , strings . Title ( nic ) )
err = setStructFieldValue ( jail , pname , fmt . Sprintf ( "%s %s" , hex . EncodeToString ( hsmac ) , hex . EncodeToString ( jsmac ) ) )
if err != nil {
return [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , [ ] byte { 0 , 0 , 0 , 0 , 0 , 0 } , fmt . Errorf ( "Error setting %s for jail %s: %s\n" , pname , jail . Name , err . Error ( ) )
}
setJailConfigUpdated ( jail )
return hsmac , jsmac , nil
}
// Setup interface host side
// Returns array of epair names, error
func setupVnetInterfaceHostSide ( jail * Jail ) ( [ ] string , error ) {
var epairs [ ] string
var jsnic string
var hsmac [ ] byte
var err error
for _ , nicCnf := range strings . Split ( jail . Config . Interfaces , "," ) {
v := strings . Split ( nicCnf , ":" )
if len ( v ) != 2 {
return [ ] string { } , fmt . Errorf ( "Invalid value for Interfaces: %s\n" , nicCnf )
}
nic := v [ 0 ]
bridge := v [ 1 ]
// Get host side MAC
2023-11-09 19:17:39 +01:00
pname := fmt . Sprintf ( "Config.%s_mac" , strings . Title ( nic ) )
2022-06-26 20:02:28 +02:00
var val * reflect . Value
val , pname , err = getStructFieldValue ( jail , pname )
if err != nil {
if strings . HasPrefix ( err . Error ( ) , "Field not found" ) {
hsmac , _ , err = generateMAC ( jail , nic )
if err != nil {
return [ ] string { } , err
}
} else {
return [ ] string { } , err
}
} else {
2024-02-11 10:17:31 +01:00
if strings . EqualFold ( val . String ( ) , "none" ) {
hsmac , _ , err = generateMAC ( jail , nic )
if err != nil {
return [ ] string { } , err
}
}
2023-11-09 19:17:39 +01:00
hsmac , err = hex . DecodeString ( strings . Split ( val . String ( ) , " " ) [ 0 ] )
if err != nil {
return [ ] string { } , fmt . Errorf ( "Error converting %s to hex\n" , strings . Split ( val . String ( ) , " " ) [ 0 ] )
}
2022-06-26 20:02:28 +02:00
}
// Get bridge MTU
mtu , err := gJailHost . GetBridgeMTU ( bridge )
if err != nil {
2024-08-20 11:29:56 +02:00
return [ ] string { } , fmt . Errorf ( "Error getting bridge \"%s\" mtu: %v\n" , bridge , err )
2022-06-26 20:02:28 +02:00
}
// Create epair interface
out , err := executeCommand ( "/sbin/ifconfig epair create" )
if err != nil {
return [ ] string { } , fmt . Errorf ( "Error creating epair interface: %v\n" , err )
}
hsepair := strings . TrimRight ( out , "\n" )
if true == strings . Contains ( nic , "vnet" ) {
jsnic = strings . Replace ( nic , "vnet" , "epair" , 1 ) + "b"
} else {
jsnic = nic
}
// Name epair and set MTU
cmd := fmt . Sprintf ( "/sbin/ifconfig %s name %s.%d mtu %d" , hsepair , nic , jail . JID , mtu )
out , err = executeCommand ( cmd )
if err != nil {
return [ ] string { } , fmt . Errorf ( "Error creating epair interface host side: %v\n" , err )
}
cmd = fmt . Sprintf ( "/sbin/ifconfig %s.%d link %s" , nic , jail . JID , hex . EncodeToString ( hsmac ) )
out , err = executeCommand ( cmd )
if err != nil {
return [ ] string { } , fmt . Errorf ( "Error setting mac host side: %v\n" , err )
}
cmd = fmt . Sprintf ( "/sbin/ifconfig %s.%d description \"associated with jail: %s as nic: %s\"" , nic , jail . JID , jail . Name , jsnic )
out , err = executeCommand ( cmd )
if err != nil {
return [ ] string { } , fmt . Errorf ( "Error setting nic description: %v\n" , err )
}
epairs = append ( epairs , hsepair )
}
2023-08-05 19:49:59 +02:00
log . Debugf ( "setupVnetInterfaceHostSide: returning %v\n" , epairs )
2022-06-26 20:02:28 +02:00
return epairs , nil
}
2023-08-06 14:50:32 +02:00
func setupVnetInterfaceJailSide ( jail * Jail , hostepairs [ ] string ) error {
2022-06-26 20:02:28 +02:00
var jsmac [ ] byte
var err error
// Maps of IP by netcard (Ex: jailIp4s["vnet0"] = "192.168.1.1")
var ip4s = make ( map [ string ] string )
var ip6s = make ( map [ string ] string )
for _ , i := range strings . Split ( jail . Config . Ip4_addr , "," ) {
v := strings . Split ( i , "|" )
2024-02-11 10:17:31 +01:00
if len ( v ) > 1 {
ip4s [ v [ 0 ] ] = v [ 1 ]
}
2022-06-26 20:02:28 +02:00
}
for _ , i := range strings . Split ( jail . Config . Ip6_addr , "," ) {
v := strings . Split ( i , "|" )
if len ( v ) > 1 {
ip6s [ v [ 0 ] ] = v [ 1 ]
}
}
// Loop through configured interfaces
2023-08-06 14:50:32 +02:00
for i , nicCnf := range strings . Split ( jail . Config . Interfaces , "," ) {
2022-06-26 20:02:28 +02:00
v := strings . Split ( nicCnf , ":" )
if len ( v ) != 2 {
return fmt . Errorf ( "Invalid value for Interfaces: %s\n" , nicCnf )
}
// vnet nic name
nic := v [ 0 ]
bridge := v [ 1 ]
// inside jail final nic name
jnic := strings . Replace ( v [ 0 ] , "vnet" , "epair" , 1 )
jnic = jnic + "b"
2023-08-06 14:50:32 +02:00
// host side associated jail nic name
jsepair := fmt . Sprintf ( "%sb" , strings . TrimSuffix ( hostepairs [ i ] , "a" ) )
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
// Get jail side MAC
2023-11-09 19:17:39 +01:00
pname := fmt . Sprintf ( "Config.%s_mac" , strings . Title ( nic ) )
2022-06-26 20:02:28 +02:00
var val * reflect . Value
val , pname , err = getStructFieldValue ( jail , pname )
if err != nil {
if strings . HasPrefix ( err . Error ( ) , "Field not found" ) {
_ , jsmac , err = generateMAC ( jail , nic )
if err != nil {
return err
}
} else {
return err
}
} else {
2023-11-09 19:17:39 +01:00
jsmac , err = hex . DecodeString ( strings . Split ( val . String ( ) , " " ) [ 1 ] )
if err != nil {
return fmt . Errorf ( "Error converting %s to hex\n" , strings . Split ( val . String ( ) , " " ) [ 1 ] )
}
2022-06-26 20:02:28 +02:00
}
2023-08-05 19:49:59 +02:00
2023-08-06 14:50:32 +02:00
cmd := fmt . Sprintf ( "/sbin/ifconfig %s vnet %s" , jsepair , jail . InternalName )
2022-06-26 20:02:28 +02:00
_ , err := executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "Error linking interface to jail: %v\n" , err )
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
// Get bridge MTU
mtu , err := gJailHost . GetBridgeMTU ( bridge )
if err != nil {
2024-08-20 11:29:56 +02:00
return fmt . Errorf ( "Error getting bridge \"%s\" mtu: %v\n" , bridge , err )
2022-06-26 20:02:28 +02:00
}
2023-08-05 19:49:59 +02:00
2023-08-06 14:50:32 +02:00
cmd = fmt . Sprintf ( "/usr/sbin/jexec %d ifconfig %s mtu %d" , jail . JID , jsepair , mtu )
2022-06-26 20:02:28 +02:00
_ , err = executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "Error setting mtu: %v\n" , err )
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
// rename epairXXb to epair0b (or opair1b, ...)
2023-08-06 14:50:32 +02:00
cmd = fmt . Sprintf ( "/usr/sbin/setfib %s jexec %d ifconfig %s name %s" , jail . Config . Exec_fib , jail . JID , jsepair , jnic )
2022-06-26 20:02:28 +02:00
_ , err = executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "Error linking interface to jail: %v\n" , err )
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
cmd = fmt . Sprintf ( "/usr/sbin/setfib %s jexec %d ifconfig %s link %s" , jail . Config . Exec_fib ,
jail . JID , jnic , hex . EncodeToString ( jsmac ) )
_ , err = executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "Error setting mac: %v\n" , err )
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
// TODO: Move outside of this function
// add interface to bridge
if jail . Config . Nat == 0 {
cmd := fmt . Sprintf ( "/sbin/ifconfig %s addm %s.%d up" , bridge , nic , jail . JID )
out , err := executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "Error adding member %s to %s: %v: %s\n" , nic , bridge , err , out )
}
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
// Check we have an IP for the nic, and set it into jail
if len ( ip4s [ nic ] ) > 0 {
err = setJailVnetIp ( jail , jnic , ip4s [ nic ] )
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
if len ( ip6s [ nic ] ) > 0 {
err = setJailVnetIp ( jail , jnic , ip6s [ nic ] )
}
2023-08-05 19:49:59 +02:00
2022-06-26 20:02:28 +02:00
// finally up interface
if jail . Config . Nat == 0 {
cmd := fmt . Sprintf ( "/sbin/ifconfig %s.%d up" , nic , jail . JID )
out , err := executeCommand ( cmd )
if err != nil {
return fmt . Errorf ( "Error upping interface %s.%d: %v: %s\n" , nic , jail . JID , err , out )
}
}
}
2023-08-05 19:49:59 +02:00
log . Debugf ( "setupVnetInterfaceJailSide: return with success\n" )
2022-06-26 20:02:28 +02:00
return nil
}
2022-07-10 20:48:24 +02:00
func generateResolvConf ( jail * Jail ) error {
if jail . Config . Resolver != "/etc/resolv.conf" && jail . Config . Resolver != "none" && jail . Config . Resolver != "/dev/null" {
f , err := os . Create ( fmt . Sprintf ( "%s/etc/resolv.conf" , jail . RootPath ) )
if err != nil {
return err
}
defer f . Close ( )
for _ , l := range strings . Split ( jail . Config . Resolver , ";" ) {
f . WriteString ( fmt . Sprintf ( "%s\n" , l ) )
}
2023-06-03 11:18:37 +02:00
} else if jail . Config . Resolver == "none" || jail . Config . Resolver == "/etc/resolv.conf" {
2022-07-10 20:48:24 +02:00
read , err := ioutil . ReadFile ( "/etc/resolv.conf" )
if err != nil {
return fmt . Errorf ( "Error opening /etc/resolv.conf: %v" , err )
}
err = ioutil . WriteFile ( fmt . Sprintf ( "%s/etc/resolv.conf" , jail . RootPath ) , read , 0644 )
if err != nil {
return fmt . Errorf ( "Error writing to %s/etc/resolv.conf: %v" , jail . RootPath , err )
}
} else if jail . Config . Resolver == "/dev/null" {
// Just do nothing
}
return nil
}
func copyLocalTime ( jail * Jail ) error {
if jail . Config . Host_time > 0 {
read , err := ioutil . ReadFile ( "/etc/localtime" )
if err != nil {
return fmt . Errorf ( "Error opening /etc/localtime: %v" , err )
}
err = ioutil . WriteFile ( fmt . Sprintf ( "%s/etc/localtime" , jail . RootPath ) , read , 0644 )
if err != nil {
return fmt . Errorf ( "Error writing to %s/etc/localtime: %v" , jail . RootPath , err )
}
}
return nil
}
2022-06-26 20:02:28 +02:00
// TODO: Umount all FS
// TODO: Delete devfs ruleset
// TODO: Remove /var/run/jail-${internalname}.conf
func cleanAfterStartCrash ( ) {
}
2022-06-19 14:48:55 +02:00
2022-10-15 14:53:43 +02:00
// Start all jails with boot=true, in priority order
func StartJailsAtBoot ( ) {
var startList [ ] Jail
2023-06-25 23:07:53 +02:00
var wg * sync . WaitGroup
var curThNb int
var curPri int
2022-10-15 14:53:43 +02:00
2023-08-06 14:50:32 +02:00
// Get boot enabled non-template jails
2022-10-15 14:53:43 +02:00
for _ , j := range gJails {
2023-08-06 14:50:32 +02:00
if j . Config . Boot > 0 && ! strings . EqualFold ( j . Config . Jailtype , "template" ) {
2022-10-15 14:53:43 +02:00
startList = append ( startList , j )
}
}
// Order by priority
js := initJailSortStruct ( )
fct , _ , err := getStructFieldValue ( js , "Config.PriorityInc" )
if err != nil {
log . Errorf ( "ERROR getting JailSort struct field \"Config.PriorityInc\"\n" )
return
}
JailsOrderedBy ( fct . Interface ( ) . ( jailLessFunc ) ) . Sort ( startList )
2023-06-25 23:07:53 +02:00
wg = new ( sync . WaitGroup )
curThNb = 0
for i , j := range startList {
2022-10-15 14:53:43 +02:00
jFullName := fmt . Sprintf ( "%s/%s" , j . Datastore , j . Name )
log . Debugf ( "Starting %s with priority %s\n" , jFullName , j . Config . Priority )
2023-06-25 23:07:53 +02:00
jailPri , err := strconv . Atoi ( j . Config . Priority )
if err != nil {
panic ( fmt . Sprintf ( "Invalid format for Priority (Jail %s)\n" , jFullName ) )
}
if ( curThNb >= gMaxThreads || i == 0 ) {
// FIXME : Use a pool instead of waiting for all threads to run a new one
wg . Wait ( )
curThNb = 0
wg . Add ( 1 )
curThNb ++
curPri = jailPri
go func ( jailFullName string ) {
defer wg . Done ( )
StartJail ( [ ] string { jailFullName } )
} ( jFullName )
} else {
if ( curPri == jailPri ) {
wg . Add ( 1 )
curThNb ++
go func ( jailFullName string ) {
defer wg . Done ( )
StartJail ( [ ] string { jailFullName } )
} ( jFullName )
} else {
wg . Wait ( )
curThNb = 0
wg . Add ( 1 )
curThNb ++
curPri = jailPri
go func ( jailFullName string ) {
defer wg . Done ( )
StartJail ( [ ] string { jailFullName } )
} ( jFullName )
}
}
2022-10-15 14:53:43 +02:00
}
2023-06-25 23:07:53 +02:00
wg . Wait ( )
2022-10-15 14:53:43 +02:00
}
2021-12-21 20:48:07 +01:00
/ *
Start jail :
Check jail fstab ?
Mount procfs
Mount linprocfs
Mount devfs ?
Mount fdescfs ?
If jail_zfs , then check jail_zfs_dataset exist ( and create otherwise )
TODO : Check NAT settings and compatibility with other jails
Generate devfsruleset from configured
Write config file in / var / run / jails . ioc - $ NAME . conf
Execute PreStart ( Exec_prestart )
Start jail ( With ENV VARS for network conf )
Start networking
Mount jail_zfs_datasets inside jail
Generate resolv . Conf
Copy / etc / localtime into jail ( ? )
Configure NAT
Execute Exec_start into jail
Execute Exec_poststart
If DHCP , check with ifconfig inside jail
Set RCTL Rules
Use setfib for each jail command
* /
func StartJail ( args [ ] string ) {
// jail we have to start
var cj * Jail
2022-04-24 16:49:54 +02:00
var err error
2022-07-10 14:16:24 +02:00
for _ , a := range args {
// Check if jail exist and is distinctly named
2023-08-06 14:50:32 +02:00
cj , err = getJailFromArray ( a , [ ] string { "basejail" , "jail" } , gJails )
2022-07-10 14:16:24 +02:00
if err != nil {
fmt . Printf ( "Error getting jail: %s\n" , err )
2021-12-21 20:48:07 +01:00
continue
}
2022-04-24 16:49:54 +02:00
2021-12-21 20:48:07 +01:00
if cj . Running == true {
2022-10-15 14:53:43 +02:00
fmt . Printf ( "Jail %s/%s is already running!\n" , cj . Datastore , cj . Name )
2021-12-21 20:48:07 +01:00
continue
}
2022-06-26 20:02:28 +02:00
2023-07-09 13:41:19 +02:00
fmt . Printf ( "> Starting jail %s\n" , cj . Name )
2023-08-06 14:50:32 +02:00
2022-06-26 20:02:28 +02:00
// Set InternalName as it is used by some of these
cj . InternalName = fmt . Sprintf ( "ioc-%s" , cj . Name )
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
if len ( cj . Config . Hostid ) > 0 && cj . Config . Hostid_strict_check > 0 {
2022-06-19 14:48:55 +02:00
if strings . EqualFold ( gJailHost . hostid , cj . Config . Hostid ) == false {
2022-04-05 22:21:39 +02:00
fmt . Printf ( "hostid is not matching and hostid_strict_check is on. Not starting jail.\n" )
return
}
}
2022-04-24 16:49:54 +02:00
2022-04-05 22:21:39 +02:00
var props_missing [ ] string
2022-04-24 16:49:54 +02:00
// DHCP can also be set with "dhcp" value in ip4_addr (Eg: "vnet0|dhcp")
if cj . Config . Dhcp > 0 || strings . Contains ( strings . ToLower ( cj . Config . Ip4_addr ) , "dhcp" ) == true {
2022-04-18 13:52:44 +02:00
if cj . Config . Bpf == 0 {
2022-04-05 22:21:39 +02:00
props_missing = append ( props_missing , fmt . Sprintf ( "%s: dhcp requires bpf" , cj . Name ) )
}
2022-04-18 13:52:44 +02:00
if cj . Config . Vnet == 0 {
2022-04-05 22:21:39 +02:00
props_missing = append ( props_missing , fmt . Sprintf ( "%s: dhcp requires vnet" , cj . Name ) )
}
}
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
// tcp(80:8080),tcp(3300-3310:33000-33010)
if cj . Config . Nat > 0 && strings . EqualFold ( cj . Config . Nat_forwards , "none" ) == false {
2022-04-24 16:49:54 +02:00
// If NAT && port forwarding is enabled, check that port does not conflict
2022-04-05 22:21:39 +02:00
// with another running jail
for _ , j := range gJails {
2022-04-18 13:52:44 +02:00
if j . Running == false || strings . EqualFold ( j . Config . Nat_forwards , "none" ) == false || j . Config . Nat != 1 {
2022-04-05 22:21:39 +02:00
continue
2022-04-18 13:52:44 +02:00
} else {
jnd , err := getNatForwardsArray ( j . Config . Nat_forwards , true )
if err != nil {
fmt . Printf ( err . Error ( ) )
return
}
cjnd , err := getNatForwardsArray ( cj . Config . Nat_forwards , true )
if err != nil {
fmt . Printf ( err . Error ( ) )
return
}
for _ , jn := range jnd {
for _ , cjn := range cjnd {
if jn == cjn {
fmt . Printf ( "nat_forwards rule \"%s\" is in conflict with jail %s, won't start\n" ,
2022-04-24 16:49:54 +02:00
fmt . Sprintf ( "%s(%s:%s)" , cjn . Proto , cjn . JailPort , cjn . HostPort ) , j . Name )
2022-04-18 13:52:44 +02:00
return
}
}
}
2022-04-05 22:21:39 +02:00
}
}
}
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
if cj . Config . Nat > 0 && strings . EqualFold ( cj . Config . Nat_interface , "none" ) == true {
2022-06-26 20:02:28 +02:00
cj . Config . Nat_interface = gJailHost . GetDefaultInterface ( )
2022-04-18 13:52:44 +02:00
cj . ConfigUpdated = true
}
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
if cj . Config . Vnet > 0 && strings . EqualFold ( cj . Config . Defaultrouter , "auto" ) == true {
2022-06-26 20:02:28 +02:00
cj . Config . Defaultrouter = gJailHost . GetDefaultGateway4 ( )
2022-04-18 13:52:44 +02:00
// "auto" default Gateway should not be updated to support jailhost route change
}
2022-04-24 16:49:54 +02:00
2022-04-18 13:52:44 +02:00
if cj . Config . Vnet > 0 && strings . EqualFold ( cj . Config . Defaultrouter6 , "auto" ) == true {
2022-06-26 20:02:28 +02:00
cj . Config . Defaultrouter6 = gJailHost . GetDefaultGateway6 ( )
2022-04-18 13:52:44 +02:00
// "auto" default Gateway should not be updated to support jailhost route change
}
2022-04-24 16:49:54 +02:00
if strings . EqualFold ( cj . Config . Ip6_addr , "accept_rtadv" ) && cj . Config . Vnet == 0 {
props_missing = append ( props_missing , fmt . Sprintf ( "%s: accept_rtadv requires vnet" , cj . Name ) )
}
if cj . Config . Bpf > 0 && cj . Config . Vnet == 0 {
props_missing = append ( props_missing , fmt . Sprintf ( "%s: bpf requires vnet" , cj . Name ) )
}
if len ( props_missing ) > 0 {
for _ , m := range props_missing {
fmt . Printf ( "%s\n" , m )
}
return
}
if cj . Config . Dhcp > 0 || strings . Contains ( strings . ToLower ( cj . Config . Ip4_addr ) , "dhcp" ) == true {
err = configureDhcpOrAcceptRtadv ( cj , IPv4 , true )
} else {
err = configureDhcpOrAcceptRtadv ( cj , IPv4 , false )
}
if err != nil {
fmt . Printf ( err . Error ( ) )
return
}
if cj . Config . Rtsold > 0 {
err = checkRtsold ( cj )
}
if err != nil {
fmt . Printf ( err . Error ( ) )
return
}
if strings . Contains ( strings . ToLower ( cj . Config . Ip6_addr ) , "accept_rtadv" ) == true {
err = configureDhcpOrAcceptRtadv ( cj , IPv6 , true )
} else {
err = configureDhcpOrAcceptRtadv ( cj , IPv6 , false )
}
if err != nil {
fmt . Printf ( err . Error ( ) )
return
}
2021-12-21 20:48:07 +01:00
fmt . Printf ( " > Mount special filesystems:\n" )
err := mountAllJailFsFromHost ( cj )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Mount special filesystems: OK\n" )
}
2022-04-24 16:49:54 +02:00
2022-04-02 14:18:50 +02:00
if cj . Config . Jail_zfs > 0 {
fmt . Printf ( " > Prepare ZFS Datasets:\n" )
err := prepareJailedZfsDatasets ( cj )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Prepare ZFS Datasets: OK\n" )
}
}
2022-04-24 16:49:54 +02:00
// Check NAT backend
if cj . Config . Nat > 0 {
log . Debug ( "Check NAT backend %s\n" , cj . Config . Nat_backend )
err = checkNat ( cj . Config . Nat_backend )
2021-12-21 20:48:07 +01:00
if err != nil {
2022-04-24 16:49:54 +02:00
fmt . Printf ( err . Error ( ) )
return
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
if cj . Config . Vnet == 0 {
2022-06-19 14:48:55 +02:00
log . Debug ( "Generate NAT IPv4 without VNet\n" )
2022-04-24 16:49:54 +02:00
ip4 , err := genNatIpv4 ( cj )
if err != nil {
fmt . Printf ( "%s\n" , err . Error ( ) )
return
}
2022-06-19 14:48:55 +02:00
log . Debug ( "Configuring NAT : Set ip4_addr to %s\n" , ip4 [ 0 ] )
2022-04-24 16:49:54 +02:00
// This IP should not be saved into json
cj . Config . Ip4_addr = fmt . Sprintf ( "%s|%s" , cj . Config . Nat_interface , ip4 [ 0 ] )
2021-12-21 20:48:07 +01:00
} else {
2022-06-19 14:48:55 +02:00
log . Debug ( "Generate NAT IPv4 with VNet\n" )
2022-04-24 16:49:54 +02:00
ip4 , err := genNatIpv4 ( cj )
if err != nil {
fmt . Printf ( "%s\n" , err . Error ( ) )
return
}
2022-06-19 14:48:55 +02:00
log . Debug ( "Configuring NAT : Set ip4_addr to %s, defaultrouter to %s\n" , ip4 [ 1 ] , ip4 [ 0 ] )
2022-04-24 16:49:54 +02:00
// This IP should not be saved into json
cj . Config . Ip4_addr = fmt . Sprintf ( "vnet0|%s" , ip4 [ 1 ] )
cj . Config . Defaultrouter = ip4 [ 0 ]
2021-12-21 20:48:07 +01:00
}
}
2023-08-06 14:50:32 +02:00
2022-04-24 16:49:54 +02:00
// See https://github.com/iocage/iocage/blob/e94863d4c54f02523fb09e62e48be7db9ac92eda/iocage_lib/ioc_start.py:401
2022-06-18 11:10:06 +02:00
if cj . Config . Vnet == 0 {
// Not supported
fmt . Printf ( "Only VNet jails supported\n" )
return
}
2023-08-06 14:50:32 +02:00
2022-06-18 11:10:06 +02:00
var net [ ] string
if false == strings . EqualFold ( cj . Config . Vnet_interfaces , "none" ) {
net = append ( net , strings . Split ( cj . Config . Vnet_interfaces , " " ) ... )
}
2023-08-06 14:50:32 +02:00
2023-06-25 23:32:15 +02:00
err , dynrs := buildDevfsRuleSet ( cj , & gMdevfs )
2022-06-19 14:48:55 +02:00
if err != nil {
fmt . Printf ( "%s\n" , err . Error ( ) )
return
}
2023-08-06 14:50:32 +02:00
2022-06-19 14:48:55 +02:00
err = buildJailParameters ( cj , dynrs )
2022-06-18 11:10:06 +02:00
if err != nil {
fmt . Printf ( "%s\n" , err . Error ( ) )
return
}
2023-08-06 14:50:32 +02:00
2022-06-19 14:48:55 +02:00
// Synchronize jail config to disk
2023-08-06 14:50:32 +02:00
cj . WriteConfigToDisk ( false )
2022-06-26 20:02:28 +02:00
start_cmd := fmt . Sprintf ( "/usr/sbin/jail -f /var/run/jail.%s.conf -c" , cj . InternalName )
//TODO: handle start_env & prestart_env, could be used by iocage plugins
_ , err = executeScript ( cj . Config . Exec_prestart )
if err != nil {
fmt . Printf ( "Error executing exec_prestart script: %v\n" , err )
fmt . Printf ( "Aborting jail start\n" )
return
}
2023-08-06 14:50:32 +02:00
2022-06-26 20:02:28 +02:00
fmt . Printf ( " > Start jail:\n" )
_ , err = executeCommand ( start_cmd )
if err != nil {
fmt . Printf ( "Error starting jail %s: %v\n" , cj . Name , err )
return
}
2023-08-06 14:50:32 +02:00
2022-06-26 20:02:28 +02:00
fmt . Printf ( " > Start jail: OK\n" )
fmt . Printf ( " > With devfs ruleset %d\n" , dynrs )
2023-08-06 14:50:32 +02:00
2022-10-15 16:33:29 +02:00
// Update running state, JID and Devfs_ruleset
2022-06-26 20:02:28 +02:00
cj . Running = true
2022-10-15 16:33:29 +02:00
cj . Devfs_ruleset = dynrs
2022-06-26 20:02:28 +02:00
rjails , err := jail . GetJails ( )
if err != nil {
fmt . Printf ( "Error: Unable to list running jails\n" )
}
for _ , j := range rjails {
if j . Name == cj . InternalName {
cj . JID = j . Jid
break
}
}
2023-08-06 14:50:32 +02:00
2024-09-05 09:28:05 +02:00
// Get a reference to current jail, to update its properties in RAM so API will get fresh data
for i , j := range gJails {
if strings . EqualFold ( j . Name , cj . Name ) && strings . EqualFold ( j . Datastore , cj . Datastore ) {
if err = setStructFieldValue ( & gJails [ i ] , "Running" , "true" ) ; err != nil {
fmt . Printf ( "ERROR: setting Running property to true: %s\n" , err . Error ( ) )
}
if err = setStructFieldValue ( & gJails [ i ] , "JID" , fmt . Sprintf ( "%d" , cj . JID ) ) ; err != nil {
fmt . Printf ( "ERROR: setting JID property to %d: %s\n" , cj . JID , err . Error ( ) )
}
if err = setStructFieldValue ( & gJails [ i ] , "InternalName" , cj . InternalName ) ; err != nil {
fmt . Printf ( "ERROR: Setting InternalName property: %s\n" , err . Error ( ) )
}
// FIXME: this value of devfs_ruleset should not go in Config, it should reside in Jail root properties as it is volatile (only valid while jail is running)
/ * if err = setStructFieldValue ( & gJails [ i ] , "Devfs_ruleset" , "0" ) ; err != nil {
fmt . Printf ( "ERROR: setting Devfs_ruleset property to 0: %s\n" , err . Error ( ) )
} * /
}
}
2022-06-26 20:02:28 +02:00
hostInt , err := gJailHost . GetInterfaces ( )
if err != nil {
fmt . Printf ( "Error listing jail host interfaces: %v\n" , err )
return
}
2023-08-06 14:50:32 +02:00
2022-06-26 20:02:28 +02:00
if false == strings . EqualFold ( cj . Config . Vnet_default_interface , "auto" ) &&
false == strings . EqualFold ( cj . Config . Vnet_default_interface , "none" ) &&
false == isStringInArray ( hostInt , cj . Config . Vnet_default_interface ) {
fmt . Printf ( "vnet_default_interface can be one of \"none\", \"auto\" of a valid interface (e.g. \"lagg0\")\n" )
return
}
2022-04-24 16:49:54 +02:00
2022-06-26 20:02:28 +02:00
fmt . Printf ( " > Setup VNet network:\n" )
2023-08-06 14:50:32 +02:00
hsepairs , err := setupVnetInterfaceHostSide ( cj ) ;
2022-06-26 20:02:28 +02:00
if err != nil {
fmt . Printf ( "Error setting VNet interface host side: %v\n" , err )
return
}
2023-08-06 14:50:32 +02:00
if err = setupVnetInterfaceJailSide ( cj , hsepairs ) ; err != nil {
2023-08-05 19:49:59 +02:00
fmt . Printf ( "Error setting VNet interface jail side: %v\n" , err )
return
2022-06-26 20:02:28 +02:00
}
fmt . Printf ( " > Setup VNet network: OK\n" )
2023-08-05 19:49:59 +02:00
// Set default route, unless main network is dhcp
2024-04-20 20:32:51 +02:00
if ! cj . isFirstNetDhcp ( ) && ! strings . EqualFold ( cj . Config . Ip4_addr , "none" ) {
2023-08-05 19:49:59 +02:00
fmt . Printf ( " > Setup default ipv4 gateway:\n" )
cmd := fmt . Sprintf ( "/usr/sbin/setfib %s /usr/sbin/jexec %d route add default %s" , cj . Config . Exec_fib , cj . JID , cj . Config . Defaultrouter )
out , err := executeCommand ( cmd )
if err != nil && len ( out ) > 0 {
fmt . Printf ( "Error: %v: %s\n" , err , out )
} else {
fmt . Printf ( " > Setup default ipv4 gateway: OK\n" )
}
2022-07-10 19:55:13 +02:00
}
2023-08-06 14:50:32 +02:00
2022-07-10 19:55:13 +02:00
if cj . Config . Ip6_addr != "none" {
fmt . Printf ( " > Setup default ipv6 gateway:\n" )
cmd := fmt . Sprintf ( "/usr/sbin/setfib %s /usr/sbin/jexec %d route add -6 default %s" , cj . Config . Exec_fib , cj . JID , cj . Config . Defaultrouter6 )
out , err := executeCommand ( cmd )
2022-07-10 20:48:24 +02:00
if err != nil && len ( out ) > 0 {
2022-07-10 19:55:13 +02:00
fmt . Printf ( "Error: %v: %s\n" , err , out )
} else {
fmt . Printf ( " > Setup default ipv6 gateway: OK\n" )
}
}
2023-08-06 14:50:32 +02:00
2022-07-10 20:48:24 +02:00
if cj . Config . Jail_zfs > 0 {
fmt . Printf ( " > Jail ZFS datasets:\n" )
err = jailZfsDatasets ( cj )
if err != nil {
fmt . Printf ( "%v\n" , err )
return
}
fmt . Printf ( " > Jail ZFS datasets: OK\n" )
2022-06-26 20:02:28 +02:00
}
2022-07-10 20:56:49 +02:00
2022-07-10 20:48:24 +02:00
err = generateResolvConf ( cj )
if err != nil {
fmt . Printf ( "%s\n" , err )
}
2023-08-06 14:50:32 +02:00
2022-07-10 20:48:24 +02:00
if cj . Config . Host_time > 0 {
err = copyLocalTime ( cj )
if err != nil {
fmt . Printf ( "%s\n" , err )
}
}
2023-08-06 14:50:32 +02:00
2022-07-10 19:55:13 +02:00
// Start services
if len ( cj . Config . Exec_start ) > 0 {
fmt . Printf ( " > Start services:\n" )
cmd := fmt . Sprintf ( "/usr/sbin/setfib %s /usr/sbin/jexec %d %s" , cj . Config . Exec_fib , cj . JID , cj . Config . Exec_start )
2023-06-10 14:12:53 +02:00
err := executeCommandNonBlocking ( cmd )
2023-08-05 19:49:59 +02:00
if err != nil {
2023-06-10 14:12:53 +02:00
fmt . Printf ( "Error: %v\n" , err )
2022-07-10 19:55:13 +02:00
} else {
fmt . Printf ( " > Start services: OK\n" )
}
}
2023-08-06 14:50:32 +02:00
2022-07-10 20:52:54 +02:00
if cj . Config . Rtsold > 0 || strings . EqualFold ( cj . Config . Ip6_addr , "accept_rtadv" ) {
fmt . Printf ( " > Start rtsold:\n" )
cmd := fmt . Sprintf ( "/usr/sbin/setfib %s /usr/sbin/jexec %d service rtsold start" , cj . Config . Exec_fib , cj . JID )
out , err := executeCommand ( cmd )
if err != nil && len ( out ) > 0 {
fmt . Printf ( "Error: %v: %s\n" , err , out )
} else {
fmt . Printf ( " > Start rtsold: OK\n" )
}
}
2023-08-06 14:50:32 +02:00
2022-07-10 19:55:13 +02:00
// TODO: Execute Exec_poststart
2022-07-10 20:48:24 +02:00
if len ( cj . Config . Exec_poststart ) > 0 {
fmt . Printf ( " > Execute post-start:\n" )
2022-07-14 11:11:23 +02:00
cmd := fmt . Sprintf ( "%s" , cj . Config . Exec_poststart )
2022-07-10 20:48:24 +02:00
out , err := executeCommand ( cmd )
if err != nil && len ( out ) > 0 {
fmt . Printf ( "Error: %v: %s\n" , err , out )
} else {
fmt . Printf ( " > Execute post-start: OK\n" )
}
}
2023-08-06 14:50:32 +02:00
2022-07-10 20:56:49 +02:00
// WIP 10/07/2022 : https://github.com/iocage/iocage/blob/master/iocage_lib/ioc_start.py#L891
// TODO: Handle dhcp
// TODO: Apply rctl
2023-08-06 14:50:32 +02:00
2022-11-20 20:19:37 +01:00
// Update last_started
2023-07-23 15:41:37 +02:00
// 23/07/2023 : This is not working, when writing to disk the old value is used
2022-11-20 20:19:37 +01:00
dt := time . Now ( )
curDate := fmt . Sprintf ( "%s" , dt . Format ( "2006-01-02 15:04:05" ) )
2023-07-23 15:41:37 +02:00
cj . Config . Last_started = curDate
2023-07-23 15:52:21 +02:00
writeConfigToDisk ( cj , false )
2023-08-06 14:50:32 +02:00
2022-04-24 16:49:54 +02:00
/ *
out , err := executeCommand ( fmt . Sprintf ( "rctl jail:%s" , cj . InternalName ) )
if err == nil && len ( out ) > 0 {
fmt . Printf ( " > Remove RCTL rules:\n" )
err := removeRctlRules ( cj . InternalName , [ ] string { "" } )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Remove RCTL rules: OK\n" )
}
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
if len ( cj . Config . Exec_prestop ) > 0 {
fmt . Printf ( " > Execute prestop:\n" )
_ , err := executeCommand ( cj . Config . Exec_prestop )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Execute prestop: OK\n" )
}
}
if len ( cj . Config . Exec_stop ) > 0 {
fmt . Printf ( " > Execute stop:\n" )
_ , err := executeCommandInJail ( cj , cj . Config . Exec_stop )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Execute stop: OK\n" )
}
}
if cj . Config . Jail_zfs > 0 {
fmt . Printf ( " > Umount jailed ZFS:\n" )
err := umountAndUnjailZFS ( cj )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Umount jailed ZFS: OK\n" )
}
}
if cj . Config . Vnet > 0 && len ( cj . Config . Ip4_addr ) > 0 {
fmt . Printf ( " > Destroy VNet interfaces:\n" )
err := destroyVNetInterfaces ( cj )
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
fmt . Printf ( " > Destroy VNet interfaces: OK\n" )
}
}
fmt . Printf ( " > Remove devfsruleset %s:\n" , cj . Config . Devfs_ruleset )
err = deleteDevfsRuleset ( cj )
2021-12-21 20:48:07 +01:00
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
2022-04-24 16:49:54 +02:00
fmt . Printf ( " > Remove devfsruleset %s: OK\n" , cj . Config . Devfs_ruleset )
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
fmt . Printf ( " > Stop jail %s:\n" , cj . Name )
err = stopJail ( cj )
2021-12-21 20:48:07 +01:00
if err != nil {
fmt . Printf ( "ERROR: %s\n" , err . Error ( ) )
} else {
2022-04-24 16:49:54 +02:00
fmt . Printf ( " > Stop jail %s: OK\n" , cj . Name )
2021-12-21 20:48:07 +01:00
}
2022-04-24 16:49:54 +02:00
* /
2021-12-21 20:48:07 +01:00
}
}