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 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 set_ip4(self, ip4): assert isinstance(ip4, IPv4Address) jail_conf = get_jail_conf() for jail_name, jail_block in jail_conf.jails(): try: ip4_addr = jail_block['ip4.addr'] except KeyError: continue if ip4_addr == str(ip4): raise IPAlreadyRegistered elif isinstance(ip4_addr, (list, tuple)): if str(ip4) in ip4_addr: raise IPAlreadyRegistered jail_conf[self.name]['interface'] = cloned_if() jail_conf[self.name]['ip4.addr'] = str(ip4) jail_conf.write('/etc/jail.conf') PFManager.refresh_anchor() line = '%s %s\n' % (str(ip4), self.name) lines = open('/etc/hosts').readlines() if line not in lines: lines.append(line) temp_etc_hosts = to_tempfile(''.join(lines)) shutil.move(temp_etc_hosts, '/etc/hosts')
def _set_ip(self, ip, version, network): if ip not in network: raise ValueError("Can't assign this ip to the jail. " "The ip should belong to the network %s" % network) jail_conf = get_jail_conf() for jail_name, jail_block in jail_conf.jails(): try: ip_addr = jail_block['ip%s.addr' % version] except KeyError: continue if ip_addr == str(ip): raise IPAlreadyRegistered elif isinstance(ip_addr, (list, tuple)): if str(ip) in ip_addr: raise IPAlreadyRegistered jail_conf[self.name]['interface'] = cloned_if() jail_conf[self.name]['ip%s.addr' % version] = str(ip) jail_conf.write('/etc/jail.conf') self._update_resolv_conf() PFManager.refresh_anchor() line = '%s %s\n' % (str(ip), self.name) lines = open('/etc/hosts').readlines() if line not in lines: lines.append(line) temp_etc_hosts = to_tempfile(''.join(lines)) shutil.move(temp_etc_hosts, '/etc/hosts')
def rdr(self, proto, internet_facing_host_port, jail_port): assert proto in ('tcp', 'udp') jail_conf = get_jail_conf() jail_conf[self.name][ '$mjail_rdr_%s_%s' % (proto, int(internet_facing_host_port)) ] = str(int(jail_port)) jail_conf.write('/etc/jail.conf') PFManager.refresh_anchor()
def rdr(self, proto, internet_facing_host_port, jail_port): assert proto in ('tcp', 'udp') jail_conf = get_jail_conf() jail_conf[self.name]['$mjail_rdr_%s_%s' % (proto, int(internet_facing_host_port))] = str( int(jail_port)) jail_conf.write('/etc/jail.conf') PFManager.refresh_anchor()
def _anchor_conf(cls): ext_if = get_ext_if() filter_rules = [] translation_rules = [] jail_conf = get_jail_conf() jails = [ jail_block for name, jail_block in jail_conf.jails() if ( jail_block.get('$mjail_managed') == 'yes' and jail_block.get('ip4.addr') ) ] cif = cloned_if() def append_jail_line(rules, jail, *strgs, **formats): for strg in strgs: rules.append( strg.format( ext_if = ext_if, cif = cif, ip4 = jail['ip4.addr'], **formats ) ) for jail in jails: append_jail_line( translation_rules, jail, 'nat on {ext_if} inet from {ip4} to any -> ({ext_if})' ) append_jail_line( filter_rules, jail, 'pass quick on {cif} inet proto udp from {ip4} to ({cif}) port 53', 'pass quick on {cif} inet proto tcp from {ip4} to ({cif}) port 53' ) for key in jail: if key.startswith('$mjail_rdr_'): proto, host_port = key[len('$mjail_rdr_'):].split('_') assert proto in ('udp', 'tcp') host_port = int(host_port) jail_port = int(jail[key]) append_jail_line( translation_rules, jail, 'rdr pass on {ext_if} inet proto {proto} from any to ({ext_if}) port {host_port} -> {ip4} port {jail_port}', proto = proto, host_port = host_port, jail_port = jail_port, ) filter_rules.append( 'pass quick on {cif} from ({cif}) to ({cif}:network)'.format(cif = cif), # TODO: allow only the host to access the jails but not the jails between them? # (could be an option in `mjail init`) ) ruleset = translation_rules + filter_rules + [''] return '\n'.join(ruleset)
def cancel_rdr(self, proto, internet_facing_host_port): assert proto in ('tcp', 'udp') jail_conf = get_jail_conf() for _, jail_block in jail_conf.jails(): try: del jail_block['$mjail_rdr_%s_%s' % (proto, int(internet_facing_host_port))] except KeyError: pass jail_conf.write('/etc/jail.conf') PFManager.refresh_anchor()
def available_ip4(): jails_net = jails_network4() taken_ip4s = set([jails_net.network_address + 1]) jail_conf = get_jail_conf() for _, jail_block in jail_conf.jails(): try: ip4 = IPv4Address(jail_block['ip4.addr']) except KeyError: continue else: taken_ip4s.add(ip4) for host in jails_net.hosts(): if host not in taken_ip4s: return host
def _resolv_conf(self): jail_block = get_jail_conf()[self.name] lines = [] for key, get_network in (('ip4.addr', jails_network4), ('ip6.addr', jails_network6)): if jail_block.get(key): try: j_network = get_network() except NoJailNetwork: pass else: lines.append("nameserver %s\n" % str(j_network.network_address + 1)) return ''.join(lines)
def available_ip6(): jails_net = jails_network6() taken_ip6s = set([jails_net.network_address + 1]) jail_conf = get_jail_conf() for _, jail_block in jail_conf.jails(): try: ip6 = IPv6Address(jail_block['ip6.addr']) except KeyError: continue else: taken_ip6s.add(ip6) for host in jails_net.hosts(): if host not in taken_ip6s: return host
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 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 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 _anchor_conf(cls): ext_if = get_ext_if() filter_rules = [] translation_rules = [] jail_conf = get_jail_conf() jails = [ jail_block for name, jail_block in jail_conf.jails() if (jail_block.get('$mjail_managed') == 'yes' and ( jail_block.get('ip4.addr') or jail_block.get('ip6.addr'))) ] cif = cloned_if() ext_if_ip6s = external_interface_ip6s() def append_jail_line(rules, jail, *strgs, **formats): ips = { key: jail[jail_key] for key, jail_key in (('ip4', 'ip4.addr'), ('ip6', 'ip6.addr')) if jail_key in jail } for strg in strgs: rules.append( strg.format(ext_if=ext_if, cif=cif, **ips, **formats)) for jail in jails: if 'ip4.addr' in jail: append_jail_line( translation_rules, jail, 'nat on {ext_if} inet from {ip4} to any -> ({ext_if})') append_jail_line( filter_rules, jail, 'pass quick on {cif} inet proto udp from {ip4} to ({cif}) port 53', 'pass quick on {cif} inet proto tcp from {ip4} to ({cif}) port 53' ) if 'ip6.addr' in jail: try: ext_if_ip6 = ext_if_ip6s[0] except IndexError: raise Exception( "Couldn't find a global scope IPv6 address of the external interface" ) append_jail_line( translation_rules, jail, 'nat on {ext_if} inet6 from {ip6} to any -> %s' % ext_if_ip6) append_jail_line( filter_rules, jail, 'pass quick on {cif} inet6 proto udp from {ip6} to ({cif}) port 53', 'pass quick on {cif} inet6 proto tcp from {ip6} to ({cif}) port 53' ) for key in jail: if key.startswith('$mjail_rdr_'): proto, host_port = key[len('$mjail_rdr_'):].split('_') assert proto in ('udp', 'tcp') host_port = int(host_port) jail_port = int(jail[key]) if 'ip4.addr' in jail: append_jail_line( translation_rules, jail, 'rdr pass on {ext_if} inet proto {proto} from any to ({ext_if}) port {host_port} -> {ip4} port {jail_port}', proto=proto, host_port=host_port, jail_port=jail_port, ) if 'ip6.addr' in jail: if len(ext_if_ip6s) == 0: raise Exception( "Couldn't find a global scope IPv6 address of the external interface" ) if len(ext_if_ip6s) > 1: warnings.warn( "The external interface has many global scope IPv6 addresses. " "The port redirection from port {host_port} to jail {jail_name}:{jail_port} will only occur on " "the address {ext_if_ip6} of the external interface." .format(host_port=host_port, jail_name=jail.get( 'host.hostname', ''), jail_port=jail_port, ext_if_ip6=ext_if_ip6s[0])) append_jail_line( translation_rules, jail, ('rdr pass on {ext_if} inet6 proto {proto} from any to %s port {host_port} -> {ip6} port {jail_port}' % ext_if_ip6s[0]), proto=proto, host_port=host_port, jail_port=jail_port, ) filter_rules.append( 'pass quick on {cif} from ({cif}) to ({cif}:network)'.format( cif=cif), # TODO: allow only the host to access the jails but not the jails between them? # (could be an option in `mjail init`) ) ruleset = translation_rules + filter_rules + [''] return '\n'.join(ruleset)