|
|
|
@ -23,25 +23,26 @@ end
|
|
|
|
|
ROOT_PATH = Pathname.new(File.expand_path("../.." ,__FILE__)) |
|
|
|
|
EZJAIL_CONFIG_PATH = Pathname.new("/usr/local/etc/ezjail/") |
|
|
|
|
|
|
|
|
|
DEFAULT_IP4_SUBNET = "192.168.10.0/24" |
|
|
|
|
DEFAULT_IP6_SUBNET = "fd7d:aed0:18aa::/48" |
|
|
|
|
|
|
|
|
|
class Jail |
|
|
|
|
def initialize(name, properties={}) |
|
|
|
|
@name = name |
|
|
|
|
@properties = properties |
|
|
|
|
end |
|
|
|
|
attr_accessor :name |
|
|
|
|
attr_accessor :name, :properties |
|
|
|
|
|
|
|
|
|
def ip4; extract_ip["ip4"]; end |
|
|
|
|
def ip6; extract_ip["ip6"]; end |
|
|
|
|
def ip4 |
|
|
|
|
extract_ip("ip4") |
|
|
|
|
end |
|
|
|
|
def ip6 |
|
|
|
|
extract_ip("ip6") |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
private |
|
|
|
|
def extract_ip(type) |
|
|
|
|
ips = @properties[ip] || [] |
|
|
|
|
ips.map do |addr| extract_ip(addr) |
|
|
|
|
ips = @properties[type] || [] |
|
|
|
|
ips.map do |addr| |
|
|
|
|
# example: em0|192.168.67.0 -> 192.168.67.0 |
|
|
|
|
spec =~ /\|?([^|]+)$/ |
|
|
|
|
addr =~ /\|?([^|]+)$/ |
|
|
|
|
$1 |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
@ -55,21 +56,23 @@ class JailRegistry < Registry
|
|
|
|
|
ip4 = next_address("ip4") |
|
|
|
|
ip6 = next_address("ip6") |
|
|
|
|
data["jails"][name] = { |
|
|
|
|
"ip4" => ip4, |
|
|
|
|
"ip6" => ip6 |
|
|
|
|
"ip4" => [ip4], |
|
|
|
|
"ip6" => [ip6] |
|
|
|
|
} |
|
|
|
|
ipconfig = "#{ip4},#{ip6}" |
|
|
|
|
flavour = [] |
|
|
|
|
if data["settings"]["flavour"] |
|
|
|
|
flavour = ["-f", data["settings"]["flavour"]] |
|
|
|
|
if settings["flavour"] |
|
|
|
|
flavour = ["-f", settings["flavour"]] |
|
|
|
|
end |
|
|
|
|
sh("ezjail-admin", "create", *flavour, name, ipconfig) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def env(name) |
|
|
|
|
jail_data = data[name] or die("no jail with name #{name} found") |
|
|
|
|
templ = Template.new(ROOT_PATH.join("templates/jail.erb")) |
|
|
|
|
puts(templ.render(name: name, properties: jail_properties(jail_data))) |
|
|
|
|
jail_data = data["jails"][name] or die("no jail with name #{name} found") |
|
|
|
|
jail_data = default_jail_conf.merge(jail_data) |
|
|
|
|
templ = Template.new(ROOT_PATH.join("templates/jail_env.erb")) |
|
|
|
|
properties = jail_properties(name, jail_data) |
|
|
|
|
puts(templ.render(name: name, properties: properties)) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def update_pf_vars |
|
|
|
@ -81,49 +84,106 @@ class JailRegistry < Registry
|
|
|
|
|
|
|
|
|
|
def update_config_symlinks |
|
|
|
|
conf_path = ROOT_PATH.join("scripts/jail_conf") |
|
|
|
|
jails.each do |name| |
|
|
|
|
path = EZJAIL_CONFIG_PATH.join(name) |
|
|
|
|
FileUtils.ln_sf(conf_path, path) |
|
|
|
|
FileUtils.mkdir_p(EZJAIL_CONFIG_PATH) |
|
|
|
|
jails.each do |jail| |
|
|
|
|
FileUtils.ln_sf(conf_path, EZJAIL_CONFIG_PATH.join(jail.name)) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def update_fstabs |
|
|
|
|
templ = Template.new(ROOT_PATH.join("templates/fstab.erb")) |
|
|
|
|
atomic_write(path, templ.render(jails: jails)) |
|
|
|
|
jails.each do |jail| |
|
|
|
|
fstab = settings["fstab"].dup |
|
|
|
|
fstab.concat(jail.properties["fstab"] || []) |
|
|
|
|
fstab.map! do |entry| |
|
|
|
|
entry % { name: jail.name } |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
path = "/etc/fstab.#{jail.name}" |
|
|
|
|
atomic_write(path, templ.render(fstab: fstab)) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
private |
|
|
|
|
def jail_properties(name) |
|
|
|
|
props = @properties.dup |
|
|
|
|
def settings |
|
|
|
|
{ |
|
|
|
|
"ip4_subnet" => "192.168.10.0/24", |
|
|
|
|
"ip6_subnet" => "fd7d:aed0:18aa::/48", |
|
|
|
|
"fstab" => [ |
|
|
|
|
"/usr/jails/basejail /usr/jails/%{name}/basejail nullfs ro 0 0", |
|
|
|
|
], |
|
|
|
|
}.merge(data["settings"]) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def default_jail_conf |
|
|
|
|
{ |
|
|
|
|
"exec_start" => "/bin/sh /etc/rc", |
|
|
|
|
"exec_stop" => nil, |
|
|
|
|
"hostname" => "%{name}", |
|
|
|
|
"rootdir" => "/usr/jails/%{name}", |
|
|
|
|
"mount_enable" => true, |
|
|
|
|
"devfs_ruleset" => "devfsrules_jails", |
|
|
|
|
"procfs_enable" => true, |
|
|
|
|
"fdescfs_enable" => true, |
|
|
|
|
"image" => nil, |
|
|
|
|
"imagetype" => nil, |
|
|
|
|
"attachparams" => nil, |
|
|
|
|
"attachblocking" => nil, |
|
|
|
|
"forceblocking" => nil, |
|
|
|
|
"zfs_datasets" => nil, |
|
|
|
|
"cpuset" => nil, |
|
|
|
|
"fib" => nil, |
|
|
|
|
"parentzfs" => nil, |
|
|
|
|
"parameters" => nil, |
|
|
|
|
"post_start_script" => nil, |
|
|
|
|
"retention_policy" => nil |
|
|
|
|
}.merge(data["default_jail_conf"]) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def jail_properties(name, properties) |
|
|
|
|
props = properties.dup |
|
|
|
|
|
|
|
|
|
ips = props.delete("ip4") || [] |
|
|
|
|
ips.concat(props.delete("ip6") || []) |
|
|
|
|
if props["ip4"] || props["ip6"] |
|
|
|
|
unless ips.empty? |
|
|
|
|
props["ip"] = ips.join(",") |
|
|
|
|
end |
|
|
|
|
props.each do |prop, value| |
|
|
|
|
props[prop] = Shellwords.escape(value) |
|
|
|
|
props[prop] = serialize_property(name, value) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
props |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def serialize_property(name, value) |
|
|
|
|
str = case value |
|
|
|
|
when TrueClass |
|
|
|
|
return value ? "YES" : "NO" |
|
|
|
|
when String |
|
|
|
|
value % { name: name } |
|
|
|
|
else |
|
|
|
|
value |
|
|
|
|
end |
|
|
|
|
Shellwords.escape(str) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def jails |
|
|
|
|
jails = {} |
|
|
|
|
data["jails"].each do |name, properties| |
|
|
|
|
jails[name] = Jail.new(name, properties) |
|
|
|
|
data["jails"].map do |name, properties| |
|
|
|
|
Jail.new(name, properties) |
|
|
|
|
end |
|
|
|
|
jails |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def next_address(type) |
|
|
|
|
assigned_subnets = data["jails"].map do |k,v| |
|
|
|
|
NetAddr::CIDR.create(v[type]) if v[type] |
|
|
|
|
end.compact |
|
|
|
|
subnet = data["settings"]["#{type}_subnet"] |
|
|
|
|
default = { "ip4" => DEFAULT_IP4_SUBNET, "ip6" => DEFAULT_IP6_SUBNET } |
|
|
|
|
subnet ||= default[type] |
|
|
|
|
next_free_subnet(NetAddr::CIDR.create(subnet), assigned_subnets) |
|
|
|
|
subnets = [] |
|
|
|
|
data["jails"].each do |k,v| |
|
|
|
|
if v[type].is_a? Array |
|
|
|
|
v[type].each do |subnet| |
|
|
|
|
subnets << NetAddr::CIDR.create(subnet) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
subnet = settings["#{type}_subnet"] |
|
|
|
|
next_free_subnet(NetAddr::CIDR.create(subnet), subnets) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|