#!/usr/bin/env ruby require "optparse" require "shellwords" require_relative "utils" OPTION_PARSER = OptionParser.new do |opts| opts.banner = "Usage: jails [options] [subcommand [options]]" opts.separator "" opts.separator < 192.168.67.0 spec =~ /\|?([^|]+)$/ $1 end end end class JailRegistry < Registry def add(name) data["jails"] ||= {} data["settings"] ||= {} ip4 = next_address("ip4") ip6 = next_address("ip6") data["jails"][name] = { "ip4" => ip4, "ip6" => ip6 } ipconfig = "#{ip4},#{ip6}" flavour = [] if data["settings"]["flavour"] flavour = ["-f", data["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))) end def update_pf_vars templ = Template.new(ROOT_PATH.join("templates/pf.erb")) path = ROOT_PATH.join("pf_vars.conf") atomic_write(path, templ.render(jails: jails)) end 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) end end def update_fstabs templ = Template.new(ROOT_PATH.join("templates/fstab.erb")) atomic_write(path, templ.render(jails: jails)) end private def jail_properties(name) props = @properties.dup ips = props.delete("ip4") || [] ips.concat(props.delete("ip6") || []) if props["ip4"] || props["ip6"] props["ip"] = ips.join(",") end props.each do |prop, value| props[prop] = Shellwords.escape(value) end props end def jails jails = {} data["jails"].each do |name, properties| jails[name] = 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) end end def main(args) OPTION_PARSER.order!(args) usage if args.size < 1 registry = JailRegistry.new case command = args.shift when "add" name = args.first or die "name required" registry.add(name) registry.save when nil usage when "regenerate" when "env" name = args.first or die "name required" registry.env(name) else die "unknown subcommand #{command}" end registry.update_pf_vars registry.update_fstabs registry.update_config_symlinks end main(ARGV)