def init(ip4_network): check_compatibility() address4 = str(ip4_network.network_address + 1) netmask = str(ip4_network.netmask) rc_conf_mod('cloned_interfaces+=%s' % cloned_if()) cmd('service', 'netif', 'cloneup') rc_conf_mod('ifconfig_%s=inet %s netmask %s' % (cloned_if(), address4, netmask)) cmd('ifconfig', cloned_if(), 'inet', address4, 'netmask', netmask) rc_conf_mod('jail_enable=YES') cmd( 'mkdir', '-p', '/var/mjail/instances/', '/var/mjail/releases/', '/var/mjail/generated_confs/' ) cmd('chmod', '700', '/var/mjail/instances/', '/var/mjail/releases/') cmd('chmod', '755', '/var/mjail/', '/var/mjail/generated_confs/') try: jail_conf = jailconf.load('/etc/jail.conf') except FileNotFoundError: jail_conf = jailconf.JailConf() jail_conf['exec.start'] = '"/bin/sh /etc/rc"' jail_conf['exec.stop'] = '"/bin/sh /etc/rc.shutdown"' jail_conf['exec.clean'] = True jail_conf['mount.devfs'] = True jail_conf['path'] = '"/var/mjail/instances/$name"' jail_conf.write('/etc/jail.conf') release = Release() if not release.built(): release.build() LocalUnboundManager.enable() PFManager.enable()
def enable(cls): cmd('mkdir', '-p', cls._conf_dir) temp_path = to_tempfile( cls._conf(), prefix = cls._conf_file ) os.rename(temp_path, cls._conf_file) cmd('local-unbound-setup', '-C', cls._conf_dir)
def enable(cls): #rc_conf_mod('gateway_enable=YES') #rc_conf_mod('net.inet.ip.forwarding=1') pf_conf_path = cls.pf_conf_path() try: pf_conf = [ line.rstrip() for line in open(pf_conf_path).readlines() if not line.endswith(cls._comment + "\n") ] except FileNotFoundError: pf_conf = [] start, translation_rules, filter_rules = pf_conf_split(pf_conf) new_conf = (start + [ cls._load_anchor, cls._insert_anchor_nat, cls._insert_anchor_rdr ] + translation_rules + filter_rules + [cls._insert_anchor_filter]) new_conf = '\n'.join(new_conf) if not new_conf.endswith( '\n'): # required by the pf configuration parser new_conf += '\n' cmd('mkdir', '-p', os.path.dirname(cls._anchor_conf_file)) if not os.path.exists(cls._anchor_conf_file): cls.overwrite_anchor_conf() temp_path = to_tempfile(new_conf, prefix=pf_conf_path) cmd('pfctl', '-vnf', temp_path ) # checking the new conf before replacing the old conf with it os.rename(temp_path, pf_conf_path) if pf_is_running(): cmd('pfctl', '-f', pf_conf_path) else: rc_conf_mod('pf_enable=YES') rc_conf_mod('pf_rules=%s' % pf_conf_path) cmd('service', 'pf', 'start')
def disable(cls): pf_conf_path = cls.pf_conf_path() try: pf_conf = [ line for line in open(pf_conf_path).readlines() if not line.endswith(cls._comment + "\n") ] except FileNotFoundError: pass else: new_conf = ''.join(pf_conf) if not new_conf.endswith('\n'): new_conf += '\n' temp_path = to_tempfile(new_conf, prefix=pf_conf_path) cmd('pfctl', '-vnf', temp_path) os.rename(temp_path, pf_conf_path) if pf_is_running(): cmd('pfctl' '-f', pf_conf_path)
def minor_upgrade(self, to_version, unattended=False): # this function would need to be tested freebsd_update_conf = to_tempfile(''.join( (re.sub(r'(?<=\b)kernel(?=\b)', '', line) if re. match(r'^Components\s', line) else line) for line in open('/etc/freebsd-update.conf').readlines())) try: jail_conf = get_jail_conf() currently_running = jail_conf[ self.name]['$mjail_currently_running_release'] to_version_major = to_version.split('.')[0] running_major = currently_running.split('.')[0] if to_version_major != running_major: raise Exception( "Can't upgrade from %s to %s. Only minor version upgrade is supported at the moment." % (running_major, to_version_major)) env = os.environ.copy() if unattended: env['PAGER'] = 'cat' cmd('freebsd-update', '-b', self.directory, '-f', freebsd_update_conf, '-r', to_version, 'upgrade', 'install', '--currently-running', currently_running, env=env) for _ in range(2): cmd('freebsd-update', '-b', self.directory, '-f', freebsd_update_conf, 'install', env=env) jail_conf[ self.name]['$mjail_currently_running_release'] = to_version jail_conf.write('/etc/jail.conf') finally: os.remove(freebsd_update_conf)
def disable(cls): pf_conf_path = cls.pf_conf_path() try: pf_conf = [ line for line in open(pf_conf_path).readlines() if not line.endswith(cls._comment + "\n") ] except FileNotFoundError: pass else: new_conf = ''.join(pf_conf) if not new_conf.endswith('\n'): new_conf += '\n' temp_path = to_tempfile(new_conf, prefix = pf_conf_path) cmd('pfctl', '-vnf', temp_path) os.rename(temp_path, pf_conf_path) if pf_is_running(): cmd('pfctl' '-f', pf_conf_path)
def build(self): components = ['base.txz', 'lib32.txz'] if int(re.match(r'^\d+', self._release).group(0)) < 12: # There's no longer a doc.txz in FreeBSD 12 components.append('doc.txz') cmd('mkdir', '-p', self.directory) with TemporaryDirectory() as tempdir: with cd(tempdir): for component in components: cmd('fetch', self._component_url(component), '-o', component) cmd('tar', 'xvf', component, '-C', self.directory) freebsd_update(self.directory, unattended = True) cmd( 'freebsd-update', '-b', self.directory, 'IDS', )
def delete(self): cmd('service', 'jail', 'stop', self.name) jail_conf = get_jail_conf() try: jail_block = jail_conf[self.name] except KeyError: pass else: try: ip4 = jail_block['ip4.addr'] except KeyError: pass else: assert isinstance(ip4, str) # list of ips not yet supported by mjail line = '%s %s\n' % (ip4, self.name) lines = [l for l in open('/etc/hosts').readlines() if l != line] temp_etc_hosts = to_tempfile(''.join(lines)) shutil.move(temp_etc_hosts, '/etc/hosts') del jail_conf[self.name] jail_conf.write('/etc/jail.conf') if os.path.exists(self.directory): cmd('chflags', '-R', 'noschg', self.directory) cmd('rm', '-rf', self.directory) PFManager.refresh_anchor()
def delete(self): cmd('service', 'jail', 'stop', self.name) jail_conf = get_jail_conf() try: jail_block = jail_conf[self.name] except KeyError: pass else: for version in (4, 6): try: ip = jail_block['ip%s.addr' % version] except KeyError: pass else: assert isinstance( ip, str) # list of ips not yet supported by mjail line = '%s %s\n' % (ip, self.name) lines = [ l for l in open('/etc/hosts').readlines() if l != line ] temp_etc_hosts = to_tempfile(''.join(lines)) shutil.move(temp_etc_hosts, '/etc/hosts') del jail_conf[self.name] jail_conf.write('/etc/jail.conf') if os.path.exists(self.directory): cmd('chflags', '-R', 'noschg', self.directory) cmd('rm', '-rf', self.directory) PFManager.refresh_anchor()
def minor_upgrade(self, to_version, unattended = False): # this function would need to be tested freebsd_update_conf = to_tempfile( ''.join( (re.sub(r'(?<=\b)kernel(?=\b)', '', line) if re.match(r'^Components\s', line) else line) for line in open('/etc/freebsd-update.conf').readlines() ) ) try: jail_conf = get_jail_conf() currently_running = jail_conf[self.name]['$mjail_currently_running_release'] to_version_major = to_version.split('.')[0] running_major = currently_running.split('.')[0] if to_version_major != running_major: raise Exception( "Can't upgrade from %s to %s. Only minor version upgrade is supported at the moment." % ( running_major, to_version_major ) ) env = os.environ.copy() if unattended: env['PAGER'] = 'cat' cmd('freebsd-update', '-b', self.directory, '-f', freebsd_update_conf, '-r', to_version, 'upgrade', 'install', '--currently-running', currently_running, env = env ) for _ in range(2): cmd('freebsd-update', '-b', self.directory, '-f', freebsd_update_conf, 'install', env = env ) jail_conf[self.name]['$mjail_currently_running_release'] = to_version jail_conf.write('/etc/jail.conf') finally: os.remove(freebsd_update_conf)
def create(self): release = Release() if not release.built(): release.build() if os.path.exists(self.directory): raise JailAlreadyExists(self.name) cmd('cp', '-R', '-v', release.directory, self.directory) jail_conf = get_jail_conf() if self.name in jail_conf: raise JailAlreadyExists(self.name) jail_conf[self.name] = jailconf.JailBlock([ ('$mjail_managed', 'yes'), ('$mjail_currently_running_release', str(release)), ('host.hostname', self.name) ]) jail_conf.write('/etc/jail.conf')
def ssh_box(self, public_key, internet_facing_port, jail_port=22): internet_facing_port = int(internet_facing_port) host_sshd_conf = SSHDConf('/etc/ssh/sshd_config') if internet_facing_port == int(host_sshd_conf.get('Port', '22')): raise ValueError("This port is the ssh port used by the host.") root_ssh_dir = os.path.join(self.directory, 'root', '.ssh') authorized_keys_file = os.path.join(root_ssh_dir, 'authorized_keys') os.makedirs(root_ssh_dir, exist_ok=True) cmd('chmod', '700', root_ssh_dir) with open(authorized_keys_file, "w") as fp: fp.write(public_key) cmd('chmod', '600', authorized_keys_file) s_conf = SSHDConf(os.path.join(self.directory, 'etc/ssh/sshd_config')) for option, value in (('PermitRootLogin', 'prohibit-password'), ('RSAAuthentication', 'yes'), ('PubkeyAuthentication', 'yes'), ('PasswordAuthentication', 'no'), ('Port', str(jail_port))): s_conf.set_option(option, value) s_conf.overwrite() rc_conf_mod('sshd_enable=YES', f=os.path.join(self.directory, 'etc/rc.conf')) self.rdr('tcp', internet_facing_port, jail_port)
def create(self): release = Release() if not release.built(): release.build() if os.path.exists(self.directory): raise JailAlreadyExists(self.name) cmd('cp', '-R', '-v', release.directory, self.directory) with open(os.path.join(self.directory, 'etc', 'resolv.conf'), "w") as fp: fp.write("nameserver %s\n" % str(jails_network4().network_address + 1)) jail_conf = get_jail_conf() if self.name in jail_conf: raise JailAlreadyExists(self.name) jail_conf[self.name] = jailconf.JailBlock([ ('$mjail_managed', 'yes'), ('$mjail_currently_running_release', str(release)), ('host.hostname', self.name) ]) jail_conf.write('/etc/jail.conf')
def ssh_box(self, public_key, internet_facing_port, jail_port = 22): internet_facing_port = int(internet_facing_port) host_sshd_conf = SSHDConf('/etc/ssh/sshd_config') if internet_facing_port == int(host_sshd_conf.get('Port', '22')): raise ValueError("This port is the ssh port used by the host.") root_ssh_dir = os.path.join(self.directory, 'root', '.ssh') authorized_keys_file = os.path.join(root_ssh_dir, 'authorized_keys') os.makedirs(root_ssh_dir, exist_ok = True) cmd('chmod', '700', root_ssh_dir) with open(authorized_keys_file, "w") as fp: fp.write(public_key) cmd('chmod', '600', authorized_keys_file) s_conf = SSHDConf(os.path.join(self.directory, 'etc/ssh/sshd_config')) for option, value in ( ('PermitRootLogin', 'prohibit-password'), ('RSAAuthentication', 'yes'), ('PubkeyAuthentication', 'yes'), ('PasswordAuthentication', 'no'), ('Port', str(jail_port)) ): s_conf.set_option(option, value) s_conf.overwrite() rc_conf_mod('sshd_enable=YES', f = os.path.join(self.directory, 'etc/rc.conf')) self.rdr('tcp', internet_facing_port, jail_port)
def build(self): components = ['base.txz', 'lib32.txz'] if int(re.match(r'^\d+', self._release).group( 0)) < 12: # There's no longer a doc.txz in FreeBSD 12 components.append('doc.txz') cmd('mkdir', '-p', self.directory) with TemporaryDirectory() as tempdir: with cd(tempdir): for component in components: cmd('fetch', self._component_url(component), '-o', component) cmd('tar', 'xvf', component, '-C', self.directory) freebsd_update(self.directory, unattended=True) cmd( 'freebsd-update', '-b', self.directory, 'IDS', )
def enable(cls): #rc_conf_mod('gateway_enable=YES') #rc_conf_mod('net.inet.ip.forwarding=1') pf_conf_path = cls.pf_conf_path() try: pf_conf = [ line.rstrip() for line in open(pf_conf_path).readlines() if not line.endswith(cls._comment + "\n") ] except FileNotFoundError: pf_conf = [] start, translation_rules, filter_rules = pf_conf_split(pf_conf) new_conf = ( start + [cls._load_anchor, cls._insert_anchor_nat, cls._insert_anchor_rdr] + translation_rules + filter_rules + [cls._insert_anchor_filter] ) new_conf = '\n'.join(new_conf) if not new_conf.endswith('\n'): # required by the pf configuration parser new_conf += '\n' cmd('mkdir', '-p', os.path.dirname(cls._anchor_conf_file)) if not os.path.exists(cls._anchor_conf_file): cls.overwrite_anchor_conf() temp_path = to_tempfile(new_conf, prefix = pf_conf_path) cmd('pfctl', '-vnf', temp_path) # checking the new conf before replacing the old conf with it os.rename(temp_path, pf_conf_path) if pf_is_running(): cmd('pfctl', '-f', pf_conf_path) else: rc_conf_mod('pf_enable=YES') rc_conf_mod('pf_rules=%s' % pf_conf_path) cmd('service', 'pf', 'start')
def freebsd_update(directory, unattended): if unattended: env = os.environ.copy() env['PAGER'] = 'cat' cmd('freebsd-update', '-b', directory, 'fetch', env=env) try: cmd('freebsd-update', '-b', directory, 'install', env=env) except CalledProcessError as exc: if exc.returncode == 1: # FreeBSD offers no way to tell if that's because there was no update to install pass # or if it comes from another problem else: raise else: cmd('freebsd-update', '-b', directory, 'fetch', 'install')
def freebsd_update(directory, unattended): if unattended: env = os.environ.copy() env['PAGER'] = 'cat' cmd( 'freebsd-update', '-b', directory, 'fetch', env = env ) try: cmd( 'freebsd-update', '-b', directory, 'install', env = env ) except CalledProcessError as exc: if exc.returncode == 1: # FreeBSD offers no way to tell if that's because there was no update to install pass # or if it comes from another problem else: raise else: cmd('freebsd-update', '-b', directory, 'fetch', 'install')
def overwrite_anchor_conf(cls): temp_path = to_tempfile(cls._anchor_conf(), prefix=cls._anchor_conf_file) cmd('pfctl', '-vnf', temp_path) os.rename(temp_path, cls._anchor_conf_file)
def start(self): cmd('service', 'jail', 'start', self.name)
def execute(self, command, *args): cmd('jexec', self.name, command, *args)
def stop(self): cmd('service', 'jail', 'stop', self.name)
def init(ip4_network: IPv4Network, ip6_network: IPv6Network): if not ip4_network.is_private: raise ValueError( "The network should be private. " "see https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses" ) if not ip6_network.is_private or not ip6_network.prefixlen == 64: raise ValueError( "The network should be a private network as defined in https://tools.ietf.org/html/rfc4193.html" ) check_compatibility() rc_conf_mod('cloned_interfaces+=%s' % cloned_if()) cmd('service', 'netif', 'cloneup') address4 = str(ip4_network.network_address + 1) netmask = str(ip4_network.netmask) rc_conf_mod('ifconfig_%s=inet %s netmask %s' % (cloned_if(), address4, netmask)) cmd('ifconfig', cloned_if(), 'inet', address4, 'netmask', netmask) address6 = str(ip6_network.network_address + 1) rc_conf_mod('ifconfig_%s_ipv6=inet6 %s prefixlen 64' % (cloned_if(), address6)) cmd('ifconfig', cloned_if(), 'inet6', address6, 'prefixlen', '64') rc_conf_mod('jail_enable=YES') cmd('mkdir', '-p', '/var/mjail/instances/', '/var/mjail/releases/', '/var/mjail/generated_confs/') cmd('chmod', '700', '/var/mjail/instances/', '/var/mjail/releases/') cmd('chmod', '755', '/var/mjail/', '/var/mjail/generated_confs/') try: jail_conf = jailconf.load('/etc/jail.conf') except FileNotFoundError: jail_conf = jailconf.JailConf() jail_conf['exec.start'] = '"/bin/sh /etc/rc"' jail_conf['exec.stop'] = '"/bin/sh /etc/rc.shutdown"' jail_conf['exec.clean'] = True jail_conf['mount.devfs'] = True jail_conf['path'] = '"/var/mjail/instances/$name"' jail_conf.write('/etc/jail.conf') release = Release() if not release.built(): release.build() LocalUnboundManager.enable() PFManager.enable()
def refresh_anchor(cls): cls.overwrite_anchor_conf() cmd('pfctl', '-a', 'mjail', '-F', 'all', '-f', cls._anchor_conf_file)
def enable(cls): cmd('mkdir', '-p', cls._conf_dir) temp_path = to_tempfile(cls._conf(), prefix=cls._conf_file) os.rename(temp_path, cls._conf_file) cmd('local-unbound-setup', '-C', cls._conf_dir)
def overwrite_anchor_conf(cls): temp_path = to_tempfile(cls._anchor_conf(), prefix = cls._anchor_conf_file) cmd('pfctl', '-vnf', temp_path) os.rename(temp_path, cls._anchor_conf_file)