/home/lnzliplg/www/core.tar
build-modules.php000064400000001741151727461540010041 0ustar00<?php
namespace ElementsKit_Lite\Core;

use ElementsKit_Lite\Libs\Framework\Attr;

defined( 'ABSPATH' ) || exit;

/**
 * Module registrar.
 *
 * Call assosiated classes of every modules.
 *
 * @since 1.0.0
 * @access public
 */
class Build_Modules {

	private $modules;

	use \ElementsKit_Lite\Traits\Singleton;

	/**
	 * Hold the module list.
	 *
	 * @since 1.0.0
	 * @access public
	 * @static
	 */

	public function __construct() {
		$this->modules = \ElementsKit_Lite\Config\Module_List::instance()->get_list( 'active' );

		foreach ( $this->modules as $module_slug => $module ) {
			if ( isset( $module['path'] ) ) {
				include_once $module['path'] . 'init.php';
			}

			// make the class name and call it.
			$class_name = (
				isset( $module['base_class_name'] )
				? $module['base_class_name']
				: '\ElementsKit_Lite\Modules\\' . \ElementsKit_Lite\Utils::make_classname( $module_slug ) . '\Init'
			);
			if ( class_exists( $class_name ) ) {
				new $class_name();
			}
		}
	}
}
editor-promotion.php000064400000004753151727461540010614 0ustar00<?php
namespace ElementsKit_Lite\Core;

defined('ABSPATH') || exit;

class Editor_Promotion {

	use \ElementsKit_Lite\Traits\Singleton;

	public function init() {
		// Enqueue promotion scripts
		add_action('elementor/editor/before_enqueue_scripts', [$this, 'enqueue_editor_scripts']);
	}

	/**
	 * Get promotion widgets data
	 */
	private function get_promotion_widgets_data() {
		$widget_list = \ElementsKit_Lite\Config\Widget_List::instance()->get_list('all');
		$promotion_data = [];

		foreach ($widget_list as $slug => $widget) {
			if (isset($widget['package']) && $widget['package'] === 'pro-disabled') {
				$promotion_data[] = [
					'name' => 'ekit-' . $slug,
					'title' => isset($widget['title']) ? $widget['title'] : ucwords(str_replace('-', ' ', $slug)),
					'icon' => isset($widget['icon']) ? $widget['icon'] : 'eicon-star',
					'categories' => ['elementskit'],
					'promotion' => [
						'title' => sprintf(__('%s Widget', 'elementskit-lite'), isset($widget['title']) ? $widget['title'] : ucwords(str_replace('-', ' ', $slug))),
						'description' => sprintf(
							__( 'Unlock the %s widget and dozens of powerful ElementsKit Pro features to design faster, smarter, and more flexible websites.', 'elementskit-lite'),
							isset($widget['title']) ? $widget['title'] : ucwords(str_replace('-', ' ', $slug))
						),
						'upgrade_url' => 'https://wpmet.com/plugin/elementskit/pricing/',
						'upgrade_text' => __('Upgrade Now', 'elementskit-lite'),
					],
				];
			}
		}
		return $promotion_data;
	}

	/**
	 * Enqueue editor scripts for promotion
	 */
	public function enqueue_editor_scripts() {
		$promotion_widgets = $this->get_promotion_widgets_data();

		wp_enqueue_script(
			'elementskit-editor-promotion',
			\ElementsKit_Lite::widget_url() . 'init/assets/js/editor-promotion.js',
			['elementor-editor', 'elementor-common'],
			\ElementsKit_Lite::version(),
			true
		);

		wp_localize_script(
			'elementskit-editor-promotion',
			'ekitPromotion',
			[
				'promotionWidgets' => $promotion_widgets,
				'upgradeUrl' => 'https://wpmet.com/plugin/elementskit/pricing/',
				'debug' => true,
				'i18n' => [
					'proFeature' => __('Pro Feature', 'elementskit-lite'),
					'upgradeNow' => __('Upgrade Now', 'elementskit-lite'),
					'learnMore' => __('Learn More', 'elementskit-lite'),
				],
			]
		);

		// Enqueue styles
		wp_enqueue_style(
			'elementskit-editor-promotion',
			\ElementsKit_Lite::widget_url() . 'init/assets/css/editor-promotion.css',
			[],
			\ElementsKit_Lite::version()
		);
	}
}
activation-actions.php000064400000001636151727461540011076 0ustar00<?php

namespace ElementsKit_Lite\Core;

use ElementsKit_Lite\Libs\Framework\Classes\Onboard_Status;

defined( 'ABSPATH' ) || exit;

class Activation_Actions {

	private $key     = 'elementskit-lite__plugin_activated';
	private $has_key = false;

	public function init() {
		if ( ! is_admin() ) {
			return;
		}

		$this->process_key();

		if ( $this->has_key === false ) {
			return;
		}

		// call activation job classes or methods here.
		$this->flush_rewrite_rules();
		$this->redirect_to_onboard();
	}

	private function process_key() {
		if ( ! empty( get_option( $this->key ) ) ) {
			$this->has_key = true;
			delete_option( $this->key );
		}
	}

	private function flush_rewrite_rules() {
		// all CPTs must be declared completely before flushing rewrite rules. otherwise, it won't work as expected.
		flush_rewrite_rules();
	}

	private function redirect_to_onboard() {
		// Onboard_Status::redirect_onboard();
	}

}
handler-api.php000064400000002144151727461540007456 0ustar00<?php
namespace ElementsKit_Lite\Core;

class Handler_Api {

	public $prefix  = '';
	public $param   = '';
	public $request = null;

	public function __construct() {
		$this->config();
		$this->init();
	}

	public function config() {
	}

	public function init() {
		add_action(
			'rest_api_init',
			function () {
				register_rest_route(
					untrailingslashit( 'elementskit/v1/' . $this->prefix ),
					'/(?P<action>\w+)/' . ltrim( $this->param, '/' ),
					array(
						'methods'             => \WP_REST_Server::ALLMETHODS,
						'callback'            => array( $this, 'callback' ),
						'permission_callback' => '__return_true',
					// all permissions are implimented inside the callback action
					)
				);
			}
		);
	}

	public function callback( $request ) {
		$this->request = $request;
		$action_class  = strtolower( $this->request->get_method() ) . '_' . $this->request['action'];

		if ( method_exists( $this, $action_class ) ) {
			return $this->{$action_class}();
		} else {
			return new \WP_Error( 'invalid_action', esc_html__( 'Invalid action', 'elementskit-lite' ), array( 'status' => 400 ) );
		}
	}
}
build-inline-scripts.php000064400000001764151727461540011341 0ustar00<?php
namespace ElementsKit_Lite\Core;

defined( 'ABSPATH' ) || exit;

/**
 * Inline script registrar.
 *
 * Returns all necessary inline js & css.
 *
 * @since 1.0.0
 * @access public
 */
class Build_Inline_Scripts {

	use \ElementsKit_Lite\Traits\Singleton;

	public function __construct() {
		// Frontend + Admin scripts
		add_action( 'wp_print_scripts', array( $this, 'print_inline_script' ) );
	}

	/**
	 * Get common inline JavaScript.
	 *
	 * @return string
	 */
	public function common_js() {
		ob_start(); ?>

		var elementskit = {
			resturl: '<?php echo defined( 'ICL_SITEPRESS_VERSION' ) ? esc_url(home_url('/wp-json/elementskit/v1/')) : esc_url(get_rest_url() . 'elementskit/v1/'); ?>',
		}

		<?php
		$output =  ob_get_contents();
		ob_end_clean();
		return $output;
	}

	/**
	 * Print inline JavaScript.
	 *
	 * @return void
	 */
	public function print_inline_script() {
		printf(
			"<script type='text/javascript'>%s</script>",
			\ElementsKit_Lite\Utils::render( $this->common_js() )
		);
	}
}
build-widgets.php000064400000005174151727461540010043 0ustar00<?php
namespace ElementsKit_Lite\Core;

use ElementsKit_Lite\Libs\Framework\Attr;

defined( 'ABSPATH' ) || exit;

class Build_Widgets {

	/**
	 * Collection of default widgets.
	 *
	 * @since 1.0.0
	 * @access private
	 */
	private $widgets;

	use \ElementsKit_Lite\Traits\Singleton;

	public function __construct() {

		new \ElementsKit_Lite\Widgets\Init\Enqueue_Scripts();
		$this->widgets = \ElementsKit_Lite\Config\Widget_List::instance()->get_list( 'full' );

		// check if the widget is exists
		foreach ( $this->widgets as $widget ) {
			$this->add_widget( $widget );
		}

		add_action( 'elementor/widgets/register', array( $this, 'register_widget' ) );
	}


	public function add_widget( $widget_config ) {
		$widget_dir = (
			isset( $widget_config['path'] )
			? $widget_config['path']
			: \ElementsKit_Lite::widget_dir() . $widget_config['slug'] . '/'
		);

		$widget_file_path = $widget_dir . $widget_config['slug'] . '.php';
		$widget_handler_file_path = $widget_dir . $widget_config['slug'] . '-handler.php';
		if (!file_exists($widget_file_path) && !file_exists($widget_handler_file_path)) {
			return;
		}

		include $widget_file_path;
		include $widget_handler_file_path;

		$base_class_name = (
			( isset( $widget_config['base_class_name'] ) )
			? $widget_config['base_class_name']
			: '\Elementor\ElementsKit_Widget_' . \ElementsKit_Lite\Utils::make_classname( $widget_config['slug'] )
		);

		$handler       = $base_class_name . '_Handler';
		$handler_class = new $handler();

		if ( $handler_class->scripts() != false ) {
			add_action( 'wp_enqueue_scripts', array( $handler_class, 'scripts' ) );
		}

		if ( $handler_class->styles() != false ) {
			add_action( 'wp_enqueue_scripts', array( $handler_class, 'styles' ) );
		}

		if ( $handler_class->inline_css() != false ) {
			wp_add_inline_style( 'elementskit-init-css', $handler_class->inline_css() );
		}

		if ( $handler_class->inline_js() != false ) {
			wp_add_inline_script( 'elementskit-init-js', $handler_class->inline_js() );
		}

		if ( $handler_class->register_api() != false ) {
			if ( \file_exists( $handler_class->register_api() ) ) {
				include_once $handler_class->register_api();
				$api = $base_class_name . '_Api';
				new $api();
			}
		}

		if ( $handler_class->wp_init() != false ) {
			add_action( 'init', array( $handler_class, 'wp_init' ) );
		}
	}


	public function register_widget( $widgets_manager ) {
		foreach ( $this->widgets as $widget_slug => $widget ) {
			$class_name = '\Elementor\ElementsKit_Widget_' . \ElementsKit_Lite\Utils::make_classname( $widget_slug );
			if ( class_exists( $class_name ) ) {
				$widgets_manager->register( new $class_name() );
			}
		}
	}
}
handler-widget.php000064400000001323151727461540010166 0ustar00<?php 
namespace ElementsKit_Lite\Core;

class Handler_Widget {

	public function wp_init() {
		return false;
	}

	static function get_name() {
		return false;
	}

	static function get_title() {
		return false;
	}

	static function get_icon() {
		return false;
	}

	static function get_categories() {
		return false;
	}
	
	static function get_dir() {
		return false;
	}
	
	static function get_url() {
		return false;
	}
	
	public function register_api() {
		return false;
	}

	public function inline_js() {
		return false;
	}

	public function inline_css() {
		return false;
	}
	
	public function sass() {
		return false;
	}

	public function scripts() {
		return false;
	}
	public function styles() {
		return false;
	}
}
config-list.php000064400000003247151727461540007515 0ustar00<?php
namespace ElementsKit_Lite\Core;

abstract class Config_List {

	use \ElementsKit_Lite\Traits\Singleton;

	private $full_list   = array();
	private $active_list = array();

	protected $optional_list = array();
	protected $required_list = array();

	protected $type;

	public function __construct() {
		$this->set_optional_list();
		$this->set_required_list();
		$this->set_full_list();
		$this->set_active_list();
	}

	public function get_list( $data = 'full', $module = null ) {
		if ( $module != null ) {
			return ( $this->{$data . '_list'}[ $module ] ?? false );
		}

		// Return all items including pro-disabled for promotion purposes
		if ( $data === 'all' ) {
			return $this->full_list;
		}

		return $this->{$data . '_list'};
	}

	public function is_active( $item ) {

		$item = ( $this->active_list[ $item ] ?? array() );

		return empty( $item['package'] ) ? false : ( ( $item['package'] == 'free' || $item['package'] == 'pro' ) );
	}

	private function set_active_list() {
		$database_list = \ElementsKit_Lite\Libs\Framework\Attr::instance()->utils->get_option( $this->type . '_list', array() );

		foreach ( $this->full_list as $key => $item ) {

			if ( isset( $database_list[ $key ]['status'] ) && $database_list[ $key ]['status'] == 'inactive' && ! key_exists( $key, $this->required_list ) ) {
				continue;
			}

			if ( isset( $item['package'] ) && $item['package'] == 'pro-disabled' ) {
				continue;
			}

			$this->active_list[ $key ] = $item;
		}
	}

	private function set_full_list() {
		$this->full_list = array_merge( $this->required_list, $this->optional_list );
	}

	abstract protected function set_required_list();

	abstract protected function set_optional_list();

}
__pycache__/helper.cpython-36.pyc000064400000000256151731527000012665 0ustar003

��g$�@sdZdZdS)zThe helper maxnamelen� N)�__doc__ZHELPER_MAXNAMELEN�rr�/usr/lib/python3.6/helper.py�<module>s__pycache__/ebtables.cpython-36.opt-1.pyc000064400000016336151731527000014134 0ustar003

��g�$�@s&dgZddlZddlmZddlmZddlmZm	Z	m
Z
ddlmZddl
mZddlmZmZddlZd	gd
ddgd
ddgd�ZiZiZiZx�ej�D]tZgee<e�ee<x\eeD]PZeejde�eejdeef�eejde�eejde�q�Wq�WGdd�de�ZdS)�ebtables�N)�runProg)�log)�tempFile�readfile�	splitArgs)�COMMANDS)�	ipXtables)�
FirewallError�INVALID_IPVZBROUTINGZ
PREROUTINGZPOSTROUTINGZOUTPUTZINPUTZFORWARD)ZbrouteZnat�filterz-N %s_directz-I %s 1 -j %s_directz-I %s_direct 1 -j RETURNz	%s_directc@s�eZdZdZdZdZdd�Zdd�Zdd�Zd	d
�Z	dd�Z
d
d�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd�Zdd�Zd/d d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd0d+d,�Zd-d.�ZdS)1rZebFcCsBt|j|_td|j|_|j�|_|j�|_|j�g|_	dS)Nz
%s-restore)
r�ipv�_command�_restore_command�_detect_restore_noflush_optionZrestore_noflush_option�_detect_concurrent_option�concurrent_option�fill_exists�available_tables)�self�r�/usr/lib/python3.6/ebtables.py�__init__9s

zebtables.__init__cCs$tjj|j�|_tjj|j�|_dS)N)�os�path�existsrZcommand_existsrZrestore_command_exists)rrrrrAszebtables.fill_existscCs(d}t|jddg�}|ddkr$d}|S)N�z--concurrentz-Lr)rr)rr�retrrrrEs
z"ebtables._detect_concurrent_optioncCs.g}y|j|d�Wntk
r(dSXdS)N�offFT)�	set_rules�
ValueError)r�rulesrrrrOsz'ebtables._detect_restore_noflush_optioncCs�g}|jr |j|kr |j|j�|dd�|D�7}tjd|j|jdj|��t|j|�\}}|dkr~td|jdj|�|f��|S)NcSsg|]}d|�qS)z%sr)�.0�itemrrr�
<listcomp>^sz"ebtables.__run.<locals>.<listcomp>z	%s: %s %s� rz'%s %s' failed: %s)	r�appendr�debug2�	__class__r�joinrr )r�argsZ_args�statusrrrrZ__runYszebtables.__runcCs(x"dD]}||krttd|��qWdS)N�
%%REJECT%%�%%ICMP%%�%%LOGTYPE%%z'%s' invalid for ebtables)r,r-r.)r
r)r�rule�strrrr�_rule_validatefs
zebtables._rule_validatecCs|tko|t|kS)N)�BUILT_IN_CHAINS)rr
�table�chainrrr�is_chain_builtinlszebtables.is_chain_builtincCsJg}|r4|jd|d|g�|jd|d|dddg�n|jd|d|g�|S)Nz-tz-Nz-I�1z-jZRETURNz-X)r&)r�addr3r4r!rrr�build_chain_rulespszebtables.build_chain_rulescCs8d|g}|r |d|t|�g7}n|d|g7}||7}|S)Nz-tz-Iz-D)r0)rr7r3r4�indexr*r/rrr�
build_rule{szebtables.build_rulecCs
tj|�S)N)r	Zcommon_reverse_rule)rr*rrr�reverse_rule�szebtables.reverse_rulecCstj|�dS)N)r	Zcommon_check_passthrough)rr*rrr�check_passthrough�szebtables.check_passthroughcCs
tj|�S)N)r	Zcommon_reverse_passthrough)rr*rrr�reverse_passthrough�szebtables.reverse_passthroughc
Cs<t�}d}i}x�|D]�}|dd�}|j|�xTdD]L}y|j|�}	Wntk
rZYq4Xt|�|	dkr4|j|	�|j|	�}q4Wx^tt|��D]N}	xHtjD]>}
|
||	kr�||	j	d�o�||	j
d�r�d||	||	<q�Wq�W|j|g�j|�qWxD|D]<}|j
d|�x&||D]}|j
dj|�d	��qW�qW|j�tj|j�}tjd
|j|jd|j|jf�g}|jd�t|j||jd
�\}
}tj�dk�rt|j�}|dk	�rd}	xH|D]@}tjd|	|fddd�|j
d	��s�tjddd�|	d7}	�q�Wtj|j�|
dk�r8td|jdj|�|f��dS)Nr�-t�--table��"z"%s"z*%s
r%�
z	%s: %s %sz%s: %dz	--noflush)�stdin�z%8d: %sr)�nofmt�nlr)rEz'%s %s' failed: %s)r>r?)rr1r9r �len�pop�range�stringZ
whitespace�
startswith�endswith�
setdefaultr&�writer)�closer�stat�namerr'r(r�st_sizerZgetDebugLogLevelrZdebug3�unlink)rr!�
log_deniedZ	temp_filer3Ztable_rulesZ_ruler/�opt�i�crPr*r+r�lines�linerrrr�sZ




 




zebtables.set_rulescCs|j|�|j|�S)N)r1�_ebtables__run)rr/rTrrr�set_rule�s
zebtables.set_ruleNcCs�g}|r|gntj�}xp|D]h}||jkr6|j|�qy*|jd|dg�|jj|�|j|�Wqtk
r�tjd|�YqXqW|S)Nz-tz-Lz#ebtables table '%s' does not exist.)r2�keysrr&rZr rZdebug1)rr3rZtablesrrr�get_available_tables�s

zebtables.get_available_tablescCsiS)Nr)rr3rrr�get_zone_table_chains�szebtables.get_zone_table_chainscCsFg}x<tj�D]0}||j�kr qxdD]}|jd||g�q&WqW|S)N�-F�-X�-Zz-t)r_r`ra)r2r\r]r&)rr!r3�flagrrr�build_flush_rules�s
zebtables.build_flush_rulescCs^g}|dkrdn|}xDtj�D]8}||j�kr0qx$t|D]}|jd|d||g�q:WqW|S)NZPANICZDROPz-tz-P)r2r\r]r&)rZpolicyr!Z_policyr3r4rrr�build_set_policy_rules�szebtables.build_set_policy_rulescCsgS)Nr)rrrr�build_default_tables�szebtables.build_default_tablesrcCs�g}x�tD]�}||j�krq
t|dd�}|dkrJ|tkrJ|jt|�d|g}x:|D]2}t|�tkrx|j||�qX|j|t|��qXWq
W|S)Nrz-t)�
DEFAULT_RULESr]�	LOG_RULES�extend�type�listr&r)rrTZ
default_rulesr3Z_default_rules�prefixr/rrr�build_default_rules�s

zebtables.build_default_rulescCs
||jkS)N)r
)rr
rrr�is_ipv_supportedszebtables.is_ipv_supported)N)r)�__name__�
__module__�__qualname__r
rQZpolicies_supportedrrrrrZr1r5r8r:r;r<r=rr[r]r^rcrdrerlrmrrrrr4s0


	@


)�__all__Zos.pathrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsrrrZfirewall.configrZ
firewall.corer	Zfirewall.errorsr
rrJr2rfrgZ
OUR_CHAINSr\r3�setr4r&r7�objectrrrrr�<module>s.
__pycache__/helper.cpython-36.opt-1.pyc000064400000000256151731527010013625 0ustar003

��g$�@sdZdZdS)zThe helper maxnamelen� N)�__doc__ZHELPER_MAXNAMELEN�rr�/usr/lib/python3.6/helper.py�<module>s__pycache__/fw.cpython-36.pyc000064400000066115151731527010012031 0ustar003

��g���@s�dgZddlZddlZddlZddlZddlZddlmZddlm	Z	ddl
mZddl
mZddl
m
Z
ddl
mZdd	l
mZdd
lmZddlmZddlmZdd
lmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl$m%Z%m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/m0Z0ddl1m2Z2m3Z3ddl4m5Z5ddl6m7Z7ddl8m9Z9ddl:m;Z;ddlm<Z<dd l=m>Z>Gd!d�de?�Z@dS)"�Firewall�N)�config)�	functions)�	ipXtables)�ebtables)�nftables)�ipset)�modules)�FirewallIcmpType)�FirewallService)�FirewallZone)�FirewallDirect)�FirewallConfig)�FirewallPolicies)�
FirewallIPSet)�FirewallTransaction)�FirewallHelper)�FirewallPolicy)�nm_get_bus_name�nm_get_interfaces_in_zone)�log)�firewalld_conf)�Direct)�service_reader)�icmptype_reader)�zone_reader�Zone)�ipset_reader)�IPSET_TYPES)�
helper_reader)�
policy_reader)�errors)�
FirewallErrorc@s�eZdZdedd�Zdd�Zdd�Zdd	�Zd
d�Zdfdd
�Zdd�Z	dgdd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zdhd)d*�Zdid+d,�Zd-d.�Zdjd/d0�Zdkd1d2�Zdld3d4�Zd5d6�Zd7d8�Zd9d:�Zd;d<�Zd=d>�Z d?d@�Z!dAdB�Z"dCdD�Z#dEdF�Z$dGdH�Z%dIdJ�Z&dKdL�Z'dMdN�Z(dmdOdP�Z)dQdR�Z*dSdT�Z+dUdV�Z,dWdX�Z-dYdZ�Z.d[d\�Z/d]d^�Z0d_d`�Z1dadb�Z2dcdd�Z3d(S)nrFcCsttj�|_||_|jr>d|_d|_d|_d|_t	|_
d|_nrtj
|�|_d|_g|_tj|�|_d|_g|_tj�|_d|_tj�|_d|_g|_
tj|�|_d|_tj�|_t|�|_t|�|_t|�|_ t!|�|_"t#|�|_t$�|_%t&|�|_t'|�|_(t)|�|_*|j+�dS)NFT),rr�FIREWALLD_CONF�_firewalld_conf�_offline�ip4tables_enabled�ip6tables_enabled�ebtables_enabled�
ipset_enabledr�ipset_supported_types�nftables_enabledr�	ip4tables�ip4tables_backend�ipv4_supported_icmp_types�	ip6tables�ip6tables_backend�ipv6_supported_icmp_typesr�ebtables_backendr�
ipset_backendr�nftables_backendr	�modules_backendr
�icmptyper�servicer�zoner
�directrr�policiesrr�helperr�policy�_Firewall__init_vars)�selfZoffline�r?�/usr/lib/python3.6/fw.py�__init__CsB










zFirewall.__init__cCsDd|j|j|j|j|j|j|j|j|j|j	|j
|j|j|j
|jfS)Nz:%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r))�	__class__r&r'r(�_state�_panic�
_default_zone�_module_refcount�_marks�cleanup_on_exit�cleanup_modules_on_exit�ipv6_rpfilter_enabledr)�_individual_calls�_log_denied)r>r?r?r@�__repr__kszFirewall.__repr__cCsjd|_d|_d|_i|_g|_tj|_tj|_	tj
|_tj|_
tj|_tj|_tj|_tj|_tj|_dS)NZINITF�)rCrDrErFrGrZFALLBACK_CLEANUP_ON_EXITrHZ FALLBACK_CLEANUP_MODULES_ON_EXITrIZFALLBACK_IPV6_RPFILTERrJZFALLBACK_INDIVIDUAL_CALLSrKZFALLBACK_LOG_DENIEDrLZFALLBACK_FIREWALL_BACKEND�_firewall_backendZFALLBACK_FLUSH_ALL_ON_RELOAD�_flush_all_on_reloadZFALLBACK_RFC3964_IPV4�
_rfc3964_ipv4ZFALLBACK_ALLOW_ZONE_DRIFTING�_allow_zone_drifting)r>r?r?r@Z__init_varstszFirewall.__init_varscCs�|jr$d|jj�kr$tjd�d|_|jrHd|jj�krHtjd�d|_|jrld|jj�krltjd�d|_|jr�|jr�|j	r�tj
d�tjd�dS)N�filterziptables is not usable.Fzip6tables is not usable.zebtables is not usable.zNo IPv4 and IPv6 firewall.�)
r&r-�get_available_tablesr�info1r'r0r(r2r+�fatal�sys�exit)r>r?r?r@�
_check_tables�s 



zFirewall._check_tablescCszy|jj�Wn*tk
r8tjd�d|_g|_YnX|jj�|_|jj	�|jj
s||jjrltjd�ntjd�d|_|j
r�|jjd�|_n|jr�|jj�|_ng|_|jj	�|jj
s�|jjr�tjd�ntjd�d|_|j
r�|jjd�|_n|j�r|jj�|_ng|_|jj	�|jj
�sN|jj�r>tjd	�ntjd
�d|_|j�rv|j�rv|jj�rvtjd�dS)Nz4ipset not usable, disabling ipset usage in firewall.FzFiptables-restore is missing, using individual calls for IPv4 firewall.zCiptables-restore and iptables are missing, disabling IPv4 firewall.�ipv4zGip6tables-restore is missing, using individual calls for IPv6 firewall.zEip6tables-restore and ip6tables are missing, disabling IPv6 firewall.�ipv6zHebtables-restore is missing, using individual calls for bridge firewall.zEebtables-restore and ebtables are missing, disabling bridge firewall.zSebtables-restore is not supporting the --noflush option, will therefore not be used)r3Zset_list�
ValueErrorr�warningr)r*Zset_supported_typesr-Zfill_exists�restore_command_existsZcommand_existsr&r+r4Zsupported_icmp_typesr.r0r'r1r2r(rK�restore_noflush_option�debug1)r>r?r?r@�_start_check�sL








zFirewall._start_checkc>Cs�tj}tjdtj�y|jj�Wn8tk
rZ}ztj|�tjd�WYdd}~X�n"X|jj	d�rt|jj	d�}|jj	d�r�|jj	d�}|dk	r�|j
�dBkr�d|_tjd|j�|jj	d	��r|jj	d	�}|dk	r�|j
�dCkr�d|_|dk	�r|j
�dDk�rd|_tjd
|j�|jj	d��rv|jj	d�}|dk	�rv|j
�dEk�rvtjd�y|j
j�Wntk
�rtYnX|jj	d��r�|jj	d�}|dk	�r�|j
�dFk�r�d|_|j
�dGk�r�d|_|j�r�tjd�n
tjd�|jj	d��r"|jj	d�}|dk	�r"|j
�dHk�r"tjd�d|_|jj	d��rt|jj	d�}|dk�sT|j
�dk�r\d|_n|j
�|_tjd|j�|jj	d��r�|jj	d�|_tjd|j�|jj	d��r�|jj	d�}|j
�dIk�r�d|_nd|_tjd|j�|jj	d��r&|jj	d�}|j
�dJk�rd|_nd|_tjd|j�|jj	d��r||jj	d�}|j
�dKk�rVd|_nd|_|j�sntjd�tjd |j�|jjtj|j��|j|j�|j�s�|j�tjd!�y|j
jj�WnZtk
�r }z<|j
j��r�tjd"|j
jj |�ntjd"|j
jj |�WYdd}~XnX|jj!tj|j
��|j"tj#d#�|j"tj$d#�|j"tj%d$�|j"tj&d$�t'|j(j)��d%k�r�tjd&�|j"tj*d'�|j"tj+d'�|j"tj,d(�|j"tj-d(�t'|j.j/��d%k�r�tjd)�|j"tj0d*�|j"tj1d*�t'|j2j3��d%k�r&tj4d+�t5j6d,�|j"tj7d-�|j"tj8d-�d}x.dLD]&}||j2j3�k�rLtj4d1|�d}�qLW|�r�t5j6d,�||j2j3�k�r�d2|j2j3�k�r�d2}nd3|j2j3�k�r�d3}nd.}tjd4||�|}ntjd5|�t9tj:�}	t;j<j=tj:��rRtjd6tj:�y|	j�Wn4tk
�rP}ztjd7tj:|�WYdd}~XnX|j>j?|	�|jj@tj|	��|jA|�|_B|j�r�dS|jC�tjD�d%k�r�tEjE�}
tF|�}|�s�|jG|d8�|�r�|�s�|jH�r�|jIjJ��r�|jKd�|jL�|�r|�rtjd9�|jMjN�|jO|d8�|jKd�|jL�|jH�rX|jIjJ��rXtjd:�|jIjP�tjd;�|jQ|d8�tjd<�|j2jR|d8�|j2jSd|jB|d8�tjd=�|jTjU|d8�|jKd�|jL�|j>jV��rVtjd>�|j>jW|�y|jKd�|jL�WnXtk
�r>}z$t|jXd?|jY�r&|jYnd@��WYdd}~Xntk
�rT�YnX~tjD�d,k�r�tEjE�}
tjZdA|
|
�dS)MNz"Loading firewalld config file '%s'z0Using fallback firewalld configuration settings.�DefaultZoneZ
CleanupOnExit�no�falseFzCleanupOnExit is set to '%s'ZCleanupModulesOnExit�yes�trueTz#CleanupModulesOnExit is set to '%s'ZLockdownzLockdown is enabledZ
IPv6_rpfilterzIPv6 rpfilter is enabledzIPV6 rpfilter is disabledZIndividualCallszIndividualCalls is enabled�	LogDeniedZoffzLogDenied is set to '%s'ZFirewallBackendzFirewallBackend is set to '%s'ZFlushAllOnReloadzFlushAllOnReload is set to '%s'ZRFC3964_IPv4zRFC3964_IPv4 is set to '%s'ZAllowZoneDriftingz�AllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.z AllowZoneDrifting is set to '%s'zLoading lockdown whitelistz*Failed to load lockdown whitelist '%s': %srr6rzNo icmptypes found.r;r7zNo services found.r8zNo zones found.rTr<�block�drop�trustedzZone '%s' is not available.ZpublicZexternalz+Default zone '%s' is not valid. Using '%s'.zUsing default zone '%s'zLoading direct rules file '%s'z)Failed to load direct rules file '%s': %s)�use_transactionzUnloading firewall moduleszApplying ipsetszApplying default rule setzApplying used zoneszApplying used policiesz2Applying direct chains rules and passthrough rulesz
Direct: %srNz%Flushing and applying took %f seconds)rdre)rfrg)rdre)rfrg)rdre)rfrg)rfrg)rdre)rdre)rdre)rirjrk)[rZ
FALLBACK_ZONErrar#r$�read�	Exceptionr^�get�lowerrHrIr:Zenable_lockdownr"rJrKrLrOrPrQrRr%Zset_firewalld_conf�copy�deepcopy�_select_firewall_backendrbZlockdown_whitelistZquery_lockdown�error�filenameZset_policies�_loaderZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPES�lenr6�
get_icmptypesZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESr7�get_servicesZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr8�	get_zonesrWrXrYZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESrZFIREWALLD_DIRECT�os�path�existsr9Zset_permanent_configZ
set_direct�
check_zonerErZZgetDebugLogLevel�timer�flushr)rZ
has_ipsets�execute�clearr5�unload_firewall_modules�apply_default_tablesZapply_ipsets�apply_default_rulesZapply_zones�change_default_zoner<Zapply_policiesZhas_configurationZapply_direct�code�msgZdebug2)r>�reload�complete_reloadZdefault_zoner��valuert�zr8�objZtm1�transaction�eZtm2r?r?r@�_start�st







 




















.zFirewall._startcCsHy|j�Wn&tk
r2d|_|jd��YnXd|_|jd�dS)N�FAILED�ACCEPT�RUNNING)r�rnrC�
set_policy)r>r?r?r@�start�s
zFirewall.startcCshtjj|�sdS|rZ|jtj�rV|dkrVt�}tjj|�|_|j	|j�||_d|_
nd}�x|ttj|��D�]h}|j
d�s�|jtj�rl|dkrltjjd||f�rl|jd||f|dd�qld||f}tjd||��y�|dk�r�t||�}|j|jj�k�r8|jj|j�}tjd	||j|j|j�|jj|j�n|jjtj��rNd|_
y|jj|�Wn<tk
�r�}	ztjd
|jt|	�f�WYdd}	~	XnX|jjtj|���n�|dk�rFt||�}|j|jj�k�r|jj |j�}tjd	||j|j|j�|jj!|j�n|jjtj��r$d|_
|jj"|�|jj"tj|���n.|dk�rnt#|||d�}|�r�dtjj|�tjj|�d
d�f|_|j	|j�tj|�}
|j|j$j%�k�r|j$j&|j�}|j$j'|j�|j(�r�tjd||j||�|j)|�ntjd	||j|j|j�n|jjtj��r,d|_
d|
_
|jj*|
�|�r^tjd||j||�|j)|�n|j$j*|��n|dk�rDt+||�}|j|j,j-�k�r�|j,j.|j�}tjd	||j|j|j�|j,j/|j�n|jjtj��r�d|_
y|j,j0|�Wn<tk
�r,}	ztj1d
|jt|	�f�WYdd}	~	XnX|jj0tj|���n0|dk�r�t2||�}|j|j3j4�k�r�|j3j5|j�}tjd	||j|j|j�|j3j6|j�n|jjtj��r�d|_
|j3j7|�|jj7tj|��n�|dk�rht8||�}|j|j9j:�k�r2|j9j;|j�}tjd	||j|j|j�|j9j<|j�n|jjtj��rHd|_
|j9j=|�|jj>tj|��ntj?d|�Wqltk
�r�}ztj@d|||�WYdd}~XqltAk
�r�tj@d||�tjB�YqlXqlW|�rd|j(�rd|j|j$j%�k�rX|j$j&|j�}tjd||j|j|j�y|j$j'|j�WntAk
�rHYnX|jjC|j�|j$j*|�dS)Nr8Fz.xmlz%s/%sT)�combinezLoading %s file '%s'r6z  Overloads %s '%s' ('%s/%s')z%s: %s, ignoring for run-time.r7)Z
no_check_namer�z  Combining %s '%s' ('%s/%s')rr;r<zUnknown reader type %szFailed to load %s file '%s': %szFailed to load %s file '%s':z0  Overloading and deactivating %s '%s' ('%s/%s')���)Dr{r|�isdir�
startswithrZ
ETC_FIREWALLDr�basename�nameZ
check_name�default�sorted�listdir�endswithrvrrarr6rxZget_icmptyperuZremove_icmptypeZadd_icmptyper"rV�strrqrrrr7ryZget_serviceZremove_serviceZadd_servicerr8rzZget_zoneZremove_zone�combinedr�Zadd_zonerr�
get_ipsets�	get_ipsetZremove_ipset�	add_ipsetr^rr;Zget_helpersZ
get_helperZ
remove_helperZ
add_helperr r<�get_policiesZ
get_policyZ
remove_policyZ
add_policyZadd_policy_objectrWrtrnZ	exceptionZforget_zone)r>r|Zreader_typer�Z
combined_zonerur�r�Zorig_objrtZ
config_objr�r?r?r@rvs


$







$




zFirewall._loadercCsp|jj�|jj�|jj�|jj�|jj�|jj�|jj�|jj�|j	j�|j
j�|j�dS)N)r6�cleanupr7r8rr;rr9r:r<r$r=)r>r?r?r@r��s









zFirewall.cleanupcCsN|jsB|jr(|j�|jj�|jd�|jrBtjd�|jj	�|j
�dS)Nr�z!Unloading firewall kernel modules)r%rHr�rr�rIrrar5r�r�)r>r?r?r@�stop�s



z
Firewall.stopc	Cs�d}d}x�t|�D]�\}}|r0|jj|�\}}n$|j|dkrDd}n|jj|�\}}|dkrn|d7}||7}q|r�|jj|d�|j|d7<q||jkr|j|d8<|j|dkr|j|=qW||fS)NrrNrT)�	enumerater5�load_modulerFZ
unload_module�
setdefault)	r>Z_modules�enableZ
num_failedZ
error_msgs�i�moduleZstatusr�r?r?r@�handle_modules�s(
zFirewall.handle_modulescCs|dkrd|_dS)NrF)r+)r>�backendr?r?r@rs�sz!Firewall._select_firewall_backendcCs4x|j�D]}|j|kr
|Sq
Wttjd|��dS)Nz'%s' backend does not exist)�all_backendsr�r"r!Z
UNKNOWN_ERROR)r>r�r�r?r?r@�get_backend_by_name�s

zFirewall.get_backend_by_namecCs\|jr|jS|dkr |jr |jS|dkr4|jr4|jS|dkrH|jrH|jStt	j
d|��dS)Nr[r\�ebz-'%s' is not a valid backend or is unavailable)r+r4r&r-r'r0r(r2r"r!�INVALID_IPV)r>�ipvr?r?r@�get_backend_by_ipv�szFirewall.get_backend_by_ipvcCsP|dkr|jr|jS|dkr(|jr(|jS|dkr<|jr<|jSttjd|��dS)Nr[r\r�z-'%s' is not a valid backend or is unavailable)	r&r-r'r0r(r2r"r!r�)r>r�r?r?r@�get_direct_backend_by_ipv�sz"Firewall.get_direct_backend_by_ipvcCs<|dkr|jS|dkr|jS|dkr*|jS|dkr8|jSdS)Nr,r/rrF)r&r'r(r+)r>r�r?r?r@�is_backend_enabled�szFirewall.is_backend_enabledcCs8|jr
dS|dkr|jS|dkr&|jS|dkr4|jSdS)NTr[r\r�F)r+r&r'r()r>r�r?r?r@�is_ipv_enabledszFirewall.is_ipv_enabledcCsRg}|jr|j|j�n6|jr*|j|j�|jr<|j|j�|jrN|j|j�|S)N)	r+�appendr4r&r-r'r0r(r2)r>�backendsr?r?r@�enabled_backendsszFirewall.enabled_backendscCsPg}|jr|j|j�|jr(|j|j�|jr:|j|j�|jrL|j|j�|S)N)	r&r�r-r'r0r(r2r+r4)r>r�r?r?r@r�szFirewall.all_backendsNcCsN|dkrt|�}n|}x |j�D]}|j||j��q W|dkrJ|jd�dS)NT)rr��	add_rulesZbuild_default_tablesr�)r>rlr�r�r?r?r@r�$s
zFirewall.apply_default_tablescCs�|dkrt|�}n|}x(|j�D]}|j|j�}|j||�q W|jd�r~|jd�}d|j�kr~|jr~|j	|j�}|j||�|jd�r�|j
r�|j�}|j||�|dkr�|jd�dS)Nr\�rawT)
rr�Zbuild_default_rulesrLr�r�r�rUrJZbuild_rpfilter_rulesrQZbuild_rfc3964_ipv4_rulesr�)r>rlr�r��rulesZipv6_backendr?r?r@r�0s"


zFirewall.apply_default_rulescCs|jr|jj�rdSdS)NTF)r+r9Zhas_runtime_configuration)r>r?r?r@�may_skip_flush_direct_backendsHsz'Firewall.may_skip_flush_direct_backendscCs`|dkrt|�}n|}x2|j�D]&}||j�kr2q |j�}|j||�q W|dkr\|jd�dS)NT)rr�r��build_flush_rulesr�r�)r>rlr�r�r�r?r?r@�flush_direct_backendsNs
zFirewall.flush_direct_backendscCsp|dkrt|�}n|}tjd�|j�s4|j|d�x$|j�D]}|j�}|j||�q>W|dkrl|jd�dS)NzFlushing rule set)rlT)	rrrar�r�r�r�r�r�)r>rlr�r�r�r?r?r@r�]s

zFirewall.flushcCs`|dkrt|�}n|}tjd|�x&|j�D]}|j|�}|j||�q,W|dkr\|jd�dS)NzSetting policy to '%s'T)rrrar�Zbuild_set_policy_rulesr�r�)r>r<rlr�r�r�r?r?r@r�os

zFirewall.set_policycCsB|sdS|j|�}|s&ttjd|��|j|�s4dS|j||j�S)NrNz'%s' is not a valid backend)r�r"r!r�r��set_rulerL)r>�backend_name�ruler�r?r?r@r��s


z
Firewall.rulecCs"ttd|��}|j|�}|s,ttjd|��|j|�s:dS|js\|js\|dkoX|j	j
�rx�t|�D]�\}}y|j||j
�Wqftk
�r}zjtjtj��tj|�xFt|d|��D]2}y|j|j|�|j
�Wq�tk
r�Yq�Xq�W|�WYdd}~XqfXqfWn|j||j
�dS)Nz'%s' is not a valid backendr)�listrSr�r"r!r�r�rKr_r2r`r�r�rLrnrra�	traceback�
format_excrt�reversedZreverse_ruleZ	set_rules)r>r�r�Z_rulesr�r�r�r�r?r?r@r��s.




zFirewall.rulescCs|jrttj��dS)N)rDr"r!Z
PANIC_MODE)r>r?r?r@�check_panic�szFirewall.check_paniccCs"|}||jj�krttj|��|S)N)r<r�r"r!ZINVALID_POLICY)r>r<Z_policyr?r?r@�check_policy�szFirewall.check_policycCs8|}|s|dkr|j�}||jj�kr4ttj|��|S)NrN)�get_default_zoner8rzr"r!ZINVALID_ZONE)r>r8�_zoner?r?r@r~�szFirewall.check_zonecCstj|�sttj|��dS)N)rZcheckInterfacer"r!ZINVALID_INTERFACE)r>�	interfacer?r?r@�check_interface�s
zFirewall.check_interfacecCs|jj|�dS)N)r7�
check_service)r>r7r?r?r@r��szFirewall.check_servicecCstj|�sttj|��dS)N)r�
check_portr"r!ZINVALID_PORT)r>Zportr?r?r@r��s
zFirewall.check_portcCs*|sttj��|dkr&ttjd|��dS)N�tcp�udp�sctp�dccpz''%s' not in {'tcp'|'udp'|'sctp'|'dccp'})r�r�r�r�)r"r!ZMISSING_PROTOCOLZINVALID_PROTOCOL)r>Zprotocolr?r?r@�check_tcpudp�s
zFirewall.check_tcpudpcCstj|�sttj|��dS)N)rZcheckIPr"r!�INVALID_ADDR)r>Zipr?r?r@�check_ip�s
zFirewall.check_ipcCsP|dkr tj|�sLttj|��n,|dkr@tj|�sLttj|��nttjd��dS)Nr[r\z'%s' not in {'ipv4'|'ipv6'})rZcheckIPnMaskr"r!r�Z
checkIP6nMaskr�)r>r��sourcer?r?r@�
check_address�s

zFirewall.check_addresscCs|jj|�dS)N)r6�check_icmptype)r>Zicmpr?r?r@r��szFirewall.check_icmptypecCs>t|t�std|t|�f��t|�dkr:ttjd|��dS)Nz%s is %s, expected intrz#timeout '%d' is not positive number)�
isinstance�int�	TypeError�typer"r!�
INVALID_VALUE)r>Ztimeoutr?r?r@�
check_timeout�s

zFirewall.check_timeoutc Cs`|j}|j}|sNi}x&|jj�D]}|jj|�d||<q W|jj�}|j�}g}x$|jj	�D]}	|j
|jj|	��q^W|s�|jd�|j
�|j�d}
y|jd|d�Wn&tk
r�}z
|}
WYdd}~XnX|�r(xL|D]D}|jj|j�s�x0|jj�D]"}
|
jdk�r�q�|
j|j��q�Wq�W|�s�|j�}||k�r�||k�rRi||<xFt||j��D]2\}}|d�rd||||||<|||=�qdWxb|jj�D]T}||k�r�x.||D]"}|jj|||||d��q�W||=ntjd|��q�Wt|�d	k�r6x(t|j��D]}tjd
|�||=�qW~x�|D]�}|jj|j��r�xx|jD]R}y|jj|j|�Wn6tk
�r�}z|jt j!k�r�|�WYdd}~XnX�qZWn|jj"|�|jj#|j��q>W|jj$|�t%�}|�r,x@|jj�dgD],}x$t&|�D]}|jj|||d��q
W�q�W||_|j�sD|jd
�|
�rVd|_'|
�nd|_'dS)N�
interfacesZDROPT)r�r�r�__default__�senderzNew zone '%s'.rz(Lost zone '%s', zone interfaces dropped.rN)r�r�r�r�)(rDrPr8rz�get_settingsr9Zget_runtime_configr�rr�r�r�r�r�r�r�rnZquery_ipsetr�r�Zset_destroyr��items�change_zone_of_interfacerrVrw�keysZentriesZ	add_entryr"r�r!�ALREADY_ENABLEDr�Zapply_ipsetZ
set_configrrrC)r>r�rDZ	flush_allZ_zone_interfacesr8Z_direct_config�_old_dzZ_ipset_objs�_nameZstart_exceptionr�r�r�Z_new_dz�iface�settingsZinterface_id�entryr�Znm_bus_namer�r?r?r@r��s�









zFirewall.reloadcCs|jS)N)rC)r>r?r?r@�	get_stateaszFirewall.get_statecCsZ|jrttjd��y|jd�Wn.tk
rN}zttj|��WYdd}~XnXd|_dS)Nzpanic mode already enabledZPANICT)rDr"r!r�r�rn�COMMAND_FAILED)r>r�r?r?r@�enable_panic_modefszFirewall.enable_panic_modecCsZ|jsttjd��y|jd�Wn.tk
rN}zttj|��WYdd}~XnXd|_dS)Nzpanic mode is not enabledr�F)rDr"r!ZNOT_ENABLEDr�rnr�)r>r�r?r?r@�disable_panic_modeqszFirewall.disable_panic_modecCs|jS)N)rD)r>r?r?r@�query_panic_mode|szFirewall.query_panic_modecCs|jS)N)rL)r>r?r?r@�get_log_denied�szFirewall.get_log_deniedcCsb|tjkr&ttjd|djtj�f��||j�krR||_|jj	d|�|jj
�nttj|��dS)Nz'%s', choose from '%s'z','rh)rZLOG_DENIED_VALUESr"r!r��joinr�rLr$�set�writeZALREADY_SET)r>r�r?r?r@�set_log_denied�s
zFirewall.set_log_deniedcCs|jS)N)rE)r>r?r?r@r��szFirewall.get_default_zonecCs�|j|�}||jkr�|j}||_|jjd|�|jj�|jj||�|jj|�}x@t|dj	��D]\}}|drd|jj
d|�qdWnttj
|��dS)Nrcr�r�rN)r~rEr$r�r�r8r�r�r�r�r�r"r!ZZONE_ALREADY_SET)r>r8r�r�Z_old_dz_settingsr�r�r?r?r@�set_default_zone�s


zFirewall.set_default_zonecCsH|j�}x:|j�D].\}}|s(t|t�r2|||<q||kr||=qW|S)N)rqr�r��bool)r>Z	permanentZruntimer��keyr�r?r?r@�'combine_runtime_with_permanent_settings�s

z0Firewall.combine_runtime_with_permanent_settingscCsi}i}x�t|j��t|j��BD]�}||kr"t||t�r�t||krN||ng�}tt||�|�||<t|t||�A|@�||<q"t||t�s�t||t�r�||r�||r�d||<q�||r�||r�d||<q"ttjdj	t
||�|���q"W||fS)NTFz Unhandled setting type {} key {})r�r�r�r�r�r�r"r!ZINVALID_SETTING�formatr�)r>Zold_settingsZnew_settingsZadd_settingsZremove_settingsr��oldr?r?r@�get_added_and_removed_settings�s

 z'Firewall.get_added_and_removed_settings)F)FF)F)N)N)N)N)N)F)4�__name__�
__module__�__qualname__rArMr=rZrbr�r�rvr�r�r�rsr�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r~r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r?r?r?r@rBsh
(	;
 








 	
s)A�__all__Zos.pathr{rXrqrr�ZfirewallrrZ
firewall.corerrrrr	Zfirewall.core.fw_icmptyper
Zfirewall.core.fw_servicerZfirewall.core.fw_zonerZfirewall.core.fw_directr
Zfirewall.core.fw_configrZfirewall.core.fw_policiesrZfirewall.core.fw_ipsetrZfirewall.core.fw_transactionrZfirewall.core.fw_helperrZfirewall.core.fw_policyrZfirewall.core.fw_nmrrZfirewall.core.loggerrZfirewall.core.io.firewalld_confrZfirewall.core.io.directrZfirewall.core.io.servicerZfirewall.core.io.icmptyperZfirewall.core.io.zonerrZfirewall.core.io.ipsetrZfirewall.core.ipsetrZfirewall.core.io.helperrZfirewall.core.io.policyr r!Zfirewall.errorsr"�objectrr?r?r?r@�<module>sH__pycache__/logger.cpython-36.opt-1.pyc000064400000055135151731527010013633 0ustar003

��g>y�@s�ddddgZddlZddlZddlZddlZddlZddlZddlZddlZddl	Z
ddl
Z
Gdd�de�ZGdd�de�Z
Gd	d
�d
e
�ZGdd�de�ZGd
d�de�ZGdd�de�Ze�ZdS)�	LogTarget�FileLog�Logger�log�Nc@s2eZdZdZdd�Zddd�Zdd�Zd	d
�ZdS)
rz% Abstract class for logging targets. cCs
d|_dS)N)�fd)�self�r�/usr/lib/python3.6/logger.py�__init__(szLogTarget.__init__rcCstd��dS)Nz%LogTarget.write is an abstract method)�NotImplementedError)r�data�level�logger�is_debugrrr	�write+szLogTarget.writecCstd��dS)Nz%LogTarget.flush is an abstract method)r)rrrr	�flush.szLogTarget.flushcCstd��dS)Nz%LogTarget.close is an abstract method)r)rrrr	�close1szLogTarget.closeN)r)�__name__�
__module__�__qualname__�__doc__r
rrrrrrr	r&s

c@s.eZdZdd�Zddd�Zdd�Zdd	�Zd
S)�
_StdoutLogcCstj|�tj|_dS)N)rr
�sys�stdoutr)rrrr	r
8s
z_StdoutLog.__init__rcCs|jj|�|j�dS)N)rrr)rrr
rrrrr	r<sz_StdoutLog.writecCs|j�dS)N)r)rrrr	rAsz_StdoutLog.closecCs|jj�dS)N)rr)rrrr	rDsz_StdoutLog.flushN)r)rrrr
rrrrrrr	r7s
rc@seZdZdd�ZdS)�
_StderrLogcCstj|�tj|_dS)N)rr
r�stderrr)rrrr	r
Ks
z_StderrLog.__init__N)rrrr
rrrr	rJsrc@s.eZdZdd�Zddd�Zdd�Zdd	�Zd
S)�
_SyslogLogcCs.tj|�tjtjjtjd�tj	tj
�dS)Nr)rr
�syslogZopenlog�os�path�basenamer�argvZLOG_PIDZ
LOG_DAEMON)rrrr	r
Ss
	z_SyslogLog.__init__rcCs�d}|rtj}nF||jkr"tj}n4||jkr4tj}n"||jkrFtj}n||jkrVtj	}|j
d�rt|dt|�d�}t|�dkr�|dkr�tj|�ntj||�dS)N�
�r)rZ	LOG_DEBUG�INFO1ZLOG_INFO�WARNINGZLOG_WARNING�ERRORZLOG_ERR�FATALZLOG_CRIT�endswith�len)rrr
rrZpriorityrrr	ras"




z_SyslogLog.writecCstj�dS)N)rZcloselog)rrrr	rwsz_SyslogLog.closecCsdS)Nr)rrrr	rzsz_SyslogLog.flushN)r)rrrr
rrrrrrr	rRs
rc@s<eZdZdZddd�Zdd�Zddd	�Zd
d�Zdd
�ZdS)rz< FileLog class.
    File will be opened on the first write. �wcCstj|�||_||_dS)N)rr
�filename�mode)rr+r,rrr	r
�s
zFileLog.__init__cCsv|jr
dStjtjB}|jjd�r,|tjO}tj|j|d�|_tj	|jd�tj
|j|j�|_tj|jtjtj
�dS)N�ai�)rr�O_CREAT�O_WRONLYr,�
startswith�O_APPEND�openr+�fchmod�fdopen�fcntlZF_SETFDZ
FD_CLOEXEC)r�flagsrrr	r2�s
zFileLog.openrcCs(|js|j�|jj|�|jj�dS)N)rr2rr)rrr
rrrrr	r�sz
FileLog.writecCs|js
dS|jj�d|_dS)N)rr)rrrr	r�s
z
FileLog.closecCs|js
dS|jj�dS)N)rr)rrrr	r�sz
FileLog.flushN)r*)r)	rrrrr
r2rrrrrrr	rs

c@s�eZdZdZd[Zd\Zd]Zd^Zd_ZdZ	e
�Ze�Z
e�Zd`d	d
�Zdd�Zdadd�Zdbdd�Zdcdd�Zdddd�Zdd�Zdd�Zdd�Zdd�Zdd�Zd d!�Zed"fd#d$�Zed"fd%d&�Zed"fd'd(�Zed"fd)d*�Zed"fd+d,�Z ed"fd-d.�Z!d/d0�Z"d1d2�Z#d3d4�Z$d5d6�Z%d7d8�Z&d9d:�Z'd;d<�Z(d=d>�Z)d?d@�Z*dAdB�Z+dCdD�Z,dedEdF�Z-dGdH�Z.dfdIdJ�Z/ed"dfdKdL�Z0ed"dfdMdN�Z1ed"dfdOdP�Z2dgdQdR�Z3dSdT�Z4dUdV�Z5dWdX�Z6dhdYdZ�Z7d"S)iraL	
    Format string:

    %(class)s      Calling class the function belongs to, else empty
    %(date)s       Date using Logger.date_format, see time module
    %(domain)s     Full Domain: %(module)s.%(class)s.%(function)s
    %(file)s       Filename of the module
    %(function)s   Function name, empty in __main__
    %(label)s      Label according to log function call from Logger.label
    %(level)d      Internal logging level
    %(line)d       Line number in module
    %(module)s     Module name
    %(message)s    Log message

    Standard levels:

    FATAL                 Fatal error messages
    ERROR                 Error messages
    WARNING               Warning messages
    INFOx, x in [1..5]    Information
    DEBUGy, y in [1..10]  Debug messages
    NO_INFO               No info output
    NO_DEBUG              No debug output
    INFO_MAX              Maximum info level
    DEBUG_MAX             Maximum debug level

    x and y depend on info_max and debug_max from Logger class
    initialization. See __init__ function.

    Default logging targets:

    stdout        Logs to stdout
    stderr        Logs to stderr
    syslog        Logs to syslog

    Additional arguments for logging functions (fatal, error, warning, info
    and debug):

    nl       Disable newline at the end with nl=0, default is nl=1.
    fmt      Format string for this logging entry, overloads global format
             string. Example: fmt="%(file)s:%(line)d %(message)s"
    nofmt    Only output message with nofmt=1. The nofmt argument wins over
             the fmt argument.

    Example:

    from logger import log
    log.setInfoLogLevel(log.INFO1)
    log.setDebugLogLevel(log.DEBUG1)
    for i in range(1, log.INFO_MAX+1):
        log.setInfoLogLabel(i, "INFO%d: " % i)
    log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: "
                  "%(level)d %(message)s")
    log.setDateFormat("%Y-%m-%d %H:%M:%S")

    fl = FileLog("/tmp/log", "a")
    log.addInfoLogging("*", fl)
    log.addDebugLogging("*", fl)
    log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s")

    log.debug3("debug3")
    log.debug2("debug2")
    log.debug1("debug1")
    log.info2("info2")
    log.info1("info1")
    log.warning("warning\n", nl=0)
    log.error("error\n", nl=0)
    log.fatal("fatal")
    log.info(log.INFO1, "nofmt info", nofmt=1)

    ����r#r�
cCs�i|_i|_d|_d|_i|_i|_i|_i|_i|_i|_	|dkrPt
d|��|dkrdt
d|��|j|_||_
d|_||_|j|jd�|j|jd�|j|jd�|j|jd�xNtd|j
d�D]:}t|d	||�|j|d�t|d
|dd�||��q�WxTtd|jd�D]@}t|d
||�|j|d|�t|d|dd�||���qW|j|j�|j|j�|jd�|jd�|jd|j|j|j|jg�|jd|jdd�t|j|j
d�D��|jd|jdd�td|jd�D��dS)z Logger class initialization �r#zLogger: info_max %d is too lowrzLogger: debug_max %d is too lowz
FATAL ERROR: zERROR: z	WARNING: zINFO%dzinfo%dcs��fdd�S)Ncs�j�|f|�|�S)N)�info)�message�args�kwargs)r�xrr	�<lambda> sz3Logger.__init__.<locals>.<lambda>.<locals>.<lambda>r)rrAr)rrAr	rBsz!Logger.__init__.<locals>.<lambda>zDEBUG%dz	DEBUG%d: zdebug%dcs��fdd�S)Ncs�j�|f|�|�S)N)�debug)r>r?r@)rrArr	rB)sz3Logger.__init__.<locals>.<lambda>.<locals>.<lambda>r)rrAr)rrAr	rB(sz%(label)s%(message)sz%d %b %Y %H:%M:%S�*cSsg|]}|�qSrr)�.0�irrr	�
<listcomp>4sz#Logger.__init__.<locals>.<listcomp>cSsg|]}|�qSrr)rErFrrr	rG6sN) �_level�_debug_level�_format�_date_format�_label�_debug_label�_logging�_debug_logging�_domains�_debug_domains�
ValueErrorr%�NO_INFO�INFO_MAX�NO_DEBUG�	DEBUG_MAX�setInfoLogLabelr'�	TRACEBACKr&�range�setattr�setDebugLogLabel�setInfoLogLevelr$�setDebugLogLevel�	setFormat�
setDateFormat�setInfoLoggingrr�setDebugLogging)rZinfo_maxZ	debug_maxrHrrr	r
�sX






zLogger.__init__cCsNxHt|j|jd�D]2}||jkr$qx |j|D]\}}}|j�q0WqWdS)z Close all logging targets r#N)rYr'rVrNr)rr
�dummy�targetrrr	r8s

zLogger.closerDcCs$|j|�||jkr|j|S|jS)z Get info log level. )�_checkDomainrH�NOTHING)r�domainrrr	�getInfoLogLevel@s


zLogger.getInfoLogLevelcCs8|j|�||jkr|j}||jkr*|j}||j|<dS)z% Set log level [NOTHING .. INFO_MAX] N)rdrerTrH)rr
rfrrr	r\Gs


zLogger.setInfoLogLevelcCs*|j|�||jkr$|j||jS|jS)z Get debug log level. )rdrIrU)rrfrrr	�getDebugLogLevelPs

zLogger.getDebugLogLevelcCs:|j|�|dkrd}||jkr&|j}||j|j|<dS)z- Set debug log level [NO_DEBUG .. DEBUG_MAX] rN)rdrVrUrI)rr
rfrrr	r]Ws

zLogger.setDebugLogLevelcCs|jS)N)rJ)rrrr	�	getFormat`szLogger.getFormatcCs
||_dS)N)rJ)rrJrrr	r^cszLogger.setFormatcCs|jS)N)rK)rrrr	�
getDateFormatfszLogger.getDateFormatcCs
||_dS)N)rK)rrJrrr	r_iszLogger.setDateFormatcCs:|j|�}x*|D]"}|j||j|jd�||j|<qWdS)zU Set log label for level. Level can be a single level or an array
        of levels. )�	min_level�	max_levelN)�
_getLevels�_checkLogLevelr'rTrL)rr
�label�levelsrrr	rWls




zLogger.setInfoLogLabelcCs>|j|dd�}x*|D]"}|j||j|jd�||j|<qWdS)zU Set log label for level. Level can be a single level or an array
        of levels. r#)r)rkrlN)rmrnr$rVrM)rr
rorprrr	r[us



zLogger.setDebugLogLabelNcCs|j||||dd�dS)z� Set info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r)rN)�_setLogging)rrfrcr
�fmtrrr	r`~szLogger.setInfoLoggingcCs|j||||dd�dS)z� Set debug log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r#)rN)rq)rrfrcr
rrrrr	ra�szLogger.setDebugLoggingcCs|j||||dd�dS)z� Add info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r)rN)�_addLogging)rrfrcr
rrrrr	�addInfoLogging�szLogger.addInfoLoggingcCs|j||||dd�dS)z� Add debg log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r#)rN)rs)rrfrcr
rrrrr	�addDebugLogging�szLogger.addDebugLoggingcCs|j||||dd�dS)z� Delete info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r)rN)�_delLogging)rrfrcr
rrrrr	�delInfoLogging�szLogger.delInfoLoggingcCs|j||||dd�dS)z� Delete debug log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r#)rN)rv)rrfrcr
rrrrr	�delDebugLogging�szLogger.delDebugLoggingcCs|j|dd�S)zN Is there currently any info logging for this log level (and
        domain)? r)r)�_isLoggingHere)rr
rrr	�isInfoLoggingHere�szLogger.isInfoLoggingHerecCs|j|dd�S)zO Is there currently any debug logging for this log level (and
        domain)? r#)r)ry)rr
rrr	�isDebugLoggingHere�szLogger.isDebugLoggingHerecOs,|j|�d|d<|j|j|f|�|�dS)z Fatal error log. rrN)�_checkKWargs�_logr')rrJr?r@rrr	�fatal�s
zLogger.fatalcOs,|j|�d|d<|j|j|f|�|�dS)z Error log. rrN)r|r}r&)rrJr?r@rrr	�error�s
zLogger.errorcOs,|j|�d|d<|j|j|f|�|�dS)z Warning log. rrN)r|r}r%)rrJr?r@rrr	�warning�s
zLogger.warningcOsB|j|d|jd�|j|�d|d<|j||j|f|�|�dS)z� Information log using info level [1..info_max].
        There are additional infox functions according to info_max from
        __init__r#)rkrlrrN)rnrTr|r}rS)rr
rJr?r@rrr	r=�s
zLogger.infocOs<|j|d|jd�|j|�d|d<|j||f|�|�dS)z� Debug log using debug level [1..debug_max].
        There are additional debugx functions according to debug_max
        from __init__r#)rkrlrN)rnrVr|r})rr
rJr?r@rrr	rC�s
zLogger.debugcCs|j|jtj�gid�dS)N)r?r@)r}rX�	traceback�
format_exc)rrrr	�	exception�szLogger.exceptioncCs&||ks||kr"td|||f��dS)Nz*Level %d out of range, should be [%d..%d].)rR)rr
rkrlrrr	rn�szLogger._checkLogLevelcCs2|sdSx$|j�D]}|dkrtd|��qWdS)N�nlrr�nofmtz0Key '%s' is not allowed as argument for logging.)r�rrr�)�keysrR)rr@�keyrrr	r|�s
zLogger._checkKWargscCs|s|dkrtd|��dS)Nr<zDomain '%s' is not valid.)rR)rrfrrr	rd�szLogger._checkDomaincCs�||jkrft|t�st|t�r$|}n|g}xp|D]0}|rL|j|d|jd�q0|j||j|jd�q0Wn6|r�dd�t|j	|j�D�}ndd�t|j|j�D�}|S)z Generate log level array. r#)rkrlcSsg|]}|�qSrr)rErFrrr	rG�sz%Logger._getLevels.<locals>.<listcomp>cSsg|]}|�qSrr)rErFrrr	rG�s)
�ALL�
isinstance�list�tuplernrVr'rTrYZDEBUG1)rr
rrprrr	rm�s


zLogger._getLevelscCsNt|t�st|t�r|}n|g}x(|D] }t|jt�s&td|jj��q&W|S)z Generate target array. z '%s' is no valid logging target.)r�r�r��
issubclass�	__class__rrRr)rrc�targetsZ_targetrrr	�_getTargets�s
zLogger._getTargetscCs�|r |j}|j}d|jdf}n|j}|j}|j|jdf}t|�dkrP|j�xVt	|d|d�D]@}||krrqdx0||D]$\}}}||kr||j
|g�j|�q|WqdWdS)z% Generate dict with domain by level. r#rN)rQrOrVrPrNr'rTr)�clearrY�
setdefault�append)rrrPrNZ_ranger
rfrbrrr	�_genDomainsszLogger._genDomainsc	Csl|j|�|j||�}|j|�}|r,|j}n|j}x*|D]"}x|D]}|||fg||<qBWq8W|j|�dS)N)rdrmr�rOrNr�)	rrfrcr
rrrrpr�rNrrr	rqs



zLogger._setLoggingc	Cst|j|�|j||�}|j|�}|r,|j}n|j}x2|D]*}x$|D]}|j|g�j|||f�qBWq8W|j|�dS)N)rdrmr�rOrNr�r�r�)	rrfrcr
rrrrpr�rNrrr	rs-s



 zLogger._addLoggingc
Cs�|j|�|j||�}|j|�}|r,|j}n|j}x�|D]|}	xv|D]n}|	|krPqB|||f||	kr�||	j|||f�t||	�dkr�||	=qB||jkrBtd|	||j	j
|f��qBWq8W|j|�dS)NrzDNo mathing logging for level %d, domain %s, target %s and format %s.)rdrmr�rOrN�remover)r�rRr�rr�)
rrfrcr
rrrrpr�rNrHrrr	rv<s&




zLogger._delLoggingcCst|j||�}|sdS|dd}|r,|j}n|j}x<||D]0\}}}|dksh|j|�shtj|d|�r<dSq<WdS)NFrf�.rDT)�_genDictrOrNr0�fnmatch�fnmatchcase)rr
r�_dict�point_domainrNrfrbrrr	ryUs
zLogger._isLoggingHerec	Cs�|jjdkrD|jjd}||jkrD|j|}|j|j|j�}|rD|Stj|j�}|j}|j|j	kr�t
|j	|jd�r�|j	|jj|kr�dSxT|j	j�D]F\}}t
|tj�r�t
||j�r�t||j�}t
|tj�r�|j|kr�|Sq�WdS)z7 Function to get calling class. Returns class or None. rZ	func_codeN)�f_code�co_argcount�co_varnames�f_locals�
_getClass2r��inspectZ	getmodule�co_name�__dict__�hasattr�__code__�itemsr��typesZ	ClassType�getattr�FunctionType)	r�frameZselfname�_self�obj�module�coderb�valuerrr	�	_getClassis*


zLogger._getClasscCsVx,|jj�D]}t|tj�r|j|kr|SqWx"|jD]}|j||�}|r6|Sq6WdS)z@ Internal function to get calling class. Returns class or None. N)r��valuesr�r�r�r��	__bases__r�)rr�r�r��baseZ_objrrr	r��s
zLogger._getClass2cOsld}d|kr|d}d}d|kr(|d}d}d|kr<|d}|j||�}|sPdSt|�dkrj|||d<n&t|�dkr�||d|d<n||d<|dd}	|r�|j}
n|j}
g}x�|
|D]�\}}
}|
|kr�q�|d	ks�|	j|d�s�tj|d|�r�|�s|j}d
|k�r|d
}|�r0|
j|d|||�n|
j|||||�|�rZ|
jd|||�|j	|
�q�WdS)Nrrr#r�r�r>rfr�rDrrr")
r�r)rOrNr0r�r�rJrr�)rr
rJr?r@rr�r�r�r�rNZused_targetsrfrcrrr	r}�sL
zLogger._logcCsg}d}|r |j}|j}|j}n|j}|j}|j}xN|D]F}|dkrh|||kr~d}t|�dkrdg}Pq8|||kr8|j|�q8W|r�t|�dkr�dS||kr�dStj	�}	x$|	r�|	j
r�|	jd|jkr�|	j
}	q�W|	s�t
d��|	jd}
|
d	}x|D]}|j|�r�g}Pq�W|	j}t|
�}
xx||D]l}|jd�}|dk�rD�q&n|dk�r\|d|�}n|}|
t|�k�r�|
j|��s�dSn|j|
��s&dS�q&Wd
}||k�r�||}|j|	j|
d
|jd
||tj|jtj��d�	}|dd
k�r�d
|d<d}x&||D]}|dk�r�q�d}P�q�W|jjd�dk�sR|jjd�dk�sR|�sRt|�dk�rl|j|	�}|�rl|j|d<d
|d|d<|dd
k�r�|dd	|d7<|dd
k�r�|dd	|d7<t|�dk�r�|S|dd	}x0|D](}|j|��stj|d|��r�|S�q�WdS)z Internal function. FrDTrr#Nrz Frame information not available.r�r<)	�file�liner��class�functionrfror
Zdater��?z	%(domain)z%(class)r�r�rf)rIrQrMrHrPrLr)r�r�Zcurrentframe�f_back�	f_globalsrrRr0r��find�co_filename�f_linenor��timeZstrftimerKZ	localtimerJr�rr�r�)rr
rZ
check_domainsZsimple_matchr�rPrLrf�fZmodule_nameZpoint_module�co�_lenrF�dZ	level_strZ
domain_neededr�r�rrr	r��s�














zLogger._genDict���������������)r7r;)rD)rD)rD)rD)r)r)r)r)8rrrrr�rer'rXr&r%rrrrrrr
rrgr\rhr]rir^rjr_rWr[r`rartrurwrxrzr{r~rr�r=rCr�rnr|rdrmr�r�rqrsrvryr�r�r}r�rrrr	r�sdG
;

	

					


 4)�__all__rr�r�r�r�rr�r5Zos.pathr�objectrrrrrrrrrrr	�<module>s.-(*4__pycache__/ipset.cpython-36.pyc000064400000021161151731527010012531 0ustar003

��gq2�@s�dZdddgZddlZddlZddlmZddlmZddl	m
Z
dd	lmZdd
l
mZmZddlmZdZd
ddddddddddgZddddd�Zdddd�ZGd d�de�Zd!d�Zd"d�Zd#d$�Zd%d&�Zd'd(�ZdS))zThe ipset command wrapper�ipset�check_ipset_name�remove_default_create_options�N)�errors)�
FirewallError)�runProg)�log)�tempFile�readfile)�COMMANDS� zhash:ipzhash:ip,portzhash:ip,port,ipzhash:ip,port,netzhash:ip,markzhash:netzhash:net,netz
hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz
inet|inet6�valuez
value in secs)�family�hashsize�maxelem�timeoutZinetZ1024Z65536)rrrc@s�eZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zd'd
d�Z	dd�Z
dd�Zdd�Zd(dd�Z
d)dd�Zdd�Zd*dd�Zd+dd�Zdd �Zd!d"�Zd#d$�Zd%d&�ZdS),rzipset command wrapper classcCstd|_d|_dS)Nr)r�_command�name)�self�r�/usr/lib/python3.6/ipset.py�__init__Ks
zipset.__init__cCs^dd�|D�}tjd|j|jdj|��t|j|�\}}|dkrZtd|jdj|�|f��|S)zCall ipset with argscSsg|]}d|�qS)z%sr)�.0�itemrrr�
<listcomp>Rszipset.__run.<locals>.<listcomp>z	%s: %s %s� rz'%s %s' failed: %s)r�debug2�	__class__r�joinr�
ValueError)r�argsZ_args�status�retrrrZ__runOszipset.__runcCs t|�tkrttjd|��dS)zCheck ipset namezipset name '%s' is not validN)�len�IPSET_MAXNAMELENrrZINVALID_NAME)rrrrr�
check_nameZszipset.check_namecCs�g}d}y|jdg�}Wn0tk
rH}ztjd|�WYdd}~XnX|j�}d}xT|D]L}|r�|j�jdd�}|d|kr�|dtkr�|j|d�|j	d�r\d	}q\W|S)
z?Return types that are supported by the ipset command and kernel�z--helpzipset error: %sNF�rzSupported set types:T)
�_ipset__runrrZdebug1�
splitlines�strip�split�IPSET_TYPES�append�
startswith)rr"�outputZex�linesZin_types�line�splitsrrr�set_supported_types`s  

zipset.set_supported_typescCs(t|�tks|tkr$ttjd|��dS)zCheck ipset typez!ipset type name '%s' is not validN)r#r$r,rrZINVALID_TYPE)r�	type_namerrr�
check_typeuszipset.check_typeNcCsd|j|�|j|�d||g}t|t�rZx0|j�D]$\}}|j|�|dkr2|j|�q2W|j|�S)z+Create an ipset with name, type and options�creater&)r%r5�
isinstance�dict�itemsr-r()r�set_namer4�optionsr �key�valrrr�
set_create{s




zipset.set_createcCs|j|�|jd|g�S)NZdestroy)r%r()rr:rrr�set_destroy�s
zipset.set_destroycCsd||g}|j|�S)N�add)r()rr:�entryr rrr�set_add�s
z
ipset.set_addcCsd||g}|j|�S)N�del)r()rr:rAr rrr�
set_delete�s
zipset.set_deletecCs,d||g}|r"|jddj|��|j|�S)N�testz%sr)r-rr()rr:rAr;r rrrrE�s
z
ipset.testcCs2dg}|r|j|�|r"|j|�|j|�jd�S)N�list�
)r-�extendr(r+)rr:r;r rrr�set_list�s

zipset.set_listcCs<|jdgd�}i}d}}i}�x|D�]}t|�dkr:q&dd�|jdd�D�}t|�dkr`q&q&|d	d
krv|d}q&|d	dkr�|d}q&|d	dkr&|dj�}d	}	x^|	t|�k�r||	}
|
dk�r�t|�|	kr�|	d7}	||	||
<ntjd|�iS|	d7}	q�W|�r$|�r$|t|�f||<d}}|j�q&W|S)z" Get active ipsets (only headers) z-terse)r;N�cSsg|]}|j��qSr)r*)r�xrrrr�sz.ipset.set_get_active_terse.<locals>.<listcomp>�:r'r�NameZTypeZHeaderrrrr�netmaskz&Malformed ipset list -terse output: %s)rrrrrN)rIr#r+r�errorr�clear)rr0r"�_nameZ_type�_optionsr1Zpairr2�i�optrrr�set_get_active_terse�sD

zipset.set_get_active_tersecCsdg}|r|j|�|j|�S)N�save)r-r()rr:r rrrrV�s
z
ipset.savecCs�|j|�|j|�t�}d|kr*d|}d||dg}|rlx0|j�D]$\}}	|j|�|	dkrD|j|	�qDW|jddj|��|jd|�xN|D]F}
d|
kr�d|
}
|r�|jd||
dj|�f�q�|jd	||
f�q�W|j�tj	|j
�}tjd
|j
|jd|j
|jf�dg}t|j||j
d
�\}}
tj�dk�r�yt|j
�Wntk
�r`YnVXd}xNt|j
�D]@}tjd||fddd�|jd��s�tjddd�|d7}�qrWtj|j
�|dk�r�td|jdj|�|
f��|
S)Nrz'%s'r6z-existr&z%s
z	flush %s
z
add %s %s %s
z
add %s %s
z%s: %s restore %sz%s: %dZrestore)�stdinr'rJz%8d: %sr)�nofmt�nlrG)rXz'%s %s' failed: %s)r%r5r	r9r-�writer�close�os�statrrrrr�st_sizerZgetDebugLogLevelr
�	ExceptionZdebug3�endswith�unlinkr)rr:r4�entriesZcreate_optionsZ
entry_optionsZ	temp_filer r<r=rAr]r!r"rSr1rrr�set_restore�sV




zipset.set_restorecCsdg}|r|j|�|j|�S)N�flush)r-r()rr:r rrr�	set_flushs
zipset.set_flushcCs|jd||g�S)N�rename)r()rZold_set_nameZnew_set_namerrrrf
szipset.renamecCs|jd||g�S)N�swap)r()rZ
set_name_1Z
set_name_2rrrrgsz
ipset.swapcCs|jdg�S)N�version)r()rrrrrhsz
ipset.version)N)N)NN)N)NN)�__name__�
__module__�__qualname__�__doc__rr(r%r3r5r>r?rBrDrErIrUrVrcrerfrgrhrrrrrHs&



'

7cCst|�tkrdSdS)z"Return true if ipset name is validFT)r#r$)rrrrrscCs8|j�}x*tD]"}||krt|||kr||=qW|S)z( Return only non default create options )�copy�IPSET_DEFAULT_CREATE_OPTIONS)r;rRrTrrrrs

c
Cshg}xX|jd�D]J}y&|jd�|jttj|dd���Wqtk
rX|j|�YqXqWdj|�S)z! Normalize IP addresses in entry �,�/F)�strict)r+�indexr-�str�	ipaddress�
ip_networkrr)rAZ_entryZ_partrrr�normalize_ipset_entry&s
rvcCsxt|jd��dkrdSytj|dd�}Wntk
r<dSXx4|D],}|jtj|dd��rDttjdj	||���qDWdS)z: Check if entry overlaps any entry in the list of entries rorJNF)rqz,Entry '{}' overlaps with existing entry '{}')
r#r+rtrur�overlapsrr�
INVALID_ENTRY�format)rArbZ
entry_networkZitrrrr�check_entry_overlaps_existing2s
rzcCs~ydd�|D�}Wntk
r&dSXt|�dkr8dS|j�|jd�}x.|D]&}|j|�rrttjdj||���|}qPWdS)z> Check if any entry overlaps any entry in the list of entries cSsg|]}tj|dd��qS)F)rq)rtru)rrKrrrrEsz1check_for_overlapping_entries.<locals>.<listcomp>NrzEntry '{}' overlaps entry '{}')	rr#�sort�poprwrrrxry)rbZprev_networkZcurrent_networkrrr�check_for_overlapping_entriesBs2


r})rl�__all__Zos.pathr\rtZfirewallrZfirewall.errorsrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsr	r
Zfirewall.configrr$r,ZIPSET_CREATE_OPTIONSrn�objectrrrrvrzr}rrrr�<module>sF
P	__pycache__/fw_policy.cpython-36.opt-1.pyc000064400000154111151731527020014342 0ustar003

��g=V�@s�ddlZddlZddlmZddlmZmZmZmZm	Z	m
Z
mZmZm
Z
mZddlmZmZmZmZmZmZmZmZmZmZmZddlmZddlmZddlm Z ddl!m"Z"dd	l#m$Z$Gd
d�de%�Z&dS)�N)�log)
�portStr�checkIPnMask�
checkIP6nMask�
checkProtocol�enable_ip_forwarding�check_single_address�portInPortRange�get_nf_conntrack_short_name�coalescePortRange�breakPortRange)�	Rich_Rule�Rich_Accept�Rich_Service�	Rich_Port�
Rich_Protocol�Rich_Masquerade�Rich_ForwardPort�Rich_SourcePort�Rich_IcmpBlock�
Rich_IcmpType�	Rich_Mark)�FirewallTransaction)�errors)�
FirewallError)�LastUpdatedOrderedDict)�SOURCE_IPSET_TYPESc@s�eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
�ddd�Zdd�Zdd�Zdd�Z�dd d!�Z�d
d"d#�Z�dd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Z�dd0d1�Zd2d3�Z�dd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Zd>d?�Z �dd@dA�Z!dBdC�Z"�ddDdE�Z#dFdG�Z$dHdI�Z%dJdK�Z&dLdM�Z'dNdO�Z(dPdQ�Z)dRdS�Z*�ddTdU�Z+dVdW�Z,�ddXdY�Z-dZd[�Z.d\d]�Z/d^d_�Z0d`da�Z1dbdc�Z2�dddde�Z3dfdg�Z4�ddhdi�Z5djdk�Z6dldm�Z7dndo�Z8dpdq�Z9drds�Z:dtdu�Z;dvdw�Z<�ddxdy�Z=dzd{�Z>�dd|d}�Z?d~d�Z@d�d��ZAd�d��ZBd�d��ZCd�d��ZD�dd�d��ZEd�d��ZF�dd�d��ZGd�d��ZHd�d��ZId�d��ZJd�d��ZK�dd�d��ZLd�d��ZM�dd�d��ZNd�d��ZOd�d��ZPd�d��ZQd�d��ZR�dd�d��ZSd�d��ZT�dd�d��ZUd�d��ZVd�d��ZW�dd�d��ZX�d d�d��ZY�d!d�d��ZZd�d��Z[�d"d�d��Z\d�d��Z]�d#d�d��Z^d�d��Z_d�d��Z`d�d��Za�d$d�dÄZbd�dńZc�d%d�dDŽZdd�dɄZed�d˄Zfd�d̈́Zgd�dτZh�d&d�dфZid�dӄZjd�dՄZk�d'd�dׄZld�dلZmd�dۄZnd�d݄Zod�d߄Zpd�d�Zqd�d�Zrd�d�Zsd�d�Ztd�d�Zu�d(d�d�Zv�d)d�d�Zwd�d�Zxd�d�Zyd�d�Zzd�d��Z{�d*d�d��Z|d�d��Z}d�d��Z~d�d��Zd�d��Z��d�d�Z��d�d�Z��d�d�Z��d�d�Z��d+�d	�d
�Z�dS(,�FirewallPolicycCs||_i|_i|_dS)N)�_fw�_chains�	_policies)�self�fw�r#�/usr/lib/python3.6/fw_policy.py�__init__szFirewallPolicy.__init__cCsd|j|j|jfS)Nz
%s(%r, %r))�	__class__rr )r!r#r#r$�__repr__szFirewallPolicy.__repr__cCs|jj�|jj�dS)N)r�clearr )r!r#r#r$�cleanups
zFirewallPolicy.cleanupcCs
t|j�S)N)rr)r!r#r#r$�new_transaction$szFirewallPolicy.new_transactioncCst|jj��S)N)�sortedr �keys)r!r#r#r$�get_policies)szFirewallPolicy.get_policiescCs8g}x*|j�D]}|j|�}|js|j|�qWt|�S)N)r-�
get_policy�derived_from_zone�appendr+)r!Zpolicies�p�p_objr#r#r$�"get_policies_not_derived_from_zone,s
z1FirewallPolicy.get_policies_not_derived_from_zonecCs~g}xt|j�D]h}|j|�}t|d�t|jjj��tddg�B@rt|d�t|jjj��tddg�B@r|j|�qW|S)N�
ingress_zones�HOST�ANY�egress_zones)r3�get_settings�setr�zoneZget_active_zonesr0)r!Zactive_policies�policy�settingsr#r#r$�)get_active_policies_not_derived_from_zone4s
((z8FirewallPolicy.get_active_policies_not_derived_from_zonecCs|jj|�}|j|S)N)r�check_policyr )r!r;r1r#r#r$r.>szFirewallPolicy.get_policycCs,dd�dD�|_||j|j<|j|j�dS)NcSsi|]}t�|�qSr#)r)�.0�xr#r#r$�
<dictcomp>Csz-FirewallPolicy.add_policy.<locals>.<dictcomp>�services�ports�
masquerade�
forward_ports�source_ports�icmp_blocks�rules�	protocols�icmp_block_inversionr4r7)rBrCrDrErFrGrHrIrJr4r7)r<r �name�copy_permanent_to_runtime)r!�objr#r#r$�
add_policyBs
zFirewallPolicy.add_policycCs0|j|}|jr|j|�|jj�|j|=dS)N)r �applied�unapply_policy_settingsr<r()r!r;rMr#r#r$�
remove_policyNs



zFirewallPolicy.remove_policycCs�|j|}|jrdSx|jD]}|j||dd�qWx|jD]}|j||dd�q<Wx|jD]}|j||�q\Wx|jD]}|j	|f|��qxWx|j
D]}|j||�q�Wxf|jD]\}y|j
|f|��Wq�tk
�r}z$|jtjgkr�tj|�n|�WYdd}~Xq�Xq�Wx|jD]}|j||��qWxj|jD]`}y|j|f|��WnDtk
�r�}z&|jtjgk�r�tj|�n|�WYdd}~XnX�q:Wx|jD]}|j||��q�W|j�r�|j|�dS)NF)�allow_apply)r rOr4�add_ingress_zoner7�add_egress_zonerG�add_icmp_blockrE�add_forward_portrB�add_servicerC�add_portr�coder�ALREADY_ENABLEDr�warningrI�add_protocolrF�add_source_portrH�add_rulerD�add_masquerade)r!r;rM�args�errorr#r#r$rLUsB
z(FirewallPolicy.copy_permanent_to_runtimeNcCsNxH|j�D]<}|j|}|jr q
||j�kr
tjd|�|j||d�q
WdS)NzApplying policy '%s')�use_transaction)r-r r/r=rZdebug1�apply_policy_settings)r!rbr;r2r#r#r$�apply_policies|s
zFirewallPolicy.apply_policiescCs|j|}||_dS)N)r rO)r!r;rOrMr#r#r$�set_policy_applied�s
z!FirewallPolicy.set_policy_appliedcCstj�||d�}|S)N)Zdate�sender�timeout)�time)r!rgrf�retr#r#r$Z__gen_settings�szFirewallPolicy.__gen_settingscCs|j|�jS)N)r.r<)r!r;r#r#r$r8�szFirewallPolicy.get_settingscCsj|jj|�}|j|}|r |js.|r2|jr2dS|r<d|_|dkrN|j�}n|}|r�x8|jsh|j|�n|j|�D]\}}|j|d|||�qrW|j	|�}	|js�|j
|||��xV|	D�]L}
�xD|	|
D�]6}|
dkr�|j||||�q�|
dkr�q�q�|
dk�r|j|||f|��q�|
dk�r0|j
||||�q�|
dk�rV|j|||d|d|�q�|
d	k�rr|j||||�q�|
d
k�r�|j|||d|d|�q�|
dk�r�|j|||�q�|
dk�r�|j||t|d
�|�q�|
dk�r�q�q�|
dk�r�q�q�tjd||
|�q�Wq�W|�sRx<|j�s"|j|�n|j|�D]\}}|j|d|||��q,Wd|_|dk�rf|j|�dS)NTrGrJrErBrCr�rIrFrDrH)�rule_strr4r7z5Policy '%s': Unknown setting '%s:%s', unable to applyF)rr>r rOr*r/�%_get_table_chains_for_policy_dispatch�#_get_table_chains_for_zone_dispatch�gen_chain_rulesr8�_ingress_egress_zones�_icmp_block�
_forward_port�_service�_port�	_protocol�_source_port�_masquerade�_FirewallPolicy__ruler
rr[�execute)r!�enabler;rb�_policyrM�transaction�table�chainr<�keyr`r#r#r$�_policy_settings�sj













zFirewallPolicy._policy_settingscCs|jd||d�dS)NT)rb)r)r!r;rbr#r#r$rc�sz$FirewallPolicy.apply_policy_settingscCs|jd||d�dS)NF)rb)r)r!r;rbr#r#r$rP�sz&FirewallPolicy.unapply_policy_settingscCsr|j|�j�}|j|�|j|�|j|�|j|�|j|�|j|�|j|�|j	|�|j
|�|j|�d�
}|jj
||�S)zH
        :return: exported config updated with runtime settings
        )
rBrCrGrDrE�
rich_rulesrIrFr4r7)r.Zexport_config_dict�
list_services�
list_ports�list_icmp_blocks�query_masquerade�list_forward_ports�
list_rules�list_protocols�list_source_ports�list_ingress_zones�list_egress_zonesrZ'combine_runtime_with_permanent_settings)r!r;Z	permanentZruntimer#r#r$�get_config_with_settings_dict�sz,FirewallPolicy.get_config_with_settings_dictcs�ddlm�d
��fdd�	}��fdd�}�j�jf�j�jf�j�jf�j�j	f�j
�jf||f�j�j
f�j�jf�j�jf�j�jfd�
}�j|�}�jj||�\}}	xt|	D]l}
t|	|
t��rxV|	|
D]8}t|t�r�||
d|f|��q�||
d||�q�Wq�||
d|�q�Wx�|D]�}
t||
t��r�xn||
D]J}t|t��rv||
d|f|�d|d	��n||
d||d|d	��qFWn||
d|d|d	��q(WdS)Nr)r
cs�j|�|d�d|d�dS)N)rkr)rgrf)r^)r;rkrgrf)r
r!r#r$�add_rule_wrapper�szFFirewallPolicy.set_config_with_settings_dict.<locals>.add_rule_wrappercs�j|�|d��dS)N)rk)�remove_rule)r;rk)r
r!r#r$�remove_rule_wrapper�szIFirewallPolicy.set_config_with_settings_dict.<locals>.remove_rule_wrapper)
rBrCrGrDrEr�rIrFr4r7rj)rgrf)rN)�firewall.core.richr
rW�remove_servicerX�remove_portrU�remove_icmp_blockr_�remove_masqueraderV�remove_forward_portr\�remove_protocolr]�remove_source_portrS�remove_ingress_zonerT�remove_egress_zoner�rZget_added_and_removed_settings�
isinstance�list�tuple)r!r;r<rfr�r�Z
setting_to_fnZold_settingsZadd_settingsZremove_settingsr~r`r#)r
r!r$�set_config_with_settings_dict�s:











  z,FirewallPolicy.set_config_with_settings_dictcCs&|sttj��|dkr"|jj|�dS)Nr5r6)r5r6)rr�INVALID_ZONEr�
check_zone)r!r:r#r#r$�check_ingress_zones
z!FirewallPolicy.check_ingress_zonecCs|j|�|S)N)r�)r!r:r#r#r$Z__ingress_zone_id"s
z FirewallPolicy.__ingress_zone_idrTcCs�|jj|�}|jj|�|jj�|j|}|j|�}	|	|jdkrXttj	d||f��d|jdks�d|jdks�|dkr�|jdr�ttj
d��|dkr�d|jdkr�ttj
d��|dkr�|j�}
n|}
|�rJ|jr�|j
d||
�|j||	||�|
j|j||	�|j�s:||j�k�rH|j||
d	�|
j|j|d�n|j
d
||
�n |j||	||�|
j|j||	�|dk�r~|
jd
�dS)Nr4z'%s' already in '%s'r6r5zI'ingress-zones' may only contain one of: many regular zones, ANY, or HOSTr7zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr>�
check_timeout�check_panicr � _FirewallPolicy__ingress_zone_idr<rrrZr�r*rOro�&_FirewallPolicy__register_ingress_zone�add_fail�(_FirewallPolicy__unregister_ingress_zoner=rcrerx)r!r;r:rgrfrbrRrz�_obj�zone_idr{r#r#r$rS&s<




zFirewallPolicy.add_ingress_zonecCs|j||�|jd|<dS)Nr4)�_FirewallPolicy__gen_settingsr<)r!r�r�rgrfr#r#r$Z__register_ingress_zoneSsz&FirewallPolicy.__register_ingress_zonecCs�|jj|�}|jj�|j|}|j|�}||jdkrLttjd||f��|dkr^|j	�}n|}|j
r�t|jd�dkr�|j||�n|j
d||�|j||�|j|j||dd�||j�kr�|j
d||�n|j|j||�|dkr�|jd�|S)Nr4z'%s' not in '%s'rjFT)rr>r�r r�r<rr�NOT_ENABLEDr*rO�lenrPror�r�r�r=�add_postrx)r!r;r:rbrzr�r�r{r#r#r$r�Vs,




z"FirewallPolicy.remove_ingress_zonecCs||jdkr|jd|=dS)Nr4)r<)r!r�r�r#r#r$Z__unregister_ingress_zoneysz(FirewallPolicy.__unregister_ingress_zonecCs|j|�|j|�dkS)Nr4)r�r8)r!r;r:r#r#r$�query_ingress_zone}sz!FirewallPolicy.query_ingress_zonecCst|j|�dj��S)Nr4)r�r8r,)r!r;r#r#r$r��sz!FirewallPolicy.list_ingress_zonescCs&|sttj��|dkr"|jj|�dS)Nr5r6)r5r6)rrr�rr�)r!r:r#r#r$�check_egress_zone�s
z FirewallPolicy.check_egress_zonecCs|j|�|S)N)r�)r!r:r#r#r$Z__egress_zone_id�s
zFirewallPolicy.__egress_zone_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}	|	|jdkrXttj	d||f��d|jdks�d|jdks�|dkr�|jdr�ttj
d��|dkr�d|jdkr�ttj
d��|dkr�|j�}
n|}
|�rJ|jr�|j
d||
�|j||	||�|
j|j||	�|j�s:||j�k�rH|j||
d	�|
j|j|d�n|j
d
||
�n |j||	||�|
j|j||	�|dk�r~|
jd
�dS)Nr7z'%s' already in '%s'r6r5zH'egress-zones' may only contain one of: many regular zones, ANY, or HOSTr4zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr>r�r�r �_FirewallPolicy__egress_zone_idr<rrrZr�r*rOro�%_FirewallPolicy__register_egress_zoner��'_FirewallPolicy__unregister_egress_zoner=rcrerx)r!r;r:rgrfrbrRrzr�r�r{r#r#r$rT�s<




zFirewallPolicy.add_egress_zonecCs|j||�|jd|<dS)Nr7)r�r<)r!r�r�rgrfr#r#r$Z__register_egress_zone�sz%FirewallPolicy.__register_egress_zonecCs�|jj|�}|jj�|j|}|j|�}||jdkrLttjd||f��|dkr^|j	�}n|}|j
r�t|jd�dkr�|j||�n|j
d||�|j||�|j|j||dd�||j�kr�|j
d||�n|j|j||�|dkr�|jd�|S)Nr7z'%s' not in '%s'rjFT)rr>r�r r�r<rrr�r*rOr�rPror�r�r�r=r�rx)r!r;r:rbrzr�r�r{r#r#r$r��s,




z!FirewallPolicy.remove_egress_zonecCs||jdkr|jd|=dS)Nr7)r<)r!r�r�r#r#r$Z__unregister_egress_zone�sz'FirewallPolicy.__unregister_egress_zonecCs|j|�|j|�dkS)Nr7)r�r8)r!r;r:r#r#r$�query_egress_zone�sz FirewallPolicy.query_egress_zonecCst|j|�dj��S)Nr7)r�r8r,)r!r;r#r#r$r��sz FirewallPolicy.list_egress_zonescCs|j�dS)N)Zcheck)r!�ruler#r#r$�
check_rule�szFirewallPolicy.check_rulecCs|j|�t|�S)N)r��str)r!r�r#r#r$Z	__rule_id�s
zFirewallPolicy.__rule_idcCsx|sdS|jr,t|j�rdSt|j�rtdSnHt|d�r@|jr@dSt|d�rt|jrt|j|j�|j|j�|j|j�SdS)N�ipv4�ipv6�mac��ipset)	Zaddrrr�hasattrr�r��_check_ipset_type_for_source�_check_ipset_applied�
_ipset_family)r!�sourcer#r#r$�_rule_source_ipv�s

zFirewallPolicy._rule_source_ipvcCs|j||||�dS)N)�
_rule_prepare)r!ryr;r�r{r#r#r$Z__ruleszFirewallPolicy.__rulecCsL|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|j�s�|jr�t|jt
�r�d|jdkr�tt	jd��d|jdkr�tt	jd��x6|jdD](}
|
dkr�q�|jjj|
�r�tt	jd	��q�W|j�r�t|jt��r�d|jdk�r,|jj�r�tt	jd
��nb|jd�r�|jj�sNtt	jd��x>|jdD]0}
|
dk�rl�qZ|jjj|
��rZtt	jd���qZW|j�r�t|jt��r�x>|jdD]0}
|
dk�rq�|jjj|
��r�tt	jd
���q�W|dk�r�|j�}n|}|j�r|jd|||�|j||||�|j|j||�|dk�rH|jd�|S)NrHz'%s' already in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfaceszAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesT)r6r5)rr>r�r�r �_FirewallPolicy__rule_idr<r/rrrZ�elementr�rr�r:�list_interfacesr�
to_address�INVALID_FORWARD�actionrr*rOrw�_FirewallPolicy__register_ruler�� _FirewallPolicy__unregister_rulerx)r!r;r�rgrfrbrzr��rule_id�_namer:r{r#r#r$r^
s`










zFirewallPolicy.add_rulecCs|j||�|jd|<dS)NrH)r�r<)r!r�r�rgrfr#r#r$Z__register_ruleEszFirewallPolicy.__register_rulec	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrHz'%s' not in '%s'FT)rr>r�r r�r<r/rrr�r*rOrwr�r�rx)	r!r;r�rbrzr�r�r�r{r#r#r$r�Is"




zFirewallPolicy.remove_rulecCs||jdkr|jd|=dS)NrH)r<)r!r�r�r#r#r$Z__unregister_ruledsz FirewallPolicy.__unregister_rulecCs|j|�|j|�dkS)NrH)r�r8)r!r;r�r#r#r$�
query_rulehszFirewallPolicy.query_rulecCst|j|�dj��S)NrH)r�r8r,)r!r;r#r#r$r�kszFirewallPolicy.list_rulescCs|jj|�dS)N)r�
check_service)r!�servicer#r#r$r�pszFirewallPolicy.check_servicecCs|j|�|S)N)r�)r!r�r#r#r$Z__service_idss
zFirewallPolicy.__service_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|dkrz|j�}
n|}
|jr�|j
d|||
�|j||||�|
j|j||�|dkr�|
jd�|S)NrBz'%s' already in '%s'T)rr>r�r�r �_FirewallPolicy__service_idr<r/rrrZr*rOrr�!_FirewallPolicy__register_servicer��#_FirewallPolicy__unregister_servicerx)r!r;r�rgrfrbrzr��
service_idr�r{r#r#r$rWws&




zFirewallPolicy.add_servicecCs|j||�|jd|<dS)NrB)r�r<)r!r�r�rgrfr#r#r$Z__register_service�sz!FirewallPolicy.__register_servicec	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrBz'%s' not in '%s'FT)rr>r�r r�r<r/rrr�r*rOrrr�r�rx)	r!r;r�rbrzr�r�r�r{r#r#r$r��s"




zFirewallPolicy.remove_servicecCs||jdkr|jd|=dS)NrB)r<)r!r�r�r#r#r$Z__unregister_service�sz#FirewallPolicy.__unregister_servicecCs|j|�|j|�dkS)NrB)r�r8)r!r;r�r#r#r$�
query_service�szFirewallPolicy.query_servicecCs|j|�dj�S)NrB)r8r,)r!r;r#r#r$r��szFirewallPolicy.list_servicescCsTg}xJ|D]B}y|jjj|�}Wn tk
r@ttj|��YnX|j|�q
W|S)N)r�helper�
get_helperrr�INVALID_HELPERr0)r!�helpers�_helpersr��_helperr#r#r$�get_helpers_for_service_helpers�s
z.FirewallPolicy.get_helpers_for_service_helperscCs�g}x�|D]�}y|jjj|�}Wn tk
r@ttj|��YnXt|j�dkr�t|j	�}y|jjj|�}|j
|�Wq�tk
r�|r�tjd|�w
Yq�Xq
|j
|�q
W|S)NrjzHelper '%s' is not available)
rr�r�rrr�r�rCr
�moduler0rr[)r!�modulesryr�r�r��_module_short_namer�r#r#r$�get_helpers_for_service_modules�s"


z.FirewallPolicy.get_helpers_for_service_modulescCs|jj|�|jj|�dS)N)r�
check_port�check_tcpudp)r!�port�protocolr#r#r$r��szFirewallPolicy.check_portcCs|j||�t|d�|fS)N�-)r�r)r!r�r�r#r#r$Z	__port_id�szFirewallPolicy.__port_idcs�|jj|�}|jj|�|jj�|j|}tt�fdd�|jd��}	x@|	D]8}
t||
d�rN|j	rl|j	n|}t
tjd|�|f��qNWt
|dd�|	D��\}}
|dkr�|j�}n|}|j�rx$|D]}|jd|t|d	��|�q�Wx$|
D]}|jd
|t|d	��|�q�Wx:|D]2}|j|��}
|j||
||�|j|j||
��qWx*|
D]"}|j|��}
|j|j||
��qNW|dk�r�|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$�<lambda>�sz)FirewallPolicy.add_port.<locals>.<lambda>rCrz'%s:%s' already in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$�
<listcomp>�sz+FirewallPolicy.add_port.<locals>.<listcomp>Tr�F)rr>r�r�r r��filterr<r	r/rrrZrr*rOrsr�_FirewallPolicy__port_id�_FirewallPolicy__register_portr�� _FirewallPolicy__unregister_portr�rx)r!r;r�r�rgrfrbrzr��existing_port_ids�port_idr��added_ranges�removed_rangesr{�ranger#)r�r$rX�s:









zFirewallPolicy.add_portcCs|j||�|jd|<dS)NrC)r�r<)r!r�r�rgrfr#r#r$Z__register_portszFirewallPolicy.__register_portcs�|jj|�}|jj�|j|}tt�fdd�|jd��}xB|D]}t||d�rBPqBW|jrf|jn|}	t	t
jd|�|	f��t|dd�|D��\}
}|dkr�|j
�}n|}|j�rx$|
D]}
|jd|t|
d	��|�q�Wx$|D]}
|jd
|t|
d	��|�q�Wx:|
D]2}
|j|
��}|j||dd�|j|j||��qWx*|D]"}
|j|
��}|j|j||��qDW|dk�r~|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$r�sz,FirewallPolicy.remove_port.<locals>.<lambda>rCrz'%s:%s' not in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$r�#sz.FirewallPolicy.remove_port.<locals>.<listcomp>Tr�F)rr>r�r r�r�r<r	r/rrr�rr*rOrsrr�r�r�r�r�rx)r!r;r�r�rbrzr�r�r�r�r�r�r{r�r#)r�r$r�s:









zFirewallPolicy.remove_portcCs||jdkr|jd|=dS)NrC)r<)r!r�r�r#r#r$Z__unregister_port=sz FirewallPolicy.__unregister_portcCs6x0|j|�dD]\}}t||�r||krdSqWdS)NrCTF)r8r	)r!r;r�r�rsrtr#r#r$�
query_portAszFirewallPolicy.query_portcCst|j|�dj��S)NrC)r�r8r,)r!r;r#r#r$r�HszFirewallPolicy.list_portscCst|�sttj|��dS)N)rrrZINVALID_PROTOCOL)r!r�r#r#r$�check_protocolMszFirewallPolicy.check_protocolcCs|j|�|S)N)r�)r!r�r#r#r$Z
__protocol_idQs
zFirewallPolicy.__protocol_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|dkrz|j�}
n|}
|jr�|j
d|||
�|j||||�|
j|j||�|dkr�|
jd�|S)NrIz'%s' already in '%s'T)rr>r�r�r �_FirewallPolicy__protocol_idr<r/rrrZr*rOrt�"_FirewallPolicy__register_protocolr��$_FirewallPolicy__unregister_protocolrx)r!r;r�rgrfrbrzr��protocol_idr�r{r#r#r$r\Us&




zFirewallPolicy.add_protocolcCs|j||�|jd|<dS)NrI)r�r<)r!r�r�rgrfr#r#r$Z__register_protocolrsz"FirewallPolicy.__register_protocolc	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrIz'%s' not in '%s'FT)rr>r�r r�r<r/rrr�r*rOrtr�r�rx)	r!r;r�rbrzr�r�r�r{r#r#r$r�vs$





zFirewallPolicy.remove_protocolcCs||jdkr|jd|=dS)NrI)r<)r!r�r�r#r#r$Z__unregister_protocol�sz$FirewallPolicy.__unregister_protocolcCs|j|�|j|�dkS)NrI)r�r8)r!r;r�r#r#r$�query_protocol�szFirewallPolicy.query_protocolcCst|j|�dj��S)NrI)r�r8r,)r!r;r#r#r$r��szFirewallPolicy.list_protocolscCs|j||�t|d�|fS)Nr�)r�r)r!r�r�r#r#r$Z__source_port_id�szFirewallPolicy.__source_port_idcs�|jj|�}|jj|�|jj�|j|}tt�fdd�|jd��}	x@|	D]8}
t||
d�rN|j	rl|j	n|}t
tjd|�|f��qNWt
|dd�|	D��\}}
|dkr�|j�}n|}|j�rx$|D]}|jd|t|d	��|�q�Wx$|
D]}|jd
|t|d	��|�q�Wx:|D]2}|j|��}
|j||
||�|j|j||
��qWx*|
D]"}|j|��}
|j|j||
��qNW|dk�r�|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$r��sz0FirewallPolicy.add_source_port.<locals>.<lambda>rFrz'%s:%s' already in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$r��sz2FirewallPolicy.add_source_port.<locals>.<listcomp>Tr�F)rr>r�r�r r�r�r<r	r/rrrZrr*rOrur�_FirewallPolicy__source_port_id�%_FirewallPolicy__register_source_portr��'_FirewallPolicy__unregister_source_portr�rx)r!r;r�r�rgrfrbrzr�r�r�r�r�r�r{r�r#)r�r$r]�s:









zFirewallPolicy.add_source_portcCs|j||�|jd|<dS)NrF)r�r<)r!r�r�rgrfr#r#r$Z__register_source_port�sz%FirewallPolicy.__register_source_portcs�|jj|�}|jj�|j|}tt�fdd�|jd��}xB|D]}t||d�rBPqBW|jrf|jn|}	t	t
jd|�|	f��t|dd�|D��\}
}|dkr�|j
�}n|}|j�rx$|
D]}
|jd|t|
d	��|�q�Wx$|D]}
|jd
|t|
d	��|�q�Wx:|
D]2}
|j|
��}|j||dd�|j|j||��qWx*|D]"}
|j|
��}|j|j||��qDW|dk�r~|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$r��sz3FirewallPolicy.remove_source_port.<locals>.<lambda>rFrz'%s:%s' not in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$r��sz5FirewallPolicy.remove_source_port.<locals>.<listcomp>Tr�F)rr>r�r r�r�r<r	r/rrr�rr*rOrurr�r�r�r�r�rx)r!r;r�r�rbrzr�r�r�r�r�r�r{r�r#)r�r$r��s:









z!FirewallPolicy.remove_source_portcCs||jdkr|jd|=dS)NrF)r<)r!r�r�r#r#r$Z__unregister_source_port�sz'FirewallPolicy.__unregister_source_portcCs6x0|j|�dD]\}}t||�r||krdSqWdS)NrFTF)r8r	)r!r;r�r�rsrtr#r#r$�query_source_port�sz FirewallPolicy.query_source_portcCst|j|�dj��S)NrF)r�r8r,)r!r;r#r#r$r�sz FirewallPolicy.list_source_portscCsdS)NTr#)r!r#r#r$Z__masquerade_idszFirewallPolicy.__masquerade_idcCs8|jj|�}|jj|�|jj�|j|}|j�}||jdkrb|jrN|jn|}tt	j
d|��|js�d|jdkr�tt	jd��d|jdkr�tt	jd��x6|jdD](}	|	dkr�q�|jjj
|	�r�tt	jd	��q�W|dkr�|j�}
n|}
|j�r|jd
||
�|j||||�|
j|j||�|dk�r4|
jd
�|S)NrDz"masquerade already enabled in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesT)rr>r�r�r �_FirewallPolicy__masquerade_idr<r/rrrZr�r:r�r*rOrv�$_FirewallPolicy__register_masquerader��&_FirewallPolicy__unregister_masqueraderx)r!r;rgrfrbrzr��
masquerade_idr�r:r{r#r#r$r_
s:





zFirewallPolicy.add_masqueradecCs|j||�|jd|<dS)NrD)r�r<)r!r�r�rgrfr#r#r$Z__register_masquerade2sz$FirewallPolicy.__register_masqueradecCs�|jj|�}|jj�|j|}|j�}||jdkrV|jrB|jn|}ttj	d|��|dkrh|j
�}n|}|jr�|jd||�|j
|j||�|dkr�|jd�|S)NrDzmasquerade not enabled in '%s'FT)rr>r�r r�r<r/rrr�r*rOrvr�r�rx)r!r;rbrzr�r�r�r{r#r#r$r�6s"




z FirewallPolicy.remove_masqueradecCs||jdkr|jd|=dS)NrD)r<)r!r�r�r#r#r$Z__unregister_masqueradePsz&FirewallPolicy.__unregister_masqueradecCs|j�|j|�dkS)NrD)r�r8)r!r;r#r#r$r�TszFirewallPolicy.query_masqueradecCs^|jj|�|jj|�|r(|jj|�|rBt||�sBttj|��|rZ|rZttjd��dS)Nz.port-forwarding is missing to-port AND to-addr)rr�r�rrrZINVALID_ADDRr�)r!�ipvr�r��toport�toaddrr#r#r$�check_forward_portYs
z!FirewallPolicy.check_forward_portcCsLtd|�r|jd||||�n|jd||||�t|d�|t|d�t|�fS)Nr�r�r�)rrrr�)r!r�r�r�r�r#r#r$Z__forward_port_idfs


z FirewallPolicy.__forward_port_idc	CsZ|jj|�}	|jj|�|jj�|j|	}
|j||||�}||
jdkrt|
jrV|
jn|	}tt	j
d|||||f��|
js�d|
jdkr�|r�tt	jd��nR|
jdr�|s�tt	jd��x6|
jdD](}
|
dkr�q�|jjj
|
�r�tt	jd��q�W|dk�r|j�}n|}|
j�r"|jd	|	|||||�|j|
|||�|j|j|
|�|dk�rV|jd	�|	S)
NrEz'%s:%s:%s:%s' already in '%s'r5r7zAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zoner6zS'forward-port' cannot be used in a policy if an egress zone has assigned interfacesT)rr>r�r�r � _FirewallPolicy__forward_port_idr<r/rrrZr�r:r�r�r*rOrq�&_FirewallPolicy__register_forward_portr��(_FirewallPolicy__unregister_forward_portrx)r!r;r�r�r�r�rgrfrbrzr��
forward_idr�r:r{r#r#r$rVnsB






zFirewallPolicy.add_forward_portcCs|j||�|jd|<dS)NrE)r�r<)r!r�rrgrfr#r#r$Z__register_forward_port�sz&FirewallPolicy.__register_forward_portcCs�|jj|�}|jj�|j|}|j||||�}	|	|jdkrh|jrJ|jn|}
ttj	d|||||
f��|dkrz|j
�}n|}|jr�|jd||||||�|j
|j||	�|dkr�|jd�|S)NrEz'%s:%s:%s:%s' not in '%s'FT)rr>r�r rr<r/rrr�r*rOrqr�rrx)r!r;r�r�r�r�rbrzr�rr�r{r#r#r$r��s&



z"FirewallPolicy.remove_forward_portcCs||jdkr|jd|=dS)NrE)r<)r!r�rr#r#r$Z__unregister_forward_port�sz(FirewallPolicy.__unregister_forward_portcCs"|j||||�}||j|�dkS)NrE)rr8)r!r;r�r�r�r�rr#r#r$�query_forward_port�sz!FirewallPolicy.query_forward_portcCst|j|�dj��S)NrE)r�r8r,)r!r;r#r#r$r��sz!FirewallPolicy.list_forward_portscCs|jj|�dS)N)rZcheck_icmptype)r!�icmpr#r#r$�check_icmp_block�szFirewallPolicy.check_icmp_blockcCs|j|�|S)N)r)r!rr#r#r$Z__icmp_block_id�s
zFirewallPolicy.__icmp_block_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|dkrz|j�}
n|}
|jr�|j
d|||
�|j||||�|
j|j||�|dkr�|
jd�|S)NrGz'%s' already in '%s'T)rr>r�r�r �_FirewallPolicy__icmp_block_idr<r/rrrZr*rOrp�$_FirewallPolicy__register_icmp_blockr��&_FirewallPolicy__unregister_icmp_blockrx)r!r;rrgrfrbrzr��icmp_idr�r{r#r#r$rU�s&




zFirewallPolicy.add_icmp_blockcCs|j||�|jd|<dS)NrG)r�r<)r!r�rrgrfr#r#r$Z__register_icmp_block�sz$FirewallPolicy.__register_icmp_blockc	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrGz'%s' not in '%s'FT)rr>r�r rr<r/rrr�r*rOrpr�r
rx)	r!r;rrbrzr�rr�r{r#r#r$r��s"




z FirewallPolicy.remove_icmp_blockcCs||jdkr|jd|=dS)NrG)r<)r!r�rr#r#r$Z__unregister_icmp_blocksz&FirewallPolicy.__unregister_icmp_blockcCs|j|�|j|�dkS)NrG)rr8)r!r;rr#r#r$�query_icmp_blockszFirewallPolicy.query_icmp_blockcCs|j|�dj�S)NrG)r8r,)r!r;r#r#r$r�szFirewallPolicy.list_icmp_blockscCsdS)NTr#)r!r#r#r$Z__icmp_block_inversion_idsz(FirewallPolicy.__icmp_block_inversion_idc
Cs|jj|�}|jj�|j|}|j�}||jdkrV|jrB|jn|}ttj	d|��|dkrh|j
�}n|}|jr�x&|j|�dD]}	|j
d||	|�q�W|jd||�|j|||�|j|j|||�|j�rx&|j|�dD]}	|j
d||	|�q�W|jd||�|dk�r|jd�|S)NrJz,icmp-block-inversion already enabled in '%s'rGFT)rr>r�r �(_FirewallPolicy__icmp_block_inversion_idr<r/rrrZr*rOr8rp�_icmp_block_inversion�._FirewallPolicy__register_icmp_block_inversionr��*_FirewallPolicy__undo_icmp_block_inversionrx)
r!r;rfrbrzr��icmp_block_inversion_idr�r{r`r#r#r$�add_icmp_block_inversions6





z'FirewallPolicy.add_icmp_block_inversioncCs|jd|�|jd|<dS)NrrJ)r�r<)r!r�rrfr#r#r$Z__register_icmp_block_inversionEsz.FirewallPolicy.__register_icmp_block_inversioncCs�|j�}|jr6x&|j|�dD]}|jd|||�qW||jdkrP|jd|=|jr~x&|j|�dD]}|jd|||�qfW|jd�dS)NrGFrJT)r*rOr8rpr<rx)r!rzr�rr{r`r#r#r$Z__undo_icmp_block_inversionJsz*FirewallPolicy.__undo_icmp_block_inversionc	Cs|jj|�}|jj�|j|}|j�}||jdkrV|jrB|jn|}ttj	d|��|dkrh|j
�}n|}|jr�x&|j|�dD]}|j
d|||�q�W|jd||�|j||�|j|j||d�|j�rx&|j|�dD]}|j
d|||�q�W|jd||�|dk�r|jd�|S)NrJz(icmp-block-inversion not enabled in '%s'rGFT)rr>r�r r
r<r/rrr�r*rOr8rpr�0_FirewallPolicy__unregister_icmp_block_inversionr�rrx)	r!r;rbrzr�rr�r{r`r#r#r$�remove_icmp_block_inversion\s6






z*FirewallPolicy.remove_icmp_block_inversioncCs||jdkr|jd|=dS)NrJ)r<)r!r�rr#r#r$Z!__unregister_icmp_block_inversion�sz0FirewallPolicy.__unregister_icmp_block_inversioncCs|j�|j|�dkS)NrJ)r
r8)r!r;r#r#r$�query_icmp_block_inversion�sz)FirewallPolicy.query_icmp_block_inversionc
Cs�|jjj|�}|jr*|jjj|jd}n|}|rT||jkrt||f|j|krtdSn ||jksp||f|j|krtdSx@|jj�D]2}|jr�||j	�kr�|j
||||�}	|j||	�q�W|j||||fg�|j
|j||||fg�dS)Nr)rr;r.r/r:Z_zone_policiesr�enabled_backends�policies_supportedZget_available_tablesZbuild_policy_chain_rules�	add_rules�_register_chainsr�)
r!r;�creater|r}r{rMZtracking_policy�backendrHr#r#r$rn�s$

zFirewallPolicy.gen_chain_rulescCsbx\|D]T\}}|r,|jj|g�j||f�q|j|j||f�t|j|�dkr|j|=qWdS)Nr)r�
setdefaultr0�remover�)r!r;rZtablesr|r}r#r#r$r�szFirewallPolicy._register_chainscCs$|jjj|�dkrdS|jjj|�S)Nzhash:mac)rr��get_typeZ
get_family)r!rKr#r#r$r��szFirewallPolicy._ipset_familycCs|jjj|�S)N)rr�r)r!rKr#r#r$Z__ipset_type�szFirewallPolicy.__ipset_typecCsdj|g|jjj|��S)N�,)�joinrr�Z
get_dimension)r!rK�flagr#r#r$�_ipset_match_flags�sz!FirewallPolicy._ipset_match_flagscCs|jjj|�S)N)rr�Z
check_applied)r!rKr#r#r$r��sz#FirewallPolicy._check_ipset_appliedcCs*|j|�}|tkr&ttjd||f��dS)Nz.ipset '%s' with type '%s' not usable as source)�_FirewallPolicy__ipset_typerrrZ
INVALID_IPSET)r!rKZ_typer#r#r$r��s
z+FirewallPolicy._check_ipset_type_for_sourcecs�t|j�tkr��jjj|jj�}|dkr2|jjg}xR|jD]H}||krHq:�j|�|j	|�t
j|�}||j_�j|||||d�q:Wg}	|j
r�|j
g}	nH|jr�t|jt�s�t|jt�r�jjj|jj���jr�fdd�dD�}	�j|j�}
|
�r&|j
�r |j
|
k�r&ttjd|
|j
f��n|
g}	|	�s4ddg}	�fdd�|	D�}	|	|_�x2t�fdd�|	D��D�]}t|j�tk�r��jjj|jj�}g}t|j�d	k�r�|j�r�ttjd
��xB|	D].}
|
|jk�r�|j|
��r�|j	|j|
��q�Wn
|j	d��x~|D�]�}t|j�tk�r�j|j |�}|�j!|j"�7}t#t|�dd�d
�}g}x�|D]�}|j$}t%|�}|j&dd�}|j	|�|j
dk�r�|j|j
��r��qTt|j'�dk�r�|j	|�n:x8|j'D].\}}|j(||||||j|�}|j)||��q�W�qTW|j*|�x4|j'D]*\}}|j+||||||�}|j)||��q
Wx.|j,D]$}|j-|||||�}|j)||��q@Wx4|j.D]*\}}|j/||||||�}|j)||��qpW�qW�qft|j�t0k�r�|jj1}|jj2}�j3||�|j+||||d|�}|j)||��qft|j�t4k�r<|jj5}�j6|�|j-|||d|�}|j)||��qft|j�t7k�r�|�rzx&|	D]}
|j|
��rX|j8t9|
��qXW|j:|||�}|j)||��qft|j�t;k�r4|jj1}|jj2}|jj<}|jj=}xD|	D]<}
|j|
��r�j>|
||||�|�r�|�r�|j8t9|
��q�W|j?|||||||�}|j)||��qft|j�t@k�r�|jj1}|jj2}�j3||�|j/||||d|�}|j)||�n�t|j�tk�s�t|j�tk�r>�jjj|jj��|j
�r�j�r�|j
�jk�r�ttjAd|j
|jjf��t|j�tk�r |j�r t|j�tk�r ttjd��|jB||�|�}|j)||�n>|jdk�rf|jC|||�}|j)||�nttjdt|j����qfWdS)N)�included_servicescsg|]}|�jkr|�qSr#)�destination)r?r�)�ictr#r$r��sz0FirewallPolicy._rule_prepare.<locals>.<listcomp>r�r�z;Source address family '%s' conflicts with rule family '%s'.csg|]}�jj|�r|�qSr#)r�is_ipv_enabled)r?r�)r!r#r$r��scsg|]}�jj|��qSr#)r�get_backend_by_ipv)r?r@)r!r#r$r��srz"Destination conflict with service.cSs|jS)N)rK)r@r#r#r$r�sz.FirewallPolicy._rule_prepare.<locals>.<lambda>)r~�	conntrack�natr�rjz3rich rule family '%s' conflicts with icmp type '%s'z'IcmpBlock not usable with accept actionzUnknown element %s)r�r�)D�typer�rrr��get_servicerK�includesr�r0�copy�deepcopyr��familyr�rr�config�get_icmptyper%r�r�rrZINVALID_RULE�ipvsr9r��is_ipv_supportedr�rr�r�r�r�r+r�r
�replacerC�build_policy_helper_ports_rulesrZadd_modules�build_policy_ports_rulesrI�build_policy_protocol_rulesrF�build_policy_source_ports_rulesrr�r�r�r�valuer�rr�r�build_policy_masquerade_rulesrZto_portr�r�build_policy_forward_port_rulesrZINVALID_ICMPTYPE�build_policy_icmp_block_rulesZ*build_policy_rich_source_destination_rules)r!ryr;r�r{r$�svc�includeZ_ruler3Z
source_ipvrZdestinationsr�r%r�r�r�r�r��
nat_moduler��protorHr�r�r�r#)r&r!r$r��s




 









zFirewallPolicy._rule_preparecCsb|jjj|�}|j|j|�}||j|j�7}tt|�dd�d�}|dkrN|g}x@|j	D]6}||krdqV|j
|�|j|�|j|||||d�qVWg}	xndD]f}
|jj
|
�s�q�|jj|
�}t|j�dkr�|
|jkr�|	j||j|
f�q�|df|	kr�|	j|df�q�W�xV|	D�]L\}}x�|D]�}
|
j}t|�}|
jjdd	�}|j|�|
jd
k�rf|j|
j��rf�qt|
j�dk�r�|j|�n:x8|
jD].\}}|j||||||
j|�}|j||��q�W�qWx2|jD](\}}|j|||||�}|j||��q�Wx,|jD]"}|j||||�}|j||��q�Wx2|jD](\}}|j|||||�}|j||��q,W�qWdS)
NcSs|jS)N)rK)r@r#r#r$r��sz)FirewallPolicy._service.<locals>.<lambda>)r~)r$r�r�rr)r*r�rj)r�r�) rr�r,r�r�r�r�r+r9r-r�r0rrr'r(r�r%r�r
r5Z
add_moduler0r4rCr6rKrr7rIr8rFr9)r!ryr;r�r{r$r>r�r?Zbackends_ipvr�rr%r�r�r�r@r�rArHr�r#r#r$rr�sb






zFirewallPolicy._servicecCs<x6|jj�D](}|jsq|j||||�}|j||�qWdS)N)rrrr7r)r!ryr;r�r�r{rrHr#r#r$rs�s
zFirewallPolicy._portcCs:x4|jj�D]&}|jsq|j|||�}|j||�qWdS)N)rrrr8r)r!ryr;r�r{rrHr#r#r$rt�s
zFirewallPolicy._protocolcCs<x6|jj�D](}|jsq|j||||�}|j||�qWdS)N)rrrr9r)r!ryr;r�r�r{rrHr#r#r$ru�s
zFirewallPolicy._source_portcCs8d}|jt|�|jj|�}|j||�}|j||�dS)Nr�)r�rrr(r;r)r!ryr;r{r�rrHr#r#r$rv�s
zFirewallPolicy._masqueradecCsXtd|�rd}nd}|r(|r(|jt|�|jj|�}	|	j||||||�}
|j|	|
�dS)Nr�r�)rr�rrr(r<r)r!ryr;r{r�r�r�r�r�rrHr#r#r$rq�s

zFirewallPolicy._forward_portc
Cs�|jjj|�}xl|jj�D]^}|js&qd}|jrXx&dD]}||jkr6|j|�s6d}Pq6W|r^q|j|||�}	|j||	�qWdS)NFr�r�T)r�r�)	rr1r2rrr%r4r=r)
r!ryr;rr{r&rZskip_backendr�rHr#r#r$rp�s


zFirewallPolicy._icmp_blockcCsh|j|j}|dkrdS|j|�r0|dkr0dSx2|jj�D]$}|jsHq<|j||�}|j||�q<WdS)N�DROP�
%%REJECT%%�REJECTZACCEPT)rBrCrD)r �targetrrrrZ'build_policy_icmp_block_inversion_rulesr)r!ryr;r{rErrHr#r#r$rsz$FirewallPolicy._icmp_block_inversionc	Cs�x|D]}|j|�qWx|D]}|j|�qWd|ks@d|krXt|�dkrXttjd��d|kshd|kr�t|�dkr�ttjd��|s�|r�|r�|r�d|kr�d|kr�ttjd|��|s�|r�|r�|r�d|kr�d|kr�ttjd|��dS)Nr6r5rjzI'ingress-zones' may only contain one of: many regular zones, ANY, or HOSTzH'egress-zones' may only contain one of: many regular zones, ANY, or HOSTzpolicy "%s" has no ingresszpolicy "%s" has no egress)r�r�r�rrr�)	r!r;r4r7�ingress_interfaces�egress_interfaces�ingress_sources�egress_sourcesr:r#r#r$�check_ingress_egress"s$

z#FirewallPolicy.check_ingress_egressc

Cs�|dkr&|dkr�|r�ttjd|��n�|dkrtd|krFttjd|��d|kr^ttjd|��|r�ttjd|��n||d	kr�d|kr�ttjd|��d|kr�ttjd|��nB|d
kr�d|kr�ttjd|��n |dkr�d|kr�ttjd
|��dS)N�
PREROUTING�rawzFpolicy "%s" egress-zones may not include a zone with added interfaces.�POSTROUTINGr5z/policy "%s" ingress-zones may not include HOST.z.policy "%s" egress-zones may not include HOST.zGpolicy "%s" ingress-zones may not include a zone with added interfaces.�FORWARD�INPUTz0policy "%s" egress-zones must include only HOST.�OUTPUTz1policy "%s" ingress-zones must include only HOST.)rrr�)
r!r;r|r}r4r7rFrGrHrIr#r#r$�check_ingress_egress_chain<s,z)FirewallPolicy.check_ingress_egress_chaincCs$|j�}|j|||�|jd�dS)NT)r*rorx)r!ryr;r{r#r#r$�!_ingress_egress_zones_transactionYsz0FirewallPolicy._ingress_egress_zones_transactioncCsL|j|}|jd}|jd}t�}t�}t�}	t�}
xB|D]:}|dkrJq<|t|jjj|��O}|	t|jjj|��O}	q<WxB|D]:}|dkr�q�|t|jjj|��O}|
t|jjj|��O}
q�W|j||||||	|
�xr|jj�D]d}|j	s�q�xV|j
|�D]H\}
}|j||
||||||	|
�	|j|||
||||	|
�}|j
||��q�Wq�WdS)Nr4r7r6r5)r6r5)r6r5)r r<r9rr:r�Zlist_sourcesrJrrrlrQZ!build_policy_ingress_egress_rulesr)r!ryr;r{rMr4r7rFrGrHrIr:rr|r}rHr#r#r$ro^s@






z$FirewallPolicy._ingress_egress_zonescCs6|j|}d|jdkrFd|jdkrFdddg}|jjsB|jd�|Sd|jdkrpdg}|jjsl|jd�|Sd|jdkr�dgSd|jdko�d|jdk�r�ddddg}|jj�s�|jd�|Sd|jdk�r.dddg}|jj�s�|jd�x4|jdD]}|jjj|�d�rP�qW|jd �|Sd|jdk�r�d!d"g}|jj�sZ|jd#�x>|jdD]}|jjj|�d�rfP�qfW|jd$�|jd%�|Sd&g}|jj�s�|jd'�x4|jdD]}|jjj|�d�r�P�q�W|jd(�x>|jdD]}|jjj|�d�r�P�q�W|jd)�|jd*�|SdS)+z:Create a list of (table, chain) needed for policy dispatchr6r4r5r7r�rOr*rK�manglerLrPrNrMZ
interfacesN)r�rO)r*rK)rSrK)rLrK)r�rO)rLrK)r�rP)r�rN)r*rK)r*rM)rSrK)rLrK)r�rN)r*rK)rSrK)rLrK)r*rM)r�rN)r*rM)rLrK)r*rK)rSrK)r�rN)rLrK)r*rM)r*rK)rSrK)r r<r�nftables_enabledr0r:r8)r!r;rM�tcr:r#r#r$rl�sj
















z4FirewallPolicy._get_table_chains_for_policy_dispatchcCsr|j|}d|jdkr4dg}|jjs0|jd�|Sd|jdkrLdddgSd|jdkrbddgStd|�SdS)z8Create a list of (table, chain) needed for zone dispatchr5r7r�rOrLrKr6�
FORWARD_INr*rSr4�FORWARD_OUTrMzInvalid policy: %sN)r�rO)rLrK)r�rV)r*rK)rSrK)r�rW)r*rM)r r<rrTr0r)r!r;rMrUr#r#r$rm�s

z2FirewallPolicy._get_table_chains_for_zone_dispatchFcCs�|jjj|�}|jr|j}n||}d|jdkrl|dkrBd|S|dkrRd|S|jsh|dkrhd|S�nJd|jd	kr�|js�|dkr�d
|S�n"d|jdk�r�|dkr�|jr�d|Sd
|Sn0|dkr�|r�d|Sd|Sn|dk�r�d|Sn�d|jd	k�rh|dk�r*|j�r d|Sd
|Sn<|dk�rL|�rBd|Sd|Sn|dk�r�|j�s�d|SnN|j�s�|dk�r�d
|S|dk�r�|�r�d|Sd|Sn|dk�r�d|Std|||f�S)Nr5r7r�ZIN_rLZPRE_rSr*r4ZOUT_r6ZFWDI_ZFWD_ZPOST_ZFWDO_z.Can't convert policy to chain name: %s, %s, %s)rSr*)rSrL)rSrL)rSrL)rr;r.r/r<r)r!r;r|Z
policy_prefixZisSNATrM�suffixr#r#r$�policy_base_chain_name�sb













z%FirewallPolicy.policy_base_chain_name)N)N)N)N)rNNT)N)rNNT)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)NN)NN)NNrNN)NNN)NN)rNN)N)NN)N)N)N)NN)F)��__name__�
__module__�__qualname__r%r'r)r*r-r3r=r.rNrQrLrdrer�r8rrcrPr�r�r�r�rSr�r�r�r�r�r�r�rTr�r�r�r�r�r�r�r�rwr^r�r�r�r�r�r�r�rWr�r�r�r�r�r�r�r�r�rXr�r�r�r�r�r�r�r\r�r�r�r�r�r�r]r�r�r�r�r�r�r_r�r�r�r�rrrVrr�rrr�rrrUr	r�r
rr�r
rrrrrrrnrr�r#r"r�r�r�rrrsrtrurvrqrprrJrQrRrorlrmrYr#r#r#r$rs$
'	?.,#,#:
'('('
+))@@		(Pr)'rhr.Zfirewall.core.loggerrZfirewall.functionsrrrrrrr	r
rrr�r
rrrrrrrrrrZfirewall.core.fw_transactionrZfirewallrZfirewall.errorsrZfirewall.fw_typesrZfirewall.core.baser�objectrr#r#r#r$�<module>s04__pycache__/logger.cpython-36.pyc000064400000055135151731527020012675 0ustar003

��g>y�@s�ddddgZddlZddlZddlZddlZddlZddlZddlZddlZddl	Z
ddl
Z
Gdd�de�ZGdd�de�Z
Gd	d
�d
e
�ZGdd�de�ZGd
d�de�ZGdd�de�Ze�ZdS)�	LogTarget�FileLog�Logger�log�Nc@s2eZdZdZdd�Zddd�Zdd�Zd	d
�ZdS)
rz% Abstract class for logging targets. cCs
d|_dS)N)�fd)�self�r�/usr/lib/python3.6/logger.py�__init__(szLogTarget.__init__rcCstd��dS)Nz%LogTarget.write is an abstract method)�NotImplementedError)r�data�level�logger�is_debugrrr	�write+szLogTarget.writecCstd��dS)Nz%LogTarget.flush is an abstract method)r)rrrr	�flush.szLogTarget.flushcCstd��dS)Nz%LogTarget.close is an abstract method)r)rrrr	�close1szLogTarget.closeN)r)�__name__�
__module__�__qualname__�__doc__r
rrrrrrr	r&s

c@s.eZdZdd�Zddd�Zdd�Zdd	�Zd
S)�
_StdoutLogcCstj|�tj|_dS)N)rr
�sys�stdoutr)rrrr	r
8s
z_StdoutLog.__init__rcCs|jj|�|j�dS)N)rrr)rrr
rrrrr	r<sz_StdoutLog.writecCs|j�dS)N)r)rrrr	rAsz_StdoutLog.closecCs|jj�dS)N)rr)rrrr	rDsz_StdoutLog.flushN)r)rrrr
rrrrrrr	r7s
rc@seZdZdd�ZdS)�
_StderrLogcCstj|�tj|_dS)N)rr
r�stderrr)rrrr	r
Ks
z_StderrLog.__init__N)rrrr
rrrr	rJsrc@s.eZdZdd�Zddd�Zdd�Zdd	�Zd
S)�
_SyslogLogcCs.tj|�tjtjjtjd�tj	tj
�dS)Nr)rr
�syslogZopenlog�os�path�basenamer�argvZLOG_PIDZ
LOG_DAEMON)rrrr	r
Ss
	z_SyslogLog.__init__rcCs�d}|rtj}nF||jkr"tj}n4||jkr4tj}n"||jkrFtj}n||jkrVtj	}|j
d�rt|dt|�d�}t|�dkr�|dkr�tj|�ntj||�dS)N�
�r)rZ	LOG_DEBUG�INFO1ZLOG_INFO�WARNINGZLOG_WARNING�ERRORZLOG_ERR�FATALZLOG_CRIT�endswith�len)rrr
rrZpriorityrrr	ras"




z_SyslogLog.writecCstj�dS)N)rZcloselog)rrrr	rwsz_SyslogLog.closecCsdS)Nr)rrrr	rzsz_SyslogLog.flushN)r)rrrr
rrrrrrr	rRs
rc@s<eZdZdZddd�Zdd�Zddd	�Zd
d�Zdd
�ZdS)rz< FileLog class.
    File will be opened on the first write. �wcCstj|�||_||_dS)N)rr
�filename�mode)rr+r,rrr	r
�s
zFileLog.__init__cCsv|jr
dStjtjB}|jjd�r,|tjO}tj|j|d�|_tj	|jd�tj
|j|j�|_tj|jtjtj
�dS)N�ai�)rr�O_CREAT�O_WRONLYr,�
startswith�O_APPEND�openr+�fchmod�fdopen�fcntlZF_SETFDZ
FD_CLOEXEC)r�flagsrrr	r2�s
zFileLog.openrcCs(|js|j�|jj|�|jj�dS)N)rr2rr)rrr
rrrrr	r�sz
FileLog.writecCs|js
dS|jj�d|_dS)N)rr)rrrr	r�s
z
FileLog.closecCs|js
dS|jj�dS)N)rr)rrrr	r�sz
FileLog.flushN)r*)r)	rrrrr
r2rrrrrrr	rs

c@s�eZdZdZd[Zd\Zd]Zd^Zd_ZdZ	e
�Ze�Z
e�Zd`d	d
�Zdd�Zdadd�Zdbdd�Zdcdd�Zdddd�Zdd�Zdd�Zdd�Zdd�Zdd�Zd d!�Zed"fd#d$�Zed"fd%d&�Zed"fd'd(�Zed"fd)d*�Zed"fd+d,�Z ed"fd-d.�Z!d/d0�Z"d1d2�Z#d3d4�Z$d5d6�Z%d7d8�Z&d9d:�Z'd;d<�Z(d=d>�Z)d?d@�Z*dAdB�Z+dCdD�Z,dedEdF�Z-dGdH�Z.dfdIdJ�Z/ed"dfdKdL�Z0ed"dfdMdN�Z1ed"dfdOdP�Z2dgdQdR�Z3dSdT�Z4dUdV�Z5dWdX�Z6dhdYdZ�Z7d"S)iraL	
    Format string:

    %(class)s      Calling class the function belongs to, else empty
    %(date)s       Date using Logger.date_format, see time module
    %(domain)s     Full Domain: %(module)s.%(class)s.%(function)s
    %(file)s       Filename of the module
    %(function)s   Function name, empty in __main__
    %(label)s      Label according to log function call from Logger.label
    %(level)d      Internal logging level
    %(line)d       Line number in module
    %(module)s     Module name
    %(message)s    Log message

    Standard levels:

    FATAL                 Fatal error messages
    ERROR                 Error messages
    WARNING               Warning messages
    INFOx, x in [1..5]    Information
    DEBUGy, y in [1..10]  Debug messages
    NO_INFO               No info output
    NO_DEBUG              No debug output
    INFO_MAX              Maximum info level
    DEBUG_MAX             Maximum debug level

    x and y depend on info_max and debug_max from Logger class
    initialization. See __init__ function.

    Default logging targets:

    stdout        Logs to stdout
    stderr        Logs to stderr
    syslog        Logs to syslog

    Additional arguments for logging functions (fatal, error, warning, info
    and debug):

    nl       Disable newline at the end with nl=0, default is nl=1.
    fmt      Format string for this logging entry, overloads global format
             string. Example: fmt="%(file)s:%(line)d %(message)s"
    nofmt    Only output message with nofmt=1. The nofmt argument wins over
             the fmt argument.

    Example:

    from logger import log
    log.setInfoLogLevel(log.INFO1)
    log.setDebugLogLevel(log.DEBUG1)
    for i in range(1, log.INFO_MAX+1):
        log.setInfoLogLabel(i, "INFO%d: " % i)
    log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: "
                  "%(level)d %(message)s")
    log.setDateFormat("%Y-%m-%d %H:%M:%S")

    fl = FileLog("/tmp/log", "a")
    log.addInfoLogging("*", fl)
    log.addDebugLogging("*", fl)
    log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s")

    log.debug3("debug3")
    log.debug2("debug2")
    log.debug1("debug1")
    log.info2("info2")
    log.info1("info1")
    log.warning("warning\n", nl=0)
    log.error("error\n", nl=0)
    log.fatal("fatal")
    log.info(log.INFO1, "nofmt info", nofmt=1)

    ����r#r�
cCs�i|_i|_d|_d|_i|_i|_i|_i|_i|_i|_	|dkrPt
d|��|dkrdt
d|��|j|_||_
d|_||_|j|jd�|j|jd�|j|jd�|j|jd�xNtd|j
d�D]:}t|d	||�|j|d�t|d
|dd�||��q�WxTtd|jd�D]@}t|d
||�|j|d|�t|d|dd�||���qW|j|j�|j|j�|jd�|jd�|jd|j|j|j|jg�|jd|jdd�t|j|j
d�D��|jd|jdd�td|jd�D��dS)z Logger class initialization �r#zLogger: info_max %d is too lowrzLogger: debug_max %d is too lowz
FATAL ERROR: zERROR: z	WARNING: zINFO%dzinfo%dcs��fdd�S)Ncs�j�|f|�|�S)N)�info)�message�args�kwargs)r�xrr	�<lambda> sz3Logger.__init__.<locals>.<lambda>.<locals>.<lambda>r)rrAr)rrAr	rBsz!Logger.__init__.<locals>.<lambda>zDEBUG%dz	DEBUG%d: zdebug%dcs��fdd�S)Ncs�j�|f|�|�S)N)�debug)r>r?r@)rrArr	rB)sz3Logger.__init__.<locals>.<lambda>.<locals>.<lambda>r)rrAr)rrAr	rB(sz%(label)s%(message)sz%d %b %Y %H:%M:%S�*cSsg|]}|�qSrr)�.0�irrr	�
<listcomp>4sz#Logger.__init__.<locals>.<listcomp>cSsg|]}|�qSrr)rErFrrr	rG6sN) �_level�_debug_level�_format�_date_format�_label�_debug_label�_logging�_debug_logging�_domains�_debug_domains�
ValueErrorr%�NO_INFO�INFO_MAX�NO_DEBUG�	DEBUG_MAX�setInfoLogLabelr'�	TRACEBACKr&�range�setattr�setDebugLogLabel�setInfoLogLevelr$�setDebugLogLevel�	setFormat�
setDateFormat�setInfoLoggingrr�setDebugLogging)rZinfo_maxZ	debug_maxrHrrr	r
�sX






zLogger.__init__cCsNxHt|j|jd�D]2}||jkr$qx |j|D]\}}}|j�q0WqWdS)z Close all logging targets r#N)rYr'rVrNr)rr
�dummy�targetrrr	r8s

zLogger.closerDcCs$|j|�||jkr|j|S|jS)z Get info log level. )�_checkDomainrH�NOTHING)r�domainrrr	�getInfoLogLevel@s


zLogger.getInfoLogLevelcCs8|j|�||jkr|j}||jkr*|j}||j|<dS)z% Set log level [NOTHING .. INFO_MAX] N)rdrerTrH)rr
rfrrr	r\Gs


zLogger.setInfoLogLevelcCs*|j|�||jkr$|j||jS|jS)z Get debug log level. )rdrIrU)rrfrrr	�getDebugLogLevelPs

zLogger.getDebugLogLevelcCs:|j|�|dkrd}||jkr&|j}||j|j|<dS)z- Set debug log level [NO_DEBUG .. DEBUG_MAX] rN)rdrVrUrI)rr
rfrrr	r]Ws

zLogger.setDebugLogLevelcCs|jS)N)rJ)rrrr	�	getFormat`szLogger.getFormatcCs
||_dS)N)rJ)rrJrrr	r^cszLogger.setFormatcCs|jS)N)rK)rrrr	�
getDateFormatfszLogger.getDateFormatcCs
||_dS)N)rK)rrJrrr	r_iszLogger.setDateFormatcCs:|j|�}x*|D]"}|j||j|jd�||j|<qWdS)zU Set log label for level. Level can be a single level or an array
        of levels. )�	min_level�	max_levelN)�
_getLevels�_checkLogLevelr'rTrL)rr
�label�levelsrrr	rWls




zLogger.setInfoLogLabelcCs>|j|dd�}x*|D]"}|j||j|jd�||j|<qWdS)zU Set log label for level. Level can be a single level or an array
        of levels. r#)r)rkrlN)rmrnr$rVrM)rr
rorprrr	r[us



zLogger.setDebugLogLabelNcCs|j||||dd�dS)z� Set info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r)rN)�_setLogging)rrfrcr
�fmtrrr	r`~szLogger.setInfoLoggingcCs|j||||dd�dS)z� Set debug log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r#)rN)rq)rrfrcr
rrrrr	ra�szLogger.setDebugLoggingcCs|j||||dd�dS)z� Add info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r)rN)�_addLogging)rrfrcr
rrrrr	�addInfoLogging�szLogger.addInfoLoggingcCs|j||||dd�dS)z� Add debg log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r#)rN)rs)rrfrcr
rrrrr	�addDebugLogging�szLogger.addDebugLoggingcCs|j||||dd�dS)z� Delete info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r)rN)�_delLogging)rrfrcr
rrrrr	�delInfoLogging�szLogger.delInfoLoggingcCs|j||||dd�dS)z� Delete debug log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. r#)rN)rv)rrfrcr
rrrrr	�delDebugLogging�szLogger.delDebugLoggingcCs|j|dd�S)zN Is there currently any info logging for this log level (and
        domain)? r)r)�_isLoggingHere)rr
rrr	�isInfoLoggingHere�szLogger.isInfoLoggingHerecCs|j|dd�S)zO Is there currently any debug logging for this log level (and
        domain)? r#)r)ry)rr
rrr	�isDebugLoggingHere�szLogger.isDebugLoggingHerecOs,|j|�d|d<|j|j|f|�|�dS)z Fatal error log. rrN)�_checkKWargs�_logr')rrJr?r@rrr	�fatal�s
zLogger.fatalcOs,|j|�d|d<|j|j|f|�|�dS)z Error log. rrN)r|r}r&)rrJr?r@rrr	�error�s
zLogger.errorcOs,|j|�d|d<|j|j|f|�|�dS)z Warning log. rrN)r|r}r%)rrJr?r@rrr	�warning�s
zLogger.warningcOsB|j|d|jd�|j|�d|d<|j||j|f|�|�dS)z� Information log using info level [1..info_max].
        There are additional infox functions according to info_max from
        __init__r#)rkrlrrN)rnrTr|r}rS)rr
rJr?r@rrr	r=�s
zLogger.infocOs<|j|d|jd�|j|�d|d<|j||f|�|�dS)z� Debug log using debug level [1..debug_max].
        There are additional debugx functions according to debug_max
        from __init__r#)rkrlrN)rnrVr|r})rr
rJr?r@rrr	rC�s
zLogger.debugcCs|j|jtj�gid�dS)N)r?r@)r}rX�	traceback�
format_exc)rrrr	�	exception�szLogger.exceptioncCs&||ks||kr"td|||f��dS)Nz*Level %d out of range, should be [%d..%d].)rR)rr
rkrlrrr	rn�szLogger._checkLogLevelcCs2|sdSx$|j�D]}|dkrtd|��qWdS)N�nlrr�nofmtz0Key '%s' is not allowed as argument for logging.)r�rrr�)�keysrR)rr@�keyrrr	r|�s
zLogger._checkKWargscCs|s|dkrtd|��dS)Nr<zDomain '%s' is not valid.)rR)rrfrrr	rd�szLogger._checkDomaincCs�||jkrft|t�st|t�r$|}n|g}xp|D]0}|rL|j|d|jd�q0|j||j|jd�q0Wn6|r�dd�t|j	|j�D�}ndd�t|j|j�D�}|S)z Generate log level array. r#)rkrlcSsg|]}|�qSrr)rErFrrr	rG�sz%Logger._getLevels.<locals>.<listcomp>cSsg|]}|�qSrr)rErFrrr	rG�s)
�ALL�
isinstance�list�tuplernrVr'rTrYZDEBUG1)rr
rrprrr	rm�s


zLogger._getLevelscCsNt|t�st|t�r|}n|g}x(|D] }t|jt�s&td|jj��q&W|S)z Generate target array. z '%s' is no valid logging target.)r�r�r��
issubclass�	__class__rrRr)rrc�targetsZ_targetrrr	�_getTargets�s
zLogger._getTargetscCs�|r |j}|j}d|jdf}n|j}|j}|j|jdf}t|�dkrP|j�xVt	|d|d�D]@}||krrqdx0||D]$\}}}||kr||j
|g�j|�q|WqdWdS)z% Generate dict with domain by level. r#rN)rQrOrVrPrNr'rTr)�clearrY�
setdefault�append)rrrPrNZ_ranger
rfrbrrr	�_genDomainsszLogger._genDomainsc	Csl|j|�|j||�}|j|�}|r,|j}n|j}x*|D]"}x|D]}|||fg||<qBWq8W|j|�dS)N)rdrmr�rOrNr�)	rrfrcr
rrrrpr�rNrrr	rqs



zLogger._setLoggingc	Cst|j|�|j||�}|j|�}|r,|j}n|j}x2|D]*}x$|D]}|j|g�j|||f�qBWq8W|j|�dS)N)rdrmr�rOrNr�r�r�)	rrfrcr
rrrrpr�rNrrr	rs-s



 zLogger._addLoggingc
Cs�|j|�|j||�}|j|�}|r,|j}n|j}x�|D]|}	xv|D]n}|	|krPqB|||f||	kr�||	j|||f�t||	�dkr�||	=qB||jkrBtd|	||j	j
|f��qBWq8W|j|�dS)NrzDNo mathing logging for level %d, domain %s, target %s and format %s.)rdrmr�rOrN�remover)r�rRr�rr�)
rrfrcr
rrrrpr�rNrHrrr	rv<s&




zLogger._delLoggingcCst|j||�}|sdS|dd}|r,|j}n|j}x<||D]0\}}}|dksh|j|�shtj|d|�r<dSq<WdS)NFrf�.rDT)�_genDictrOrNr0�fnmatch�fnmatchcase)rr
r�_dict�point_domainrNrfrbrrr	ryUs
zLogger._isLoggingHerec	Cs�|jjdkrD|jjd}||jkrD|j|}|j|j|j�}|rD|Stj|j�}|j}|j|j	kr�t
|j	|jd�r�|j	|jj|kr�dSxT|j	j�D]F\}}t
|tj�r�t
||j�r�t||j�}t
|tj�r�|j|kr�|Sq�WdS)z7 Function to get calling class. Returns class or None. rZ	func_codeN)�f_code�co_argcount�co_varnames�f_locals�
_getClass2r��inspectZ	getmodule�co_name�__dict__�hasattr�__code__�itemsr��typesZ	ClassType�getattr�FunctionType)	r�frameZselfname�_self�obj�module�coderb�valuerrr	�	_getClassis*


zLogger._getClasscCsVx,|jj�D]}t|tj�r|j|kr|SqWx"|jD]}|j||�}|r6|Sq6WdS)z@ Internal function to get calling class. Returns class or None. N)r��valuesr�r�r�r��	__bases__r�)rr�r�r��baseZ_objrrr	r��s
zLogger._getClass2cOsld}d|kr|d}d}d|kr(|d}d}d|kr<|d}|j||�}|sPdSt|�dkrj|||d<n&t|�dkr�||d|d<n||d<|dd}	|r�|j}
n|j}
g}x�|
|D]�\}}
}|
|kr�q�|d	ks�|	j|d�s�tj|d|�r�|�s|j}d
|k�r|d
}|�r0|
j|d|||�n|
j|||||�|�rZ|
jd|||�|j	|
�q�WdS)Nrrr#r�r�r>rfr�rDrrr")
r�r)rOrNr0r�r�rJrr�)rr
rJr?r@rr�r�r�r�rNZused_targetsrfrcrrr	r}�sL
zLogger._logcCsg}d}|r |j}|j}|j}n|j}|j}|j}xN|D]F}|dkrh|||kr~d}t|�dkrdg}Pq8|||kr8|j|�q8W|r�t|�dkr�dS||kr�dStj	�}	x$|	r�|	j
r�|	jd|jkr�|	j
}	q�W|	s�t
d��|	jd}
|
d	}x|D]}|j|�r�g}Pq�W|	j}t|
�}
xx||D]l}|jd�}|dk�rD�q&n|dk�r\|d|�}n|}|
t|�k�r�|
j|��s�dSn|j|
��s&dS�q&Wd
}||k�r�||}|j|	j|
d
|jd
||tj|jtj��d�	}|dd
k�r�d
|d<d}x&||D]}|dk�r�q�d}P�q�W|jjd�dk�sR|jjd�dk�sR|�sRt|�dk�rl|j|	�}|�rl|j|d<d
|d|d<|dd
k�r�|dd	|d7<|dd
k�r�|dd	|d7<t|�dk�r�|S|dd	}x0|D](}|j|��stj|d|��r�|S�q�WdS)z Internal function. FrDTrr#Nrz Frame information not available.r�r<)	�file�liner��class�functionrfror
Zdater��?z	%(domain)z%(class)r�r�rf)rIrQrMrHrPrLr)r�r�Zcurrentframe�f_back�	f_globalsrrRr0r��find�co_filename�f_linenor��timeZstrftimerKZ	localtimerJr�rr�r�)rr
rZ
check_domainsZsimple_matchr�rPrLrf�fZmodule_nameZpoint_module�co�_lenrF�dZ	level_strZ
domain_neededr�r�rrr	r��s�














zLogger._genDict���������������)r7r;)rD)rD)rD)rD)r)r)r)r)8rrrrr�rer'rXr&r%rrrrrrr
rrgr\rhr]rir^rjr_rWr[r`rartrurwrxrzr{r~rr�r=rCr�rnr|rdrmr�r�rqrsrvryr�r�r}r�rrrr	r�sdG
;

	

					


 4)�__all__rr�r�r�r�rr�r5Zos.pathr�objectrrrrrrrrrrr	�<module>s.-(*4__pycache__/fw_service.cpython-36.opt-1.pyc000064400000003201151731527020014474 0ustar003

��gg�@s2dgZddlmZddlmZGdd�de�ZdS)�FirewallService�)�errors)�
FirewallErrorc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCs||_i|_dS)N)Z_fw�	_services)�self�fw�r� /usr/lib/python3.6/fw_service.py�__init__szFirewallService.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rrrr	�__repr__ szFirewallService.__repr__cCs|jj�dS)N)r�clear)rrrr	�cleanup#szFirewallService.cleanupcCst|jj��S)N)�sortedr�keys)rrrr	�get_services(szFirewallService.get_servicescCs||jkrttj|��dS)N)rrrZINVALID_SERVICE)r�servicerrr	�
check_service+s
zFirewallService.check_servicecCs|j|�|j|S)N)rr)rrrrr	�get_service/s
zFirewallService.get_servicecCs||j|j<dS)N)r�name)r�objrrr	�add_service3szFirewallService.add_servicecCs|j|�|j|=dS)N)rr)rrrrr	�remove_service6s
zFirewallService.remove_serviceN)�__name__�
__module__�__qualname__r
rrrrrrrrrrr	rsN)�__all__ZfirewallrZfirewall.errorsr�objectrrrrr	�<module>s__pycache__/nftables.cpython-36.pyc000064400000130376151731527020013215 0ustar003

��g��%@slddlmZddlZddlZddlZddlmZddlmZm	Z	m
Z
mZmZddl
mZmZmZmZmZmZmZddlmZmZmZmZmZmZmZddlmZdZed	d
Z dZ!dZ"id
ddCe"fiddDe"fdde"fd�dde"fdde"fdde"fdde"fd�d�Z#dEdd�Z$e$ddd�e$dd�e$dd�e$dd�e$ddd�e$ddd �e$ddd�e$dd!d"�e$ddd#�e$ddd"�e$dd$d"�e$ddd%�e$dd!d�e$ddd&�e$ddd�e$dd$�e$ddd'�e$ddd(�e$ddd)�e$dd!�e$dd$d"�e$dd*�e$dd+�e$dd,�e$ddd-�e$dd.�e$dd/�e$dd0�e$dd!d'�e$ddd1�e$dd!d)�e$ddd2�e$dd.d"�e$dd.d�d3�"e$d4dd'�e$d4d$d�e$d4dd)�e$d4dd"�e$d4d�e$d4d�e$d4d�e$d4dd-�e$d4d5�e$d4d6�e$d4d7�e$d4d8�e$d4d9�e$d4d:�e$d4dd�e$d4d;�e$d4d$�e$d4dd�e$d4d<�e$d4dd&�e$d4d=�e$d4d>�e$d4d.�e$d4d.d"�e$d4d.d�e$d4d$d"�e$d4d$d)�d?�d@�Z%GdAdB�dBe&�Z'dS)F�)�absolute_importN)�log)�	check_mac�getPortRange�normalizeIP6�check_single_address�
check_address)�
FirewallError�
UNKNOWN_ERROR�INVALID_RULE�INVALID_ICMPTYPE�INVALID_TYPE�
INVALID_ENTRY�INVALID_PORT)�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�Rich_Masquerade�Rich_ForwardPort�Rich_IcmpBlock)�NftablesZ	firewalld�_Zpolicy_dropZpolicy_�
�
PREROUTING�
prerouting��dZpostrouting)r�POSTROUTING�input�forward�output)r�INPUT�FORWARD�OUTPUT)�raw�mangle�nat�filtercCsHdd|dd�id|d�ig}|dk	rD|jdd|dd�id|d�i�|S)N�match�payload�type)�protocol�fieldz==)�left�op�right�code)�append)r,r+r1�	fragments�r4�/usr/lib/python3.6/nftables.py�_icmp_types_fragmentsSsr6�icmpzdestination-unreachable�
z
echo-replyzecho-request���redirect��zparameter-problem�����zrouter-advertisementzrouter-solicitationz
source-quench�z
time-exceededztimestamp-replyztimestamp-request��)"zcommunication-prohibitedzdestination-unreachablez
echo-replyzecho-requestzfragmentation-neededzhost-precedence-violationzhost-prohibitedz
host-redirectzhost-unknownzhost-unreachablez
ip-header-badznetwork-prohibitedznetwork-redirectznetwork-unknownznetwork-unreachablezparameter-problemzport-unreachablezprecedence-cutoffzprotocol-unreachabler;zrequired-option-missingzrouter-advertisementzrouter-solicitationz
source-quenchzsource-route-failedz
time-exceededztimestamp-replyztimestamp-requestztos-host-redirectztos-host-unreachableztos-network-redirectztos-network-unreachablezttl-zero-during-reassemblyzttl-zero-during-transit�icmpv6zmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportznd-neighbor-advertznd-neighbor-solicitzpacket-too-bigznd-redirectznd-router-advertznd-router-solicit)zaddress-unreachablez
bad-headerzbeyond-scopezcommunication-prohibitedzdestination-unreachablez
echo-replyzecho-requestz
failed-policyzmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportzneighbour-advertisementzneighbour-solicitationzno-routezpacket-too-bigzparameter-problemzport-unreachabler;zreject-routezrouter-advertisementzrouter-solicitationz
time-exceededzttl-zero-during-reassemblyzttl-zero-during-transitzunknown-header-typezunknown-option)�ipv4�ipv6c@s`eZdZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Z	dd
�Z
dd�Zd�dd�Zdd�Z
dd�Zdd�Zdd�Zd�dd�Zdd�Zd�d d!�Zd"d#�Zd�d%d&�Zd�d(d)�Zd�d*d+�Zd�d,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Z d>d?�Z!d@dA�Z"dBdC�Z#dDdE�Z$dFdG�Z%dHdI�Z&d�dJdK�Z'dLdM�Z(dNdO�Z)dPdQ�Z*dRdS�Z+d�dTdU�Z,d�dVdW�Z-d�dXdY�Z.dZd[�Z/d�d\d]�Z0d�d^d_�Z1d�d`da�Z2d�dbdc�Z3d�ddde�Z4dfdg�Z5d�dhdi�Z6djdk�Z7d�dldm�Z8dndo�Z9dpdq�Z:drds�Z;dtdu�Z<d�dvdw�Z=d�dxdy�Z>dzd{�Z?d�d|d}�Z@d~d�ZAd�d��ZBd�d��ZCd�d��ZDd�d��ZEd�d��ZFd�d��ZGd�d�d��ZHdS)��nftablesTcCsb||_d|_g|_i|_i|_i|_i|_i|_gggd�|_t	�|_
|j
jd�|j
jd�dS)NT)�inet�ip�ip6)
�_fwZrestore_command_existsZavailable_tables�rule_to_handle�rule_ref_count�rich_rule_priority_counts�policy_priority_counts�zone_source_index_cache�created_tablesrrIZset_echo_outputZset_handle_output)�self�fwr4r4r5�__init__�sznftables.__init__cCs�xdD]}||krPqWd||dkr`||ddd||dddf}||dd=n(d||dkr�d}||dd=ndS||dd	}|r�|dkr�||kr�|||kr�||j|�n�|dk�r�||kr�g||<|�r(|||k�r||j|�||jd
d�d�||j|�}n|jj�r8d
}nt||�}||}||=|d
k�rf||d<n |d8}||d<||ddd<dS)N�add�insert�deletez%%ZONE_SOURCE%%�rule�zone�addressz%%ZONE_INTERFACE%%�familycSs|dS)Nrr4)�xr4r4r5�<lambda>�sz3nftables._run_replace_zone_source.<locals>.<lambda>)�keyrr<�index)rWrXrY)�remover2�sortrarM�_allow_zone_drifting�len)rTrZrR�verbZzone_sourcer]ra�
_verb_snippetr4r4r5�_run_replace_zone_source�sD




z!nftables._run_replace_zone_sourcecCsBd|krdtj|d�iSd|kr4dtj|d�iSttd��dS)NrXrYrWzFailed to reverse rule)�copy�deepcopyr	r
)rT�dictr4r4r5�reverse_rule�s
znftables.reverse_rulec
Cs�xdD]}||krPqW|||dk�r�||d|}||d|=t|�tkr^ttd��||dd||ddf}|dkr�||ks�|||ks�|||dkr�ttd	��|||d
8<n�||kr�i||<|||kr�d|||<d}xVt||j��D]B}||k�r"|dk�r"P||||7}||k�r|dk�rP�qW|||d
7<||}	||=|dk�r�|	|d<n |d
8}|	|d<||ddd<dS)
NrWrXrYrZz%priority must be followed by a numberr]�chainrz*nonexistent or underflow of priority countr<ra)rWrXrY)r+�intr	rr
�sorted�keys)
rTrZZpriority_counts�tokenrf�priorityrmra�prgr4r4r5�_set_rule_replace_priority�sD

 


z#nftables._set_rule_replace_prioritycCsfx`d
D]X}||krd||krtj||d�}xdD]}||kr6||=q6Wtj|dd	�}|SqWdS)NrWrXrYrZra�handle�positionT)Z	sort_keys)rWrXrY)rarurv)rirj�json�dumps)rTrZrf�rule_keyZnon_keyr4r4r5�
_get_rule_keys


znftables._get_rule_keycCsLdddddg}dddg}g}g}tj|j�}tj|j�}tj|j�}	|jj�}
�x�|D�]�}t|�tkrvtt	d|��x|D]}||kr|Pq|W||kr�tt
d|��|j|�}
|
|
k�rDtj
d|j|
|
|
�|dkr�|
|
d	7<qVnX|
|
d	k�r|
|
d	8<qVn6|
|
d	k�r,|
|
d	8<ntt	d
|
|
|
f��n|
�r\|dk�r\d	|
|
<|j|�tj|�}|
�rttd||dd��||dd<|j||d
�|j||d�|j||	�|dk�rdd|ddd|ddd|ddd|j|
d�ii}|j|�qVWdddd	iig|i}tj�dk�rVtjd|jtj|��|jj|�\}}}|dk�r�tdd|tj|�f��||_||_|	|_|
|_d}x�|D]�}|d	7}|j|�}
|
�s̐q�d|k�r�|j|
=|j|
=�q�x"|D]}||d|k�r�P�q�W||d|k�r$�q�|d||dd|j|
<�q�WdS)NrWrXrY�flush�replacez#rule must be a dictionary, rule: %szno valid verb found, rule: %sz%s: prev rule ref cnt %d, %sr<z)rule ref count bug: rule_key '%s', cnt %drZ�exprz%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r]�tablerm)r]r~rmrurIZmetainfoZjson_schema_versionr@z.%s: calling python-nftables with JSON blob: %srz'%s' failed: %s
JSON blob:
%szpython-nftablesru)rirjrPrQrRrOr+rkr	r
rrzrZdebug2�	__class__r2�listr(rtrhrNZgetDebugLogLevelZdebug3rwrxrIZjson_cmd�
ValueError)rT�rules�
log_deniedZ_valid_verbsZ_valid_add_verbsZ_deduplicated_rulesZ_executed_rulesrPrQrRrOrZrfryZ_ruleZ	json_blobZrcr!�errorrar4r4r5�	set_rules+s�







&






znftables.set_rulescCs|j|g|�dS)N�)r�)rTrZr�r4r4r5�set_rule�sznftables.set_ruleNcCs|r
|gStj�S)N)�IPTABLES_TO_NFT_HOOKrp)rTr~r4r4r5�get_available_tables�sznftables.get_available_tablescCsFg}x<dD]4}|jdd||d�ii�|jdd||d�ii�q
W|S)	NrJrKrLrWr~)r]�namerY)rJrKrL)r2)rTr~r�r]r4r4r5�_build_delete_table_rules�s


z"nftables._build_delete_table_rulescCs�i}i}xB|jd�D]4}|j|�}||jkr|j|||<|j|||<qW||_||_i|_i|_i|_x*dD]"}t|j|krp|j|j	t�qpW|j
t�S)NTrJrKrL)rJrKrL)� _build_set_policy_rules_ct_rulesrzrNrOrPrQrR�
TABLE_NAMErSrbr�)rTZsaved_rule_to_handleZsaved_rule_ref_countrZ�
policy_keyr]r4r4r5�build_flush_rules�s 


znftables.build_flush_rulesc
Cslddd�|}g}xTdD]L}|j|ddtd	d
|fddd
diiddddgid�iddigd�ii�qW|S)NrWrY)TFrr r!rZrJz%s_%sr(r)�ctr`�state�in�set�established�related)r.r/r0�accept)r]r~rmr})rr r!)r2�TABLE_NAME_POLICY)rT�enable�add_delr��hookr4r4r5r��s


z)nftables._build_set_policy_rules_ct_rulescCstg}|dkrt|jdddtd�ii�|jdjt�x>dD]6}|jdddtd	d
|fd|dtd
dd�ii�q:W|dk�r�|jdddtd�ii�|jdjt�x>dD]6}|jdddtd	d|fd|dtd
dd�ii�q�W||jd�7}nz|dk�rfx4|jd�D]&}|j|�}||jk�r|j|��qW||jt�7}t|jdk�rp|jdjt�n
t	t
d�|S)NZPANICrWr~rJ)r]r�rr!rmz%s_%sr%r(i,r<�drop)r]r~r�r+r��prio�policy�DROPrr rT�ACCEPTFznot implemented)rr!i���)rr r!)r2r�rS�NFT_HOOK_OFFSETr�rzrNr�rbr	r
)rTr�r�r�rZr�r4r4r5�build_set_policy_rules�sH













znftables.build_set_policy_rulescCs<t�}x,|r|gntj�D]}|jt|j��qWt|�S)N)r��ICMP_TYPES_FRAGMENTSrp�updater�)rT�ipvZ	supportedZ_ipvr4r4r5�supported_icmp_types�sznftables.supported_icmp_typescCs>g}x4dD],}|jdd|td�ii�|j|jt�q
W|S)NrJrKrLrWr~)r]r�)rJrKrL)r2r�rS)rTZdefault_tablesr]r4r4r5�build_default_tabless

znftables.build_default_tables�offcCs�g}x�tdj�D]�}|jdddtd|ddtd|dtd|d	d
�ii�xz|jjrlddd
dgndd
dgD]X}|jdddtd||fd�ii�|jdddtd|ddd||fiigd�ii�qvWqWx�d?D]�}x�tdj�D]�}|jdd|td|ddtd|dtd|d	d
�ii�x~|jj�rJddd
dgndd
dgD]Z}|jdd|td||fd�ii�|jdd|td|ddd||fiigd�ii��qTWq�Wq�WxVtdj�D]F}|jdddtd|ddtd|dtd|d	d
�ii��q�W|jdddtddddddiid d!d"d#gid$�id%digd�ii�|jdddtdddddd&iid d'd$�id%digd�ii�|jdddtdddd(dd)iid*d+d$�id%digd�ii�x~|jj�r�ddd
dgndd
dgD]Z}|jdddtd,d|fd�ii�|jdddtddddd,d|fiigd�ii��q�W|d-k�r�|jdddtddddddiid d!d.gid$�i|j|�d/d0d1iigd�ii�|jdddtddddddiid d!d.gid$�id2digd�ii�|d-k�r$|jdddtdd|j|�d/d0d3iigd�ii�|jdddtddd4d5d6d7�igd�ii�|jdddtdd8ddddiid d!d"d#gid$�id%digd�ii�|jdddtdd8dddd&iid d'd$�id%digd�ii�|jdddtdd8dd(dd)iid*d+d$�id%digd�ii�xbd@D]Z}|jdddtd,d8|fd�ii�|jdddtdd8ddd,d8|fiigd�ii��qWx�dAD]�}xz|jj�r�dd
gnd
gD]^}|jdddtd;d8||fd�ii�|jdddtdd8ddd;d8||fiigd�ii��q�W�qvWxbdBD]Z}|jdddtd,d8|fd�ii�|jdddtdd8ddd,d8|fiigd�ii��qW|d-k�r�|jdddtdd8ddddiid d!d.gid$�i|j|�d/d0d1iigd�ii�|jdddtdd8ddddiid d!d.gid$�id2digd�ii�|d-k�r6|jdddtdd8|j|�d/d0d3iigd�ii�|jdddtdd8d4d5d6d7�igd�ii�|jdddtdd<ddddiid d!d"d#gid$�id%digd�ii�|jdddtd=dd(dd>iid*d+d$�id%digd�ii�xbdCD]Z}|jdddtd,d<|fd�ii�|jdddtdd<ddd,d<|fiigd�ii��q�WxbdDD]Z}|jdddtd,d<|fd�ii�|jdddtdd<ddd,d<|fiigd�ii��qHW|S)ENr&rWrmrJz	mangle_%sr(z%srr<)r]r~r�r+r�r��POLICIES_preZZONES_SOURCEZZONES�
POLICIES_postzmangle_%s_%s)r]r~r�rZ�jump�target)r]r~rmr}rKrLr'znat_%sz	nat_%s_%sz	filter_%sr"r)r�r`r�r�r�r�r�)r.r/r0r�Zstatus�dnat�meta�iifnamez==�lozfilter_%s_%sr�Zinvalidr�prefixzSTATE_INVALID_DROP: r�zFINAL_REJECT: �reject�icmpxzadmin-prohibited)r+r}r#�IN�OUTzfilter_%s_%s_%sr$�
filter_OUTPUT�oifname)rKrL)r�)r�r�)r�)r�)r�)r�rpr2r�rMrd�_pkttype_match_fragment)rTr�Z
default_rulesrmZdispatch_suffixr]�	directionr4r4r5�build_default_ruless�
$

(

&

.
 


&

&











&


.


&










&


&znftables.build_default_rulescCs4|dkrdddgS|dkr dgS|dkr0ddgSgS)	Nr(r"�
FORWARD_IN�FORWARD_OUTr&rr'rr4)rTr~r4r4r5�get_zone_table_chains�s
znftables.get_zone_table_chainsrJc
s��dkr\�dkr\g}
|
j�j�|��||||dd�	�|
j�j�|��||||dd�	�|
S�jjj|���jdkrxdnd��dkr��d	kr�d
nd}�jjj|�t|��g}g}
|r�|jdd
ddiiddt	|�id�i�|�r|
jdd
ddiiddt	|�id�i�ddd�}|�rlxT|D]L}�dk�rT�jj
j|�}||k�rT�||k�rT�q|j�jd|���qW|�r�xT|D]L}�dk�r��jj
j|�}||k�r��||k�r��qx|
j�jd|���qxW��������fdd�}g}
|�rHx�|D]P}|
�rxB|
D]}|
j|||���qWn"�dk�r0|�r0n|
j||d���q�Wn\�dk�rZ|�rZnJ|
�r�xB|
D]}|
j|d|���qfWn"�dk�r�|�r�n|
j|dd��|
S)Nr'rJrK)r]rLr�pre�postrTFr)r�r`r�z==r�)r.r/r0r�)rGrH�saddr�daddrcs�g}|r|j|�|r |j|�|jddd��fii��td���f|d�}|j�j����rrdd|iiSdd|iiSdS)	Nr�r�z%s_%sz%s_%s_POLICIES_%s)r]r~rmr}rWrZrY)r2r�r��_policy_priority_fragment)�ingress_fragment�egress_fragment�expr_fragmentsrZ)�_policyrm�chain_suffixr�r]�p_objrTr~r4r5�_generate_policy_dispatch_rules

zRnftables.build_policy_ingress_egress_rules.<locals>._generate_policy_dispatch_rule)
�extend�!build_policy_ingress_egress_rulesrMr�Z
get_policyrr�policy_base_chain_name�POLICY_CHAIN_PREFIXr2r�r[Zcheck_source�_rule_addr_fragment)rTr�r�r~rmZingress_interfacesZegress_interfacesZingress_sourcesZegress_sourcesr]r��isSNATZingress_fragmentsZegress_fragmentsZ
ipv_to_family�srcr��dstr�r�r�r4)r�rmr�r�r]r�rTr~r5r��sv









z*nftables.build_policy_ingress_egress_rulesFc	
Cs�|dkrT|dkrTg}	|	j|j|||||||d��|	j|j|||||||d��|	S|dkrh|dkrhdnd}
|jjj||t|
d�}d	d
d	d	d
d
d�|}|t|�dd
kr�|dt|�d�d}d}
|dkr�|
dd||fiig}n,ddd|iid|d�i|
dd||fiig}|�rL|�rLd}|td||f|d�}|j|j	��nP|�rnd}|td||f|d�}n.d}|td||f|d�}|�s�|j|j	��|d|iigS)Nr'rJrKrLrTF)r�r�r�)rrr"r�r�r$r<�+�*�gotor�z%s_%sr)r�r`z==)r.r/r0rXz%s_%s_ZONES)r]r~rmr}rWrYrZ)
r��!build_zone_source_interface_rulesrMr�r�r�rer�r��_zone_interface_fragment)rTr�r[r��	interfacer~rmr2r]r�r�r��opt�actionr�rfrZr4r4r5r�Qs\



z*nftables.build_zone_source_interface_rulesc	Csn|dkr�|dkr�g}|jd�r6|j|td�d��}	nd}	td|�sTt|�sT|	dkrp|j|j||||||d��td|�s�t|�s�|	dkr�|j|j||||||d��|S|dkr�|dkr�d	nd
}
|jjj	||t
|
d�}dd
d�|}ddddddd�|}
|jj�rd||f}nd||f}d}|t||j
|
|�|dd||fiigd�}|j|j||��|d|iigS)Nr'rJzipset:rGrKrHrLrTF)r�rXrY)TFr�r�)rrr"r�r�r$z%s_%s_ZONES_SOURCEz%s_%s_ZONESr�r�z%s_%s)r]r~rmr}rZ)�
startswith�_set_get_familyrerrr��build_zone_source_address_rulesrMr�r�r�rdr�r�r��_zone_source_fragment)rTr�r[r�r\r~rmr]r�Zipset_familyr�r�r�r�Zzone_dispatch_chainr�rZr4r4r5r��sB


z(nftables.build_zone_source_address_rulesc
Cs|dkrH|dkrHg}|j|j||||d��|j|j||||d��|Sddd�|}|dkrj|dkrjd	nd
}|jjj||t|d�}	g}|j|d|td
||	fd�ii�x0d!D](}
|j|d|td||	|
fd�ii�q�WxDd"D]<}
|j|d|td
||	fddd||	|
fiigd�ii�q�W|jjj|j	}|jj
�dk�r�|dk�r�|d#k�r�|}|dk�rhd}|j|d|td
||	f|j|jj
��ddd|	|fiigd�ii�|dk�r|d$k�r|d%k�r�|j�}
n|j
�di}
|j|d|td
||	f|
gd�ii�|�s|j�|S)&Nr'rJrKrLrWrY)TFrTF)r�rmz%s_%s)r]r~r�r�r�deny�allowr�z%s_%s_%srZr�r�)r]r~rmr}r�r(�REJECT�
%%REJECT%%r�r�z"filter_%s_%s: "r�)r�rr�r�r�)r�rr�r�r�)r�r�r�)r�r�r�r�)r�r�)r��build_policy_chain_rulesrMr�r�r�r2r�Z	_policiesr��get_log_deniedr��_reject_fragment�lower�reverse)rTr�r�r~rmr]r�r�r�r�r�r�Z
log_suffix�target_fragmentr4r4r5r��sZ





&




 





z!nftables.build_policy_chain_rulescCs<|dkriS|dkr,ddddiid	|d
�iSttd|��dS)
N�all�unicast�	broadcast�	multicastr)r�r`�pkttypez==)r.r/r0zInvalid pkttype "%s")r�r�r�)r	r)rTr�r4r4r5r��s
z nftables._pkttype_match_fragmentcCsdddd�idddd�idddd�idddd�idddd�idddd�idddd�idddd�idddd�idddd�iddd	d�iddd	d�iddd
d�iddd
d�iddd
d�idddd�idddd�iddd
d�iddd
d�idddd�idddd�idddiidddiid�}||S)Nr�r7zhost-prohibited)r+r}znet-prohibitedzadmin-prohibitedrFznet-unreachablezhost-unreachablezport-unreachabler�zprot-unreachablezaddr-unreachablezno-router+z	tcp reset)zicmp-host-prohibitedzhost-prohibzicmp-net-prohibitedz
net-prohibzicmp-admin-prohibitedzadmin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp-net-unreachableznet-unreachzicmp-host-unreachablezhost-unreachzicmp-port-unreachablezicmp6-port-unreachablezport-unreachzicmp-proto-unreachablez
proto-unreachzicmp6-addr-unreachablezaddr-unreachzicmp6-no-routezno-routez	tcp-resetztcp-rstr4)rTZreject_typeZfragsr4r4r5�_reject_types_fragment�s0
znftables._reject_types_fragmentcCsdddd�iS)Nr�r�zadmin-prohibited)r+r}r4)rTr4r4r5r�sznftables._reject_fragmentcCs ddddiiddddgid	�iS)
Nr)r�r`�l4protoz==r�r7rF)r.r/r0r4)rTr4r4r5�_icmp_match_fragment"sznftables._icmp_match_fragmentcCsP|siSddddd�}|j�\}}|||d�}|j�}|dk	rH||d<d|iS)	N�secondZminuteZhourZday)�s�m�h�d)�rateZper�burst�limit)Zvalue_parseZburst_parse)rTr�Zrich_to_nftr�Zdurationr�r�r4r4r5�_rich_rule_limit_fragment'sz"nftables._rich_rule_limit_fragmentcCs�t|j�tttgkrn<|jrHt|j�tttt	gkrRt
tdt|j���n
t
td��|jdkr�t|j�ttgks�t|j�tt	gkr�dSt|j�tgks�t|j�ttgkr�dSn|jdkr�dSdSdS)NzUnknown action %szNo rule action specified.rr�r�r�r�)
r+�elementrrrr�rrrrr	rrr)rT�	rich_ruler4r4r5�_rich_rule_chain_suffix?s 


z nftables._rich_rule_chain_suffixcCs>|jr|jrttd��|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrr�r�)r�auditr	rrr)rTr�r4r4r5� _rich_rule_chain_suffix_from_logUs


z)nftables._rich_rule_chain_suffix_from_logcCsddiS)Nz%%ZONE_INTERFACE%%r4)rTr4r4r5r�`sz!nftables._zone_interface_fragmentcCsNtd|�rt|�}n,td|�r@|jd�}t|d�d|d}d||d�iS)NrH�/rr<z%%ZONE_SOURCE%%)r[r\)rrr�split)rTr[r\Z
addr_splitr4r4r5r�cs



znftables._zone_source_fragmentcCs
d|jiS)Nz%%POLICY_PRIORITY%%)rr)rTr�r4r4r5r�ksz"nftables._policy_priority_fragmentcCs|s|jdkriSd|jiS)Nrz%%RICH_RULE_PRIORITY%%)rr)rTr�r4r4r5�_rich_rule_priority_fragmentnsz%nftables._rich_rule_priority_fragmentcCs�|js
iS|jjj||t�}ddd�|}|j|�}i}	|jjrPd|jj|	d<|jjr|d|jjkrhdn|jj}
d|
|	d<d	td
|||f||j	|jj
�d|	igd�}|j|j|��|d
|iiS)NrWrY)TFz%sr�Zwarning�warn�levelrJz%s_%s_%sr)r]r~rmr}rZ)
rrMr�r�r�r�r�rr�r�r�r�r�)rTr�r�r�r~r�r�r�r�Zlog_optionsrrZr4r4r5�_rich_rule_logss&
znftables._rich_rule_logc
Cs�|js
iS|jjj||t�}ddd�|}|j|�}dtd|||f||j|jj�dddiigd	�}	|	j	|j
|��|d
|	iiS)NrWrY)TFrJz%s_%s_%srrr�)r]r~rmr}rZ)r�rMr�r�r�r�r�r�r�r�r�)
rTr�r�r�r~r�r�r�r�rZr4r4r5�_rich_rule_audit�s
znftables._rich_rule_auditc
Cs�|js
iS|jjj||t�}ddd�|}|j|�}d|||f}	t|j�tkr\ddi}
�nt|j�tkr�|jjr�|j	|jj�}
nddi}
n�t|j�t
kr�ddi}
n�t|j�tk�rHd}|jjj||t�}d|||f}	|jjj
d	�}t|�d
k�r,dddd
iiddddd
ii|d
gi|dgid�i}
ndddd
ii|dd�i}
nttdt|j���dt|	||j|jj�|
gd�}|j|j|��|d|iiS)NrWrY)TFz%s_%s_%sr�r�r�r&r�r<r�r`�mark�^�&r)r`�valuezUnknown action %srJ)r]r~rmr}rZ)r�rMr�r�r�r�r+rrr�rrr�r�rer	rr�r�r�r�r�)
rTr�r�r�r~r�r�r�r�rmZrule_actionrrZr4r4r5�_rich_rule_action�sB


,znftables._rich_rule_actioncCs�|jd�r0|j|td�d�d|kr(dnd|�St|�r>d}n�td|�rNd}nvtd|�r�d}tj|dd�}d	|jj	|j
d
�i}nDtd|�r�d}t|�}n,d}|jd
�}d	t|d�t
|d�d
�i}dd||d�i|r�dnd|d�iSdS)Nzipset:r�TF�etherrGrK)�strictr�)�addrrerHrLr�rr<r)r*)r,r-z!=z==)r.r/r0)r��_set_match_fragmentrerrr�	ipaddressZIPv4NetworkZnetwork_addressZ
compressedZ	prefixlenrr�rn)rTZ
addr_fieldr\�invertr]Znormalized_addressZaddr_lenr4r4r5r��s(
&





znftables._rule_addr_fragmentcCs6|siS|d
krttd|��ddddiid|d	�iS)NrGrHzInvalid familyr)r�r`�nfprotoz==)r.r/r0)rGrH)r	r)rTZrich_familyr4r4r5�_rich_rule_family_fragment�s
z#nftables._rich_rule_family_fragmentcCs8|siS|jr|j}n|jr&d|j}|jd||jd�S)Nzipset:r�)r)r�ipsetr�r)rTZ	rich_destr\r4r4r5�_rich_rule_destination_fragment�s
z(nftables._rich_rule_destination_fragmentcCsZ|siS|jr|j}n2t|d�r.|jr.|j}nt|d�rH|jrHd|j}|jd||jd�S)N�macrzipset:r�)r)r�hasattrrrr�r)rTZrich_sourcer\r4r4r5�_rich_rule_source_fragment�s
z#nftables._rich_rule_source_fragmentcCsPt|�}t|t�r$|dkr$tt��n(t|�dkr8|dSd|d|dgiSdS)Nrr<�range)r�
isinstancernr	rre)rT�portrr4r4r5�_port_fragments
znftables._port_fragmentc	Csbddd�|}d}|jjj||t�}	g}
|r>|
j|j|j��|rT|
j|jd|��|r||
j|j|j	��|
j|j
|j��|
jdd|dd	�id
|j|�d�i�|s�t
|j�tkr�|
jddd
diiddddgid�i�g}|�r0|j|j|||||
��|j|j|||||
��|j|j|||||
��n.|j|ddtd||	f|
ddigd�ii�|S)NrWrY)TFr(r�r)r*�dport)r,r-z==)r.r/r0r�r`r�r�r��new�	untrackedrZrJz%s_%s_allowr�)r]r~rmr})rMr�r�r�r2rr]r�r�destinationr�sourcerr+r�rrrrr�)rTr�r��protorrr�r�r~r�r�r�r4r4r5�build_policy_ports_ruless:


z!nftables.build_policy_ports_rulesc	CsZddd�|}d}|jjj||t�}g}	|r>|	j|j|j��|rT|	j|jd|��|r||	j|j|j	��|	j|j
|j��|	jdddd	iid
|d�i�|s�t|j
�tkr�|	jdddd
iiddddgid�i�g}
|�r(|
j|j|||||	��|
j|j|||||	��|
j|j|||||	��n.|
j|ddtd||f|	ddigd�ii�|
S)NrWrY)TFr(r�r)r�r`r�z==)r.r/r0r�r�r�r�rrrZrJz%s_%s_allowr�)r]r~rmr})rMr�r�r�r2rr]r�rrrrr+r�rrrrr�)rTr�r�r,rr�r�r~r�r�r�r4r4r5�build_policy_protocol_rules2s8

z$nftables.build_policy_protocol_rulesc	Csbddd�|}d}|jjj||t�}	g}
|r>|
j|j|j��|rT|
j|jd|��|r||
j|j|j	��|
j|j
|j��|
jdd|dd	�id
|j|�d�i�|s�t
|j�tkr�|
jddd
diiddddgid�i�g}|�r0|j|j|||||
��|j|j|||||
��|j|j|||||
��n.|j|ddtd||	f|
ddigd�ii�|S)NrWrY)TFr(r�r)r*�sport)r,r-z==)r.r/r0r�r`r�r�r�rrrZrJz%s_%s_allowr�)r]r~rmr})rMr�r�r�r2rr]r�rrrrrr+r�rrrrr�)rTr�r�rrrr�r�r~r�r�r�r4r4r5�build_policy_source_ports_rulesUs:


z(nftables.build_policy_source_ports_rulesc
	Cs�d}|jjj||t�}	ddd�|}
g}|rR|jdddtd||f||d�ii�g}|rl|j|jd	|��|jd
d|dd
�id|j|�d�i�|jdd||fi�|j|
ddtd|	|d�ii�|S)Nr(rWrY)TFz	ct helperrJzhelper-%s-%s)r]r~r�r+r,r�r)r*r)r,r-z==)r.r/r0rZzfilter_%s_allow)r]r~rmr})rMr�r�r�r2r�r�r)
rTr�r�rrrZhelper_nameZmodule_short_namer~r�r�r�r�r4r4r5�build_policy_helper_ports_ruleszs.



z(nftables.build_policy_helper_ports_rulescCs�ddd�|}|jjj||t�}g}	|rv|t|�ddkrT|dt|�d�d}ddd	d
iid|d�id
dig}
n|jd|�d
dig}
dtd||
d�}|	j|d|ii�|	S)NrWrY)TFr<r�r�r)r�r`r�z==)r.r/r0r�r�rJzfilter_%s_allow)r]r~rmr}rZ)rMr�r�r�rer�r�r2)rTr�r[r�r~r�rr�r�r�r}rZr4r4r5�build_zone_forward_rules�s"z!nftables.build_zone_forward_rulesc	Cs�d}|jjj||tdd�}ddd�|}g}|r`|j|j|j��|j|j|j��|j	|�}	nd}	|t
d||	f|d	d
ddiid
dd�iddigd�}
|
j|j|��|d|
iigS)Nr'T)r�rWrY)TFr�z	nat_%s_%sr)r�r`r�z!=r�)r.r/r0Z
masquerade)r]r~rmr}rZ)
rMr�r�r�r2rrrrr�r�r�r�)rTr�r�r]r�r~r�r�r�r�rZr4r4r5�"_build_policy_masquerade_nat_rules�s&
z+nftables._build_policy_masquerade_nat_rulesc
Cs^g}|rD|jr|jdks,|jrDtd|jj�rD|j|j||d|��nV|r�|jrX|jdksl|jr�td|jj�r�|j|j||d|��n|j|j||d|��d}|jjj||t	�}ddd�|}g}|r�|j
|j|j��|j
|j
|j��|j|�}	nd	}	d
td||	f|dd
ddiiddddgid�iddigd�}
|
j|j|��|j
|d|
ii�|S)NrHrLrGrKr(rWrY)TFr�rJzfilter_%s_%sr)r�r`r�r�r�rr)r.r/r0r�)r]r~rmr}rZ)r]rrrr�r&rMr�r�r�r2rrrr�r�r�r�)rTr�r�r�r�r~r�r�r�r�rZr4r4r5�build_policy_masquerade_rules�s8
z&nftables.build_policy_masquerade_rulesc	Cs$d}	|jjj||	t�}
ddd�|}g}|r\|j|j|j��|j|j|j��|j	|�}
nd}
|jdd|dd	�id
|j
|�d�i�|r�td|�r�t|�}|r�|d
kr�|jd||j
|�d�i�q�|jdd|ii�n|jdd|j
|�ii�|t
d|
|
f|d�}|j|j|��|d|iigS)Nr'rWrY)TFr�r)r*r)r,r-z==)r.r/r0rHr�r�)rrrr;rz	nat_%s_%s)r]r~rmr}rZ)rMr�r�r�r2rrrrr�rrrr�r�r�)rTr�r�rr,�toaddr�toportr]r�r~r�r�r�r�rZr4r4r5�$_build_policy_forward_port_nat_rules�s4


z-nftables._build_policy_forward_port_nat_rulesc	
Cs�g}|rF|jr|jdks&|rFtd|�rF|j|j||||||d|��n�|r�|jrZ|jdksh|r�td|�r�|j|j||||||d|��nL|r�td|�r�|j|j||||||d|��n|j|j||||||d|��|S)NrHrLrGrK)r]rr�r*)	rTr�r�rr,r)r(r�r�r4r4r5�build_policy_forward_port_rulessz(nftables.build_policy_forward_port_rulescCs2|t|krt||Sttd||j|f��dS)Nz)ICMP type '%s' not supported by %s for %s)r�r	rr�)rTr�Z	icmp_typer4r4r5�_icmp_types_to_nft_fragments(sz%nftables._icmp_types_to_nft_fragmentscCsBd}|jjj||t�}ddd�|}|r6|jr6|j}n<|jrjg}d|jkrT|jd�d|jkrr|jd�nddg}g}	�x�|D�]�}
|jjj|�r�d||f}ddi}nd	||f}|j�}g}
|r�|
j|j	|j
��|
j|j|j��|
j|j|j
��|
j|j|
|j��|�r�|	j|j|||||
��|	j|j|||||
��|j�rf|	j|j|||||
��nN|j|�}d
td|||f|
|j�gd�}|j|j|��|	j|d
|ii�q~|jj�dk�r|jjj|��r|	j|d
d
t||
|j|jj��ddd||fiigd�ii�|	j|d
d
t||
|gd�ii�q~W|	S)Nr(rWrY)TFrGrHz%s_%s_allowr�z
%s_%s_denyrJz%s_%s_%s)r]r~rmr}rZr�rr�z"%s_%s_ICMP_BLOCK: ")rMr�r�r��ipvsrr2�query_icmp_block_inversionr�rr]rrrr�r,r�rrr�rr�r�r�r�r�r�)rTr�r�Zictr�r~r�r�r-r�r�Zfinal_chainr�r�r�rZr4r4r5�build_policy_icmp_block_rules/sb





"
"
z&nftables.build_policy_icmp_block_rulescCs�d}|jjj||t�}g}ddd�|}|jjj|�r@|j�}nddi}|j|ddtd||fd	|j�|gd
�ii�|jj	�dkr�|jjj|�r�|j|ddtd||fd	|j�|j
|jj	��dd
d||fiigd
�ii�|S)Nr(rWrY)TFr�rZrJz%s_%sr9)r]r~rmrar}r�rr�z%s_%s_ICMP_BLOCK: )rMr�r�r�r.r�r2r�r�r�r�)rTr�r�r~r�r�r�r�r4r4r5�'build_policy_icmp_block_inversion_rulesks,




 z0nftables.build_policy_icmp_block_inversion_rulescCs�g}ddddiiddd�iddd	d
dgdd
�iddd�ig}|dkrV|jdddii�|jddi�|jdddtd|d�ii�|jdddtdddddd�iddddgid�id digd�ii�|S)!Nr)r�r`rz==rH)r.r/r0Zfibr�ZiifrZoif)�flags�resultFr�rr�zrpfilter_DROP: r�rXrZrJZfilter_PREROUTING)r]r~rmr}r*rFr+)r,r-r�znd-router-advertznd-neighbor-solicitr�)r2r�)rTr�r�r�r4r4r5�build_rpfilter_rules�s0

znftables.build_rpfilter_rulesc	Cs�ddddddddd	g	}d
d�|D�}dd
ddd�idd|id�ig}|jjd"krb|jdddii�|j|jd��g}|jdddtdd|d�ii�|jdddtd d!|d�ii�|S)#Nz::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19cSs2g|]*}d|jd�dt|jd�d�d�i�qS)r�r�rr<)rre)r�rn)�.0r^r4r4r5�
<listcomp>�sz5nftables.build_rfc3964_ipv4_rules.<locals>.<listcomp>r)r*rLr�)r,r-z==r�)r.r/r0r�r�rr�zRFC3964_IPv4_REJECT: zaddr-unreachrWrZrJr�r<)r]r~rmrar}Zfilter_FORWARDrB)r�r�)rMZ_log_deniedr2r�r�)rTZ	daddr_setr�r�r4r4r5�build_rfc3964_ipv4_rules�s:

z!nftables.build_rfc3964_ipv4_rulescCs�d}g}|j|j|j��|j|j|j��|j|j|j��g}|j|j|||||��|j|j|||||��|j|j	|||||��|S)Nr()
r2rr]rrrrrrr)rTr�r�r�r~r�r�r4r4r5�*build_policy_rich_source_destination_rules�sz3nftables.build_policy_rich_source_destination_rulescCs|dkrdSdS)NrGrH�ebTF)rGrHr8r4)rTr�r4r4r5�is_ipv_supported�sznftables.is_ipv_supportedc
Cs�ddd�}||||ddg||dd||g||dd||g||dg||||||g||ddg||dd||g||dgdd	�}||kr�||Sttd
|��dS)NZ	ipv4_addrZ	ipv6_addr)rGrHZ
inet_protoZinet_servicerZifnameZ
ether_addr)zhash:ipzhash:ip,portzhash:ip,port,ipzhash:ip,port,netzhash:ip,markzhash:netzhash:net,netz
hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz!ipset type name '%s' is not valid)r	r
)rTr�r+Zipv_addr�typesr4r4r5�_set_type_list�s"

znftables._set_type_listc
Cs�|rd|kr|ddkrd}nd}t||j||�d�}x0|jd�djd�D]}|dkrLdg|d
<PqLW|r�d|kr�|d|d<d|kr�|d|d<g}x0dD](}d|i}	|	j|�|jdd|	ii�q�W|S)Nr]�inet6rHrG)r~r�r+�:r<�,rK�netrZintervalr1ZtimeoutZmaxelem�sizerJrLrWr�)rKr?r)rJrKrL)r�r;r�r�r2)
rTr�r+�optionsr�Zset_dict�tr�r]Z	rule_dictr4r4r5�build_set_create_rules�s*


znftables.build_set_create_rulescCs$|j|||�}|j||jj��dS)N)rCr�rMr�)rTr�r+rAr�r4r4r5�
set_createsznftables.set_createcCs8x2dD]*}dd|t|d�ii}|j||jj��qWdS)NrJrKrLrYr�)r]r~r�)rJrKrL)r�r�rMr�)rTr�r]rZr4r4r5�set_destroys

znftables.set_destroycCs6|jjj|�jjd�djd�}g}x�tt|��D]�}||dkrr|jdddii�|jdd	|rdd
ndd�i�q2||dkr�|jd|j|�|r�dndd�i�q2||dkr�|jdd|r�dndii�q2||dkr�|jdddii�q2t	d||��q2Wdt|�dk�rd|in|d|�r&dndd|d�iS)Nr=r<r>rr�r`r�r*Zthrr")r,r-rKr?rr�r�Zifacer�r�rz-Unsupported ipset type for match fragment: %sr)�concatrz!=z==�@)r.r/r0)rKr?r)
rMr�	get_ipsetr+r�rrer2r�r	)rTr�Z
match_destr�type_formatr3�ir4r4r5r s$ znftables._set_match_fragmentcCsN|jjj|�}|jjd�djd�}|jd�}t|�t|�krHttd��g}�x�tt|��D�]�}||dk�r,y||j	d�}Wn&t
k
r�|jd�||}	Yn,X|j||d|��|||dd�}	y|	j	d�}Wn t
k
�r|j|	�Yn(X|jd|	d|�|	|dd�gi�q\||dk�r d||k�rb|jd||jd�i�n�y||j	d�}WnLt
k
�r�||}
d|jk�r�|jdd
k�r�t
|
�}
|j|
�Yn^X||d|�}
d|jk�r�|jdd
k�r�t
|
�}
|jd|
t|||dd��d�i�q\|j||�q\Wt|�dk�rJd|igS|S)Nr=r<r>z+Number of values does not match ipset type.rZtcp�-rrKr?r�r]r<r�)rrerF)rKr?)rMrrHr+r�rer	rrrar�r2rArrn)rTr��entry�objrIZentry_tokensZfragmentrJraZport_strrr4r4r5�_set_entry_fragment7sL

("znftables._set_entry_fragmentc	Cs>g}|j||�}x(dD] }|jdd|t||d�ii�qW|S)NrJrKrLrWr�)r]r~r��elem)rJrKrL)rNr2r�)rTr�rLr�r�r]r4r4r5�build_set_add_rulesks

znftables.build_set_add_rulescCs"|j||�}|j||jj��dS)N)rPr�rMr�)rTr�rLr�r4r4r5�set_addusznftables.set_addcCsF|j||�}x4dD],}dd|t||d�ii}|j||jj��qWdS)NrJrKrLrYr�)r]r~r�rO)rJrKrL)rNr�r�rMr�)rTr�rLr�r]rZr4r4r5�
set_deleteys
znftables.set_deletecCs4g}x*dD]"}dd|t|d�ii}|j|�q
W|S)NrJrKrLr{r�)r]r~r�)rJrKrL)r�r2)rTr�r�r]rZr4r4r5�build_set_flush_rules�s
znftables.build_set_flush_rulescCs |j|�}|j||jj��dS)N)rSr�rMr�)rTr�r�r4r4r5�	set_flush�s
znftables.set_flushcCsJ|jjj|�}|jdkrd}n(|jrBd|jkrB|jddkrBd}nd}|S)Nzhash:macr	r]r<rLrK)rMrrHr+rA)rTr�rr]r4r4r5r��s
znftables._set_get_familyc	Cs�g}|j|j|||��|j|j|��d}x^|D]D}|j|j||��|d7}|dkr2|j||jj��|j�d}q2W|j||jj��dS)Nrr<i�)r�rCrSrPr�rMr��clear)	rTZset_nameZ	type_nameZentriesZcreate_optionsZ
entry_optionsr��chunkrLr4r4r5�set_restore�s
znftables.set_restore)N)N)r�)rJ)FrJ)rJ)rJ)F)NN)NN)NN)NN)N)N)N)N)N)F)N)N)F)NN)I�__name__�
__module__�__qualname__r�Zpolicies_supportedrVrhrlrtrzr�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�rrrr�rrrrr r!r#r$r%r&r'r*r+r,r/r0r3r6r7r9r;rCrDrErrNrPrQrRrSrTr�rWr4r4r4r5rI�s�/.`

4


R
i
;
-
9
 +


	
$
$
$


'
$

<
#


4
		rIij���i����)N)(Z
__future__rrirwr
Zfirewall.core.loggerrZfirewall.functionsrrrrrZfirewall.errorsr	r
rrr
rrZfirewall.core.richrrrrrrrZnftables.nftablesrr�r�r�r�r�r6r��objectrIr4r4r4r5�<module>s�$$





































__pycache__/icmp.cpython-36.pyc000064400000004265151731527020012344 0ustar003

��g�#@s�ddddgZddddddd	d
ddd
dddddddddddddddddddd d!d"d#d$�"Zd%d&d'd(d)dddd*d+d,d,d-d-d.d/d0d0d1d1d2d3�Zd4d5�Zd6d�Zd7d8�Zd9d�Zd:S);�
ICMP_TYPES�ICMPV6_TYPES�check_icmp_type�check_icmpv6_typez0/0z3/0z3/1z3/2z3/3z3/4z3/5z3/6z3/7z3/9z3/10z3/11z3/12z3/13z3/14z3/15z4/0z5/0z5/1z5/2z5/3z8/0z9/0z10/0z11/0z11/1z12/0z12/1z13/0z14/0z17/0z18/0)"z
echo-reply�pongznetwork-unreachablezhost-unreachablezprotocol-unreachablezport-unreachablezfragmentation-neededzsource-route-failedznetwork-unknownzhost-unknownznetwork-prohibitedzhost-prohibitedzTOS-network-unreachablezTOS-host-unreachablezcommunication-prohibitedzhost-precedence-violationzprecedence-cutoffz
source-quenchznetwork-redirectz
host-redirectzTOS-network-redirectzTOS-host-redirectzecho-request�pingzrouter-advertisementzrouter-solicitationzttl-zero-during-transitzttl-zero-during-reassemblyz
ip-header-badzrequired-option-missingztimestamp-requestztimestamp-replyzaddress-mask-requestzaddress-mask-replyz1/0z1/1z1/3z1/4z2/0z4/1z4/2z128/0z129/0z133/0z134/0z135/0z136/0z137/0)zno-routezcommunication-prohibitedzaddress-unreachablezport-unreachablezpacket-too-bigzttl-zero-during-transitzttl-zero-during-reassemblyz
bad-headerzunknown-header-typezunknown-optionzecho-requestrz
echo-replyrzrouter-solicitationzrouter-advertisementzneighbour-solicitationzneigbour-solicitationzneighbour-advertisementzneigbour-advertisementZredirectcCs|tkrdSdS)NTF)r)�_name�r�/usr/lib/python3.6/icmp.py�check_icmp_nameVsr
cCs|tj�krdSdS)NTF)r�values)�_typerrr	r[scCs|tkrdSdS)NTF)r)rrrr	�check_icmpv6_name`sr
cCs|tj�krdSdS)NTF)rr)rrrr	resN)�__all__rrr
rr
rrrrr	�<module>sx__pycache__/fw_icmptype.cpython-36.pyc000064400000004205151731527020013734 0ustar003

��g�	�@s>dgZddlmZddlmZddlmZGdd�de�ZdS)�FirewallIcmpType�)�log)�errors)�
FirewallErrorc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCs||_i|_dS)N)�_fw�
_icmptypes)�self�fw�r
�!/usr/lib/python3.6/fw_icmptype.py�__init__szFirewallIcmpType.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rr
r
r�__repr__!szFirewallIcmpType.__repr__cCs|jj�dS)N)r�clear)rr
r
r�cleanup$szFirewallIcmpType.cleanupcCst|jj��S)N)�sortedr�keys)rr
r
r�
get_icmptypes)szFirewallIcmpType.get_icmptypescCs||jkrttj|��dS)N)rrrZINVALID_ICMPTYPE)r�icmptyper
r
r�check_icmptype,s
zFirewallIcmpType.check_icmptypecCs|j|�|j|S)N)rr)rrr
r
r�get_icmptype0s
zFirewallIcmpType.get_icmptypecCs�|j}t|�dkrddg}x�|D]z}|dkrL|jjrB|jjrBq |jj}n,|dkrt|jjrj|jjrjq |jj}ng}|jj	�|kr t
jd|j|f�q W||j|j<dS)NrZipv4Zipv6z5ICMP type '%s' is not supported by the kernel for %s.)
Zdestination�lenrZip4tables_enabledZnftables_enabledZipv4_supported_icmp_typesZip6tables_enabledZipv6_supported_icmp_types�name�lowerrZinfo1r)r�objZ	orig_ipvsZipvZsupported_icmpsr
r
r�add_icmptype4s 


zFirewallIcmpType.add_icmptypecCs|j|�|j|=dS)N)rr)rrr
r
r�remove_icmptypeGs
z FirewallIcmpType.remove_icmptypeN)�__name__�
__module__�__qualname__rrrrrrrrr
r
r
rrsN)	�__all__Zfirewall.core.loggerrZfirewallrZfirewall.errorsr�objectrr
r
r
r�<module>s__pycache__/fw_zone.cpython-36.pyc000064400000077522151731527030013072 0ustar003

��gy��@s�ddlZddlZddlmZmZmZddlmZddlm	Z	ddl
mZddlm
Z
mZmZmZmZmZmZmZmZddlmZmZmZddlmZdd	lmZdd
lmZGdd�de �Z!dS)
�N)�	SHORTCUTS�DEFAULT_ZONE_TARGET�SOURCE_IPSET_TYPES)�FirewallTransaction)�Policy)�log)	�Rich_Service�	Rich_Port�
Rich_Protocol�Rich_SourcePort�Rich_ForwardPort�Rich_IcmpBlock�
Rich_IcmpType�Rich_Masquerade�	Rich_Mark)�checkIPnMask�
checkIP6nMask�	check_mac)�errors)�
FirewallError)�LastUpdatedOrderedDictc@sNeZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zdd
�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zd�dd �Zd!d"�Zd#d$�Zd%d&�Zd�d'd(�Zd)d*�Zd+d,�Zd-d.�Zd�d/d0�Zd�d1d2�Zd3d4�Zd5d6�Zd7d8�Zd9d:�Zd;d<�Z d=d>�Z!d�d@dA�Z"dBdC�Z#d�dDdE�Z$d�dFdG�Z%d�dHdI�Z&dJdK�Z'dLdM�Z(dNdO�Z)d�dQdR�Z*d�dSdT�Z+d�dUdV�Z,dWdX�Z-d�dYdZ�Z.d�d[d\�Z/d]d^�Z0d_d`�Z1dadb�Z2d�dcdd�Z3dedf�Z4dgdh�Z5didj�Z6dkdl�Z7dmdn�Z8dodp�Z9d�dqdr�Z:dsdt�Z;dudv�Z<dwdx�Z=d�dydz�Z>d{d|�Z?d}d~�Z@dd��ZAd�d�d��ZBd�d��ZCd�d��ZDd�d��ZEd�d��ZFd�d�d��ZGd�d��ZHd�d��ZId�d��ZJd�d�d��ZKd�d��ZLd�d��ZMd�d��ZNd�d�d��ZOd�d��ZPd�d��ZQd�d�d��ZRd�d�d��ZSd�d�d��ZTd�d��ZUd�d�d��ZVd�d��ZWd�d��ZXd�d��ZYd�d�d��ZZd�d��Z[d�d��Z\d�d��Z]d�d��Z^d�d��Z_d�d�d��Z`d�d��Zad�d�d„Zbd�dĄZcd�dƄZddS)��FirewallZonercCs||_i|_i|_dS)N)�_fw�_zones�_zone_policies)�self�fw�r�/usr/lib/python3.6/fw_zone.py�__init__&szFirewallZone.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rrrr�__repr__+szFirewallZone.__repr__cCs|jj�|jj�dS)N)r�clearr)rrrr�cleanup.s
zFirewallZone.cleanupcCs
t|j�S)N)rr)rrrr�new_transaction2szFirewallZone.new_transactioncCsdj||d�S)Nzzone_{fromZone}_{toZone})�fromZone�toZone)�format)rr%r&rrr�policy_name_from_zones5sz#FirewallZone.policy_name_from_zonescCst|jj��S)N)�sortedr�keys)rrrr�	get_zones:szFirewallZone.get_zonescCs8g}x.|j�D]"}|j|�s&|j|�r|j|�qW|S)N)r+�list_interfaces�list_sources�append)rZactive_zones�zonerrr�get_active_zones=s
zFirewallZone.get_active_zonescCs6|j|�}x&|jD]}||j|jdkr|SqWdS)N�
interfaces)�_FirewallZone__interface_idr�settings)r�	interface�interface_idr/rrr�get_zone_of_interfaceDs

z"FirewallZone.get_zone_of_interfacecCs6|j|�}x&|jD]}||j|jdkr|SqWdS)N�sources)�_FirewallZone__source_idrr3)r�source�	source_idr/rrr�get_zone_of_sourceLs

zFirewallZone.get_zone_of_sourcecCs|jj|�}|j|S)N)r�
check_zoner)rr/�zrrr�get_zoneTszFirewallZone.get_zonecCsBt�}|j|_|j||�|_|j|_|j|_|g|_|g|_�x�dD�]�}||jkr~|d	kr~|dkr~t	||t
jt||���qD|d
kr�||jkr�|d
kr�t	||t
jt||���qD||jko�|d
ko�|dk�r�t	||t
jt||���qD|dkrDg|_
xB|j
D]8}|j||�}||j|j|�k�r�|j
jt
j|���q�WqDW|S)N�services�ports�
masquerade�
forward_ports�source_ports�icmp_blocks�rules�	protocols�HOST�ANY)r?r@rArBrCrDrErF)r?r@rCrDrF)rA)rDrB)rE)r�nameZderived_from_zoner(�ZONE_POLICY_PRIORITYZpriority�targetZ
ingress_zonesZegress_zones�setattr�copy�deepcopy�getattrrE�_rich_rule_to_policiesr.)r�z_objr%r&�p_objZsetting�ruleZcurrent_policyrrr�policy_obj_from_zone_objXs6

z%FirewallZone.policy_obj_from_zone_objcCs�dd�d	D�|_||j|j<g|j|j<xX|jdfd|jf|jdfgD]8\}}|j|||�}|jjj|�|j|jj|j�qFW|j	|j�dS)
NcSsi|]}t�|�qSr)r)�.0�xrrr�
<dictcomp>sz)FirewallZone.add_zone.<locals>.<dictcomp>r1r7�icmp_block_inversion�forwardrGrH)r1r7rXrY)
r3rrIrrTr�policyZ
add_policyr.�copy_permanent_to_runtime)r�objr%r&rRrrr�add_zone~s

zFirewallZone.add_zonecCsn|j|}x|jD]}|j||dd�qWx|jD]}|j||dd�q2W|jrZ|j|�|jrj|j|�dS)NF)�allow_apply)	rr1�
add_interfacer7�
add_sourcerY�add_forwardrX�add_icmp_block_inversion)rr/r\�argrrrr[�s

z&FirewallZone.copy_permanent_to_runtimecCs8|j|}|jr|j|�|jj�|j|=|j|=dS)N)r�applied�unapply_zone_settingsr3r"r)rr/r\rrr�remove_zone�s


zFirewallZone.remove_zoneNcCsVxP|j�D]D}|j|}t|j�dks4t|j�dkr
tjd|�|j||d�q
WdS)NrzApplying zone '%s')�use_transaction)r+r�lenr1r7r�debug1�apply_zone_settings)rrgr/rQrrr�apply_zones�s

zFirewallZone.apply_zonescCs|j|}||_dS)N)rrd)rr/rdr\rrr�set_zone_applied�s
zFirewallZone.set_zone_appliedcCs�d|krdS|jd�}t|�dkr&dSd}x tD]}|dt|kr0|}q0W|dk	r�|d|j�krhdSt|�dks�t|�dkr�|ddkr�|d|fSdS)N�_�r���prer�deny�allow�post)rqrrrrsrt)�splitrhrr+)r�chainZsplits�_chainrVrrr�zone_from_chain�s 

zFirewallZone.zone_from_chaincCst|j|�}|dkrdS|\}}|d	kr0|}d}n4|d
krB|}d}n"|dkrTd}|}nttjd|��|j||�|fS)N�
PREROUTING�
FORWARD_INrH�INPUTrG�POSTROUTING�FORWARD_OUTz&chain '%s' can't be mapped to a policy)ryrz)r{)r|r})rxrrZ
INVALID_CHAINr()rrvrVr/rwr%r&rrr�policy_from_chain�s
zFirewallZone.policy_from_chainc	Csj|dkrf|j|�}|dk	rf|j|�\}}|dkr:|j�}n|}|jjj|d|||�|dkrf|jd�dS)N�ipv4�ipv6T)rr�)r~r$rrZZgen_chain_rules�execute)	r�ipv�tablervrgrVrZrw�transactionrrr�create_zone_base_by_chain�s

z&FirewallZone.create_zone_base_by_chaincCstj�||d�}|S)N)Zdate�sender�timeout)�time)rr�r��retrrrZ__gen_settings�szFirewallZone.__gen_settingscCs|j|�jS)N)r>r3)rr/rrr�get_settings�szFirewallZone.get_settingscCs�|j|�}x�|D]z}xt||D]h}|dkr<|j||||�q|dkr`|j|||d|d|�q|dkrlqq|dkrvqtjd|||�qWqW|r�|j|||�dS)Nr1r7rrorXrYz3Zone '%s': Unknown setting '%s:%s', unable to apply)r��
_interface�_sourcerZwarning�_icmp_block_inversion)r�enabler/r�r3�key�argsrrr�_zone_settingss

zFirewallZone._zone_settingscCs�|jj|�}|j|}|jr dSd|_|dkr8|j�}n|}x2|j|D]$}tjd||�|jjj	||d�qHW|j
d||�|dkr�|jd�dS)NTz+Applying policy (%s) derived from zone '%s')rg)rr<rrdr$rrrirZ�apply_policy_settingsr�r�)rr/rg�_zoner\r�rZrrrrjs

z FirewallZone.apply_zone_settingscCs�|jj|�}|j|}|js dS|dkr2|j�}n|}x$|j|D]}|jjj||d�qBW|jd||�|dkr||j	d�dS)N)rgFT)
rr<rrdr$rrZ�unapply_policy_settingsr�r�)rr/rgr�r\r�rZrrrre,s

z"FirewallZone.unapply_zone_settingscCs~|j|�}|j|�}g}x\td�D]P}|j|d|krZ|jtjt||j|d���q"|j||j|d�q"Wt|�S)zH
        :return: exported config updated with runtime settings
        �r)	r>�get_config_with_settings_dict�rangeZIMPORT_EXPORT_STRUCTUREr.rMrNrO�tuple)rr/r\Z	conf_dictZ	conf_list�irrr�get_config_with_settings?s

"z%FirewallZone.get_config_with_settingsc
Cs�|j|�j�}|dtkr"d|d<|j|�|j|�|j|�|j|�|j|�|j|�|j	|�|j
|�|j|�|j|�|j
|�|j|�d�}|jj||�S)zH
        :return: exported config updated with runtime settings
        rK�default)r?r@rDrArBr1r7�	rules_strrFrCrXrY)r>Zexport_config_dictr�
list_services�
list_ports�list_icmp_blocks�query_masquerade�list_forward_portsr,r-�
list_rules�list_protocols�list_source_ports�query_icmp_block_inversion�
query_forwardrZ'combine_runtime_with_permanent_settings)rr/Z	permanentZruntimerrrr�Os z*FirewallZone.get_config_with_settings_dictc
sddlm�d��fdd�	}��fdd�}�j�jf�j�jf�j�jf�j�j	f�j
�jf�j�j
f�j�jf||f�j�jf�j�jf�j�jf�j�jfd�}�j|�}�jj||�\}}	xv|	D]n}
t|	|
t��r$xX|	|
D]:}t|t��r||
d|f|��q�||
d||�q�Wq�||
d|�q�Wx�|D]�}
t||
t��r�x�||
D]l}|
dk�r�||
d|||d�nDt|t��r�||
d|f|�d|d��n||
d||d|d��q\Wn6|
dk�r�||
d||d�n||
d|d|d��q>WdS)Nr)�	Rich_Rulecs�j|�|d�d|d�dS)N)�rule_strr)r�r�)�add_rule)r/r�r�r�)r�rrr�add_rule_wrapperhszDFirewallZone.set_config_with_settings_dict.<locals>.add_rule_wrappercs�j|�|d��dS)N)r�)�remove_rule)r/r�)r�rrr�remove_rule_wrapperjszGFirewallZone.set_config_with_settings_dict.<locals>.remove_rule_wrapper)r?r@rDrArBr1r7r�rFrCrXrYror1r7)r�)r�r�rX)rN)r1r7)rX)�firewall.core.richr��add_service�remove_service�add_port�remove_port�add_icmp_block�remove_icmp_block�add_masquerade�remove_masquerade�add_forward_port�remove_forward_portr_�remove_interfacer`�
remove_source�add_protocol�remove_protocol�add_source_port�remove_source_portrb�remove_icmp_block_inversionra�remove_forwardr�rZget_added_and_removed_settings�
isinstance�listr�)rr/r3r�r�r�Z
setting_to_fnZold_settingsZadd_settingsZremove_settingsr�r�r)r�rr�set_config_with_settings_dictesF













  
z*FirewallZone.set_config_with_settings_dictcCs|jj|�dS)N)r�check_interface)rr4rrrr��szFirewallZone.check_interfacecCs\|jj|�}|j|}|j|�}||jdkrX|jd|}d|krX|ddk	rX|dSdS)Nr1r�)rr<rr2r3)rr/r4r��_objr5r3rrr�interface_get_sender�s

z!FirewallZone.interface_get_sendercCs|j|�|S)N)r�)rr4rrrZ__interface_id�s
zFirewallZone.__interface_idTc
Cs|jj�|jj|�}|j|}|j|�}||jdkrLttjd||f��|j	|�dk	rjttj
d|��tjd||f�|dkr�|j
�}	n|}	|jr�|r�|j||	d�|	j|j|d�|r�|jd|||	�|j||||�|	j|j||�|dk�r|	jd�|S)Nr1z'%s' already bound to '%s'z'%s' already bound to a zonez&Setting zone of interface '%s' to '%s')rgFT)r�check_panicr<rr2r3rr�ZONE_ALREADY_SETr6�
ZONE_CONFLICTrrir$rdrj�add_failrlr��!_FirewallZone__register_interface�#_FirewallZone__unregister_interfacer�)
rr/r4r�rgr^r�r�r5r�rrrr_�s8









zFirewallZone.add_interfacecCs6|jd|�|jd|<|p"|dk|jd|d<dS)Nrr1��__default__)�_FirewallZone__gen_settingsr3)rr�r5r/r�rrrZ__register_interface�sz!FirewallZone.__register_interfacecCsR|jj�|j|�}|jj|�}||kr,|S|dk	r@|j||�|j|||�}|S)N)rr�r6r<r�r_)rr/r4r��	_old_zone�	_new_zoner�rrr�change_zone_of_interface�s

z%FirewallZone.change_zone_of_interfacecCsz|jj�|dkr|j�}n|}|j||�|jd|d|dd�|dk	rd|dkrd|jd|d|dd�|dkrv|jd�dS)NT�+)r.r�F)rr�r$rjr�r�)rZold_zoneZnew_zonergr�rrr�change_default_zone�s

z FirewallZone.change_default_zonec	Cs�|jj�|j|�}|dkr,ttjd|��|dkr8|n
|jj|�}||krbttjd|||f��|dkrt|j�}n|}|j	|}|j
|�}|j|j||�|j
d|||�|dkr�|jd�|S)Nz'%s' is not in any zoner�z"remove_interface(%s, %s): zoi='%s'FT)rr�r6rrZUNKNOWN_INTERFACEr<r�r$rr2�add_postr�r�r�)	rr/r4rgZzoir�r�r�r5rrrr��s(






zFirewallZone.remove_interfacecCs||jdkr|jd|=dS)Nr1)r3)rr�r5rrrZ__unregister_interfacesz#FirewallZone.__unregister_interfacecCs|j|�|j|�dkS)Nr1)r2r�)rr/r4rrr�query_interfaceszFirewallZone.query_interfacecCs|j|�dj�S)Nr1)r�r*)rr/rrrr,"szFirewallZone.list_interfacesFcCsxt|�rdSt|�rdSt|�r$dS|jd�rh|j|dd��|rV|j|dd��|j|dd��Sttj	|��dS)Nrr�r�zipset:�)
rrr�
startswith�_check_ipset_type_for_source�_check_ipset_applied�
_ipset_familyrrZINVALID_ADDR)rr9rdrrr�check_source's
zFirewallZone.check_sourcecCs|j||d�}||fS)N)rd)r�)rr9rdr�rrrZ__source_id6szFirewallZone.__source_idc
Cs|jj�|jj|�}|j|}t|�r0|j�}|j||d�}||jdkr`tt	j
d||f��|j|�dk	r~tt	jd|��|dkr�|j
�}	n|}	|jr�|r�|j||	d�|	j|j|d�|r�|jd||d|d	|	�|j||||�|	j|j||�|dk�r|	jd�|S)
N)rdr7z'%s' already bound to '%s'z'%s' already bound to a zone)rgFTrro)rr�r<rr�upperr8r3rrr�r;r�r$rdrjr�rlr��_FirewallZone__register_source� _FirewallZone__unregister_sourcer�)
rr/r9r�rgr^r�r�r:r�rrrr`:s4





zFirewallZone.add_sourcecCs6|jd|�|jd|<|p"|dk|jd|d<dS)Nrr7r�r�)r�r3)rr�r:r/r�rrrZ__register_sourceaszFirewallZone.__register_sourcecCsb|jj�|j|�}|jj|�}||kr,|St|�r<|j�}|dk	rP|j||�|j|||�}|S)N)rr�r;r<rr�r�r`)rr/r9r�r�r�r�rrr�change_zone_of_sourcegs

z"FirewallZone.change_zone_of_sourcec	Cs�|jj�t|�r|j�}|j|�}|dkr<ttjd|��|dkrH|n
|jj|�}||krrttj	d|||f��|dkr�|j
�}n|}|j|}|j|�}|j
|j||�|jd||d|d|�|dkr�|jd�|S)Nz'%s' is not in any zoner�zremove_source(%s, %s): zos='%s'FrroT)rr�rr�r;rrZUNKNOWN_SOURCEr<r�r$rr8r�r�r�r�)	rr/r9rgZzosr�r�r�r:rrrr�ys,






zFirewallZone.remove_sourcecCs||jdkr|jd|=dS)Nr7)r3)rr�r:rrrZ__unregister_source�sz FirewallZone.__unregister_sourcecCs(t|�r|j�}|j|�|j|�dkS)Nr7)rr�r8r�)rr/r9rrr�query_source�szFirewallZone.query_sourcecCsdd�|j|�dj�D�S)NcSsg|]}|d�qS)ror)rU�krrr�
<listcomp>�sz-FirewallZone.list_sources.<locals>.<listcomp>r7)r�r*)rr/rrrr-�szFirewallZone.list_sourcescs�x��jj�D]�}|jsqxP�j|D]B}x<�jjj|�D]*\}}	|j||||||	|�}
|j||
�q8Wq$W�j|d�}�j	|�dr|d
kr|j
|||d|d�}
|j||
�qWxΈjjj�D]�}|�jjj|�kr�|�jjj
|�kr�q�|�jjj�k�rd�jjj|�j�rd|�r<t�j|��dk�r<�jjj||d�n&�jjjd	||�|j�fd
d�|�q�|r�|j�fdd�|�q�WdS)NrHrYr��*�filter)r4ro)rgFcs |�jjj�ko�jjjd|�S)NT)rrZ�)get_active_policies_not_derived_from_zone�!_ingress_egress_zones_transaction)�p)rrr�<lambda>�sz)FirewallZone._interface.<locals>.<lambda>cs|�jjj�ko�jjj|�S)N)rrZr�r�)r�)rrrr��s)r�r�)r�enabled_backends�policies_supportedrrZ�#_get_table_chains_for_zone_dispatchZ!build_zone_source_interface_rules�	add_rulesr(r��build_zone_forward_rules�"get_policies_not_derived_from_zone�list_ingress_zones�list_egress_zonesr��
get_policyrdrhr,r��_ingress_egress_zonesr�)rr�r/r4r�r.�backendrZr�rvrEr)rrr��s2$zFirewallZone._interfacecCs$|j|�dkrdS|jjj|dd�S)Nzhash:macF)rd)�_ipset_typer�ipsetZ
get_family)rrIrrrr��szFirewallZone._ipset_familycCs|jjj|dd�S)NF)rd)rr�Zget_type)rrIrrrr��szFirewallZone._ipset_typecCsdj|g|jjj|��S)N�,)�joinrr�Z
get_dimension)rrI�flagrrr�_ipset_match_flags�szFirewallZone._ipset_match_flagscCs|jjj|�S)N)rr�Z
check_applied)rrIrrrr��sz!FirewallZone._check_ipset_appliedcCs*|j|�}|tkr&ttjd||f��dS)Nz.ipset '%s' with type '%s' not usable as source)r�rrrZ
INVALID_IPSET)rrIZ_typerrrr��s
z)FirewallZone._check_ipset_type_for_sourcec
s�x�|r�jj|�gn�jj�D]�}|js*qxN�j|D]@}x:�jjj|�D](\}}	|j||||||	�}
|j||
�qJWq6W�j	|d�}�j
|�dr|j|||d|d�}
|j||
�qWxΈjjj�D]�}|�jjj
|�kr�|�jjj|�kr�q�|�jjj�k�rl�jjj|�j�rl|�rDt�j|��dk�rD�jjj||d�n&�jjjd||�|j�fdd	�|�q�|r�|j�fd
d	�|�q�WdS)NrHrYr�)r9ro)rgFcs |�jjj�ko�jjjd|�S)NT)rrZr�r�)r�)rrrr�sz&FirewallZone._source.<locals>.<lambda>cs|�jjj�ko�jjj|�S)N)rrZr�r�)r�)rrrr�
s)r�get_backend_by_ipvr�r�rrZr�Zbuild_zone_source_address_rulesr�r(r�r�r�r�r�r�r�rdrhr-r�r�r�)rr�r/r�r9r�r�rZr�rvrEr)rrr��s2"$zFirewallZone._sourcecCs0|jj|�}|j|d�}|jjj||||�|S)NrG)rr<r(rZr�)rr/�servicer�r��p_namerrrr�
szFirewallZone.add_servicecCs,|jj|�}|j|d�}|jjj||�|S)NrG)rr<r(rZr�)rr/r�r�rrrr�szFirewallZone.remove_servicecCs(|jj|�}|j|d�}|jjj||�S)NrG)rr<r(rZ�
query_service)rr/r�r�rrrr�szFirewallZone.query_servicecCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr�szFirewallZone.list_servicescCs2|jj|�}|j|d�}|jjj|||||�|S)NrG)rr<r(rZr�)rr/�port�protocolr�r�r�rrrr�#szFirewallZone.add_portcCs.|jj|�}|j|d�}|jjj|||�|S)NrG)rr<r(rZr�)rr/r�r�r�rrrr�)szFirewallZone.remove_portcCs*|jj|�}|j|d�}|jjj|||�S)NrG)rr<r(rZ�
query_port)rr/r�r�r�rrrr/szFirewallZone.query_portcCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr�4szFirewallZone.list_portscCs2|jj|�}|j|d�}|jjj|||||�|S)NrG)rr<r(rZr�)rr/�source_portr�r�r�r�rrrr�9szFirewallZone.add_source_portcCs.|jj|�}|j|d�}|jjj|||�|S)NrG)rr<r(rZr�)rr/rr�r�rrrr�?szFirewallZone.remove_source_portcCs*|jj|�}|j|d�}|jjj|||�S)NrG)rr<r(rZ�query_source_port)rr/rr�r�rrrrEszFirewallZone.query_source_portcCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr�JszFirewallZone.list_source_portscCs�|jj|�}t|j�tkr(|j|d�gSt|j�ttt	t
gkrL|j|d�gSt|j�ttgkrv|j|d�|j|d�gSt|j�t
gkr�|j|d�gSt|j�tgkr�|jd|�gS|jdkr�|j|d�gStdt|j���dS)NrHrGz Rich rule type (%s) not handled.)rr<�type�actionrr(�elementrr	r
rr
rrrr)rr/rSrrrrPOs 

z#FirewallZone._rich_rule_to_policiescCs.x(|j||�D]}|jjj||||�qW|S)N)rPrrZr�)rr/rSr�r�r�rrrr�bszFirewallZone.add_rulecCs*x$|j||�D]}|jjj||�qW|S)N)rPrrZr�)rr/rSr�rrrr�gszFirewallZone.remove_rulecCs2d}x(|j||�D]}|o(|jjj||�}qW|S)NT)rPrrZ�
query_rule)rr/rSr�r�rrrrlszFirewallZone.query_rulecCs^|jj|�}t�}xB|j|d�|j|d�|jd|�gD]}|jt|jjj|���q6Wt|�S)NrHrG)rr<�setr(�updaterZr�r�)rr/r�r�rrrr�rs
zFirewallZone.list_rulescCs0|jj|�}|j|d�}|jjj||||�|S)NrG)rr<r(rZr�)rr/r�r�r�r�rrrr�{szFirewallZone.add_protocolcCs,|jj|�}|j|d�}|jjj||�|S)NrG)rr<r(rZr�)rr/r�r�rrrr��szFirewallZone.remove_protocolcCs(|jj|�}|j|d�}|jjj||�S)NrG)rr<r(rZ�query_protocol)rr/r�r�rrrr	�szFirewallZone.query_protocolcCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr��szFirewallZone.list_protocolscCs.|jj|�}|jd|�}|jjj|||�|S)NrH)rr<r(rZr�)rr/r�r�r�rrrr��szFirewallZone.add_masqueradecCs*|jj|�}|jd|�}|jjj|�|S)NrH)rr<r(rZr�)rr/r�rrrr��szFirewallZone.remove_masqueradecCs&|jj|�}|jd|�}|jjj|�S)NrH)rr<r(rZr�)rr/r�rrrr��szFirewallZone.query_masqueradec	Cs6|jj|�}|j|d�}|jjj|||||||�|S)NrH)rr<r(rZr�)	rr/r�r��toport�toaddrr�r�r�rrrr��s
zFirewallZone.add_forward_portcCs2|jj|�}|j|d�}|jjj|||||�|S)NrH)rr<r(rZr�)rr/r�r�r
rr�rrrr��sz FirewallZone.remove_forward_portcCs.|jj|�}|j|d�}|jjj|||||�S)NrH)rr<r(rZ�query_forward_port)rr/r�r�r
rr�rrrr�szFirewallZone.query_forward_portcCs&|jj|�}|j|d�}|jjj|�S)NrH)rr<r(rZr�)rr/r�rrrr��szFirewallZone.list_forward_portscCsP|jj|�}|j|d�}|jjj||||�|j|d�}|jjj||||�|S)NrGrH)rr<r(rZr�)rr/�icmpr�r�r�rrrr��szFirewallZone.add_icmp_blockcCsH|jj|�}|j|d�}|jjj||�|j|d�}|jjj||�|S)NrGrH)rr<r(rZr�)rr/r
r�rrrr��szFirewallZone.remove_icmp_blockcCsD|jj|�}|j|d�}|j|d�}|jjj||�oB|jjj||�S)NrGrH)rr<r(rZ�query_icmp_block)rr/r
�p_name_host�
p_name_fwdrrrr�s
zFirewallZone.query_icmp_blockcCsH|jj|�}|j|d�}|j|d�}tt|jjj|�|jjj|���S)NrGrH)rr<r(r)rrZr�)rr/rrrrrr��s
zFirewallZone.list_icmp_blockscCsH|jj|�}|j|d�}|jjj||�|j|d�}|jjj||�|S)NrGrH)rr<r(rZrb)rr/r�r�rrrrb�sz%FirewallZone.add_icmp_block_inversioncCsL|jj|�}|j|d�}|jjj|||�|j|d�}|jjj|||�dS)NrGrH)rr<r(rZr�)rr�r/r�r�rrrr��s
z"FirewallZone._icmp_block_inversioncCsD|jj|�}|j|d�}|jjj|�|j|d�}|jjj|�|S)NrGrH)rr<r(rZr�)rr/r�rrrr��sz(FirewallZone.remove_icmp_block_inversioncCs@|jj|�}|j|d�}|j|d�}|jjj|�o>|jjj|�S)NrGrH)rr<r(rZr�)rr/rrrrrr��s
z'FirewallZone.query_icmp_block_inversionc
	Cs�|j|d�}xT|j|jdD]@}x:|jj�D],}|js:q.|j|||d|d�}|j||�q.WqWxj|j|jdD]V\}}	xL|r�|jj|�gn|jj�D],}|js�q�|j|||d|	d�}|j||�q�WqtWdS)NrHr1r�)r4r7)r9)	r(rr3rr�r�r�r�r�)
rr�r/r�r�r4r�rEr�r9rrr�_forward�s"zFirewallZone._forwardcCsdS)NTr)rrrrZ__forward_idszFirewallZone.__forward_idc	Cs�|jj|�}|jj|�|jj�|j|}|j�}||jdkrRttj	d|��|dkrd|j
�}n|}|jr||jd||�|j
||||�|j|j||�|dkr�|jd�|S)NrYzforward already enabled in '%s'T)rr<Z
check_timeoutr�r�_FirewallZone__forward_idr3rrZALREADY_ENABLEDr$rdr�_FirewallZone__register_forwardr��!_FirewallZone__unregister_forwardr�)	rr/r�r�rgr�r��
forward_idr�rrrras$




zFirewallZone.add_forwardcCs|j||�|jd|<dS)NrY)r�r3)rr�rr�r�rrrZ__register_forward.szFirewallZone.__register_forwardcCs�|jj|�}|jj�|j|}|j�}||jdkrFttjd|��|dkrX|j	�}n|}|j
rp|jd||�|j|j
||�|dkr�|jd�|S)NrYzforward not enabled in '%s'FT)rr<r�rrr3rrZNOT_ENABLEDr$rdrr�rr�)rr/rgr�r�rr�rrrr�2s 




zFirewallZone.remove_forwardcCs||jdkr|jd|=dS)NrY)r3)rr�rrrrZ__unregister_forwardKsz!FirewallZone.__unregister_forwardcCs|j�|j|�dkS)NrY)rr�)rr/rrrr�OszFirewallZone.query_forward)N)N)N)N)NNT)N)N)N)F)F)NNT)N)N)F)rN)rN)rN)rN)rN)rN)NNrN)NN)NN)rN)N)rNN)N)e�__name__�
__module__�__qualname__rJrr!r#r$r(r+r0r6r;r>rTr]r[rfrkrlrxr~r�r�r�r�rjrer�r�r�r�r�r2r_r�r�r�r�r�r�r,r�r8r`r�r�r�r�r�r-r�r�r�r�r�r�r�r�r�r�r�r�r�rr�r�r�rr�rPr�r�rr�r�r�r	r�r�r�r�r�r�rr�r�r�rr�rbr�r�r�rrrarr�rr�rrrrr#s�&



8
(





&


,(



	





		
		

r)"r�rMZfirewall.core.baserrrZfirewall.core.fw_transactionrZfirewall.core.io.policyrZfirewall.core.loggerrr�rr	r
rrr
rrrZfirewall.functionsrrrZfirewallrZfirewall.errorsrZfirewall.fw_typesr�objectrrrrr�<module>s,__pycache__/ipXtables.cpython-36.opt-1.pyc000064400000104137151731527030014306 0ustar003

��g���@s(ddlZddlZddlmZddlmZddlmZm	Z	m
Z
mZmZm
Z
mZmZddlmZddlmZmZmZmZmZddlmZmZmZmZmZmZmZddl Z dZ!d	d
dgdd
gdd
d	d
dgdd
d
gd	d
dgd�Z"ddd�Z#ddd�Z$dd�Z%dd�Z&dd�Z'Gdd�de(�Z)Gdd�de)�Z*dS)�N)�runProg)�log)�tempFile�readfile�	splitArgs�	check_mac�portStr�check_single_address�
check_address�normalizeIP6)�config)�
FirewallError�INVALID_PASSTHROUGH�INVALID_RULE�
UNKNOWN_ERROR�INVALID_ADDR)�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�Rich_Masquerade�Rich_ForwardPort�Rich_IcmpBlock��INPUT�OUTPUT�FORWARD�
PREROUTING�POSTROUTING)�security�raw�mangle�nat�filterzicmp-host-prohibitedzicmp6-adm-prohibited)�ipv4�ipv6�icmpz	ipv6-icmpcCs�ddddddd�}|dd�}x~|D]v}y|j|�}Wntk
rLw$YnX|d
kr�yt||d	�Wntk
r~YnX|j|d	�||||<q$W|S)z Inverse valid rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz--new-chainN�-I�--insert�)r'r()�index�	Exception�int�pop)�args�replace_args�ret_args�arg�idx�r3�/usr/lib/python3.6/ipXtables.py�common_reverse_rule9s(
r5cCs�ddddddd�}|dd�}x�|D]x}y|j|�}Wntk
rLw$YnX|dkr�yt||d	�Wntk
r~YnX|j|d	�||||<|SWttd
��dS)z Reverse valid passthough rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz--new-chainN�-I�--insertr)zno '-A', '-I' or '-N' arg)r6r7)r*�
ValueErrorr,r-r
r)r.r/r0�xr2r3r3r4�common_reverse_passthrough^s,
r:cCs�t|�}tddddddddd	d
ddd
dddddddg�}t||@�dkrbttdt||@�d��tddddddg�}t||@�dkr�ttd��dS)zZ Check if passthough rule is valid (only add, insert and new chain
    rules are allowed) z-Cz--checkz-Dz--deletez-Rz	--replacez-Lz--listz-Sz--list-rulesz-Fz--flushz-Zz--zeroz-Xz--delete-chainz-Pz--policyz-Ez--rename-chainrzarg '%s' is not allowedz-Az--appendz-Iz--insertz-Nz--new-chainzno '-A', '-I' or '-N' argN)�set�lenr
r�list)r.Znot_allowedZneededr3r3r4�common_check_passthrough�s*

r>c@s�eZdZdZdZdZdd�Zdd�Zdd�Zd	d
�Z	dd�Z
d
d�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd �Zdhd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zdid,d-�Zd.d/�Zdjd1d2�Zd3d4�Zd5d6�Zdkd8d9�Zdld:d;�Z d<d=�Z!d>d?�Z"d@dA�Z#dBdC�Z$dDdE�Z%dFdG�Z&dHdI�Z'dJdK�Z(dLdM�Z)dNdO�Z*dPdQ�Z+dmdRdS�Z,dndTdU�Z-dodVdW�Z.dXdY�Z/dpdZd[�Z0dqd\d]�Z1drd^d_�Z2dsd`da�Z3dbdc�Z4ddde�Z5dfdg�Z6d!S)t�	ip4tablesr$TcCsd||_tj|j|_tjd|j|_|j�|_|j�|_	|j
�g|_i|_i|_
g|_i|_dS)Nz
%s-restore)�_fwrZCOMMANDS�ipv�_command�_restore_command�_detect_wait_option�wait_option�_detect_restore_wait_option�restore_wait_option�fill_exists�available_tables�rich_rule_priority_counts�policy_priority_counts�zone_source_index_cache�
our_chains)�self�fwr3r3r4�__init__�s

zip4tables.__init__cCs$tjj|j�|_tjj|j�|_dS)N)�os�path�existsrBZcommand_existsrCZrestore_command_exists)rNr3r3r4rH�szip4tables.fill_existscCs�|jr(|j|kr(|jgdd�|D�}ndd�|D�}tjd|j|jdj|��t|j|�\}}|dkr�td|jdj|�|f��|S)NcSsg|]}d|�qS)z%sr3)�.0�itemr3r3r4�
<listcomp>�sz#ip4tables.__run.<locals>.<listcomp>cSsg|]}d|�qS)z%sr3)rTrUr3r3r4rV�sz	%s: %s %s� rz'%s %s' failed: %s)rEr�debug2�	__class__rB�joinrr8)rNr.Z_args�status�retr3r3r4Z__run�szip4tables.__runc
Cs<y|j|�}Wntk
r"dSX||||d�<dSdS)NF�T)r*r8)rN�rule�patternZreplacement�ir3r3r4�
_rule_replace�szip4tables._rule_replacecCs|tko|t|kS)N)�BUILT_IN_CHAINS)rNrA�table�chainr3r3r4�is_chain_builtin�szip4tables.is_chain_builtincCs2d|g}|r|jd�n
|jd�|j|�|gS)Nz-tz-Nz-X)�append)rN�addrcrdr^r3r3r4�build_chain_rules�s

zip4tables.build_chain_rulescCs8d|g}|r |d|t|�g7}n|d|g7}||7}|S)Nz-tz-Iz-D)�str)rNrgrcrdr*r.r^r3r3r4�
build_rule�szip4tables.build_rulecCst|�S)N)r5)rNr.r3r3r4�reverse_rule�szip4tables.reverse_rulecCst|�dS)N)r>)rNr.r3r3r4�check_passthrough�szip4tables.check_passthroughcCst|�S)N)r:)rNr.r3r3r4�reverse_passthrough�szip4tables.reverse_passthroughcCs�d}y|jd�}Wntk
r&YnXt|�|dkrD||d}d}xLd
D]D}y|j|�}Wntk
rtYqNXt|�|dkrN||d}qNW||fS)Nr#z-tr]�-A�--append�-I�--insert�-N�--new-chain)rnrorprqrrrs)r*r8r<)rNr.rcr`rd�optr3r3r4�passthrough_parse_table_chain�s$z'ip4tables.passthrough_parse_table_chaincCs4yH|jd�}|j|�|j|�}d|dkr:||df}n||df}WnFtk
r�y|jd�}|j|�d}Wntk
r�dSXYnXd}|ddkr�d}|r�|r�||kr�|j|�nn|�r0|�r�||kr�|j|�|jdd
�d�|j|�}n|jj�rd}nt|�}d|d<|j	dd|d�dS)Nz%%ZONE_SOURCE%%z-m���z%%ZONE_INTERFACE%%Tr�-D�--deleteFcSs|dS)Nrr3)r9r3r3r4�<lambda>&sz4ip4tables._run_replace_zone_source.<locals>.<lambda>)�keyz-Ir)z%dr])ryrz)
r*r-r8�removerf�sortr@�_allow_zone_driftingr<�insert)rNr^rLr`�zoneZzone_source�rule_addr*r3r3r4�_run_replace_zone_source	s>







z"ip4tables._run_replace_zone_sourcecCsy|j|�}Wntk
r$Y�n�Xd}d}d}|j|�|j|�}t|�tkr\ttd��d}	xLdD]D}
y|j|
�}Wntk
r�YqfXt|�|dkrf||d}	qfWxhdD]`}
y|j|
�}Wntk
r�Yq�Xt|�|dk�r�||d}|
dk�rd}|
dkr�d}q�W|	|f}|�sp||k�sP|||k�sP|||dk�rZttd��|||d8<n�||k�r�i||<|||k�r�d|||<d}
xHt	||j
��D]4}||k�r�|�r�P|
|||7}
||k�r�P�q�W|||d7<d
||<|j|dd|
�dS)a
        Change something like
          -t filter -I public_IN %%RICH_RULE_PRIORITY%% 123
        or
          -t filter -A public_IN %%RICH_RULE_PRIORITY%% 321
        into
          -t filter -I public_IN 4
        or
          -t filter -I public_IN
        TFr]z%priority must be followed by a numberr#�-t�--table�-A�--append�-I�--insert�-D�--deleterz*nonexistent or underflow of priority countr)z%dN���)r�r�)r�r�r�r�r�r�)r�r�)r�r�)r*r8r-�typer,r
rr<r�sorted�keysr�)rNr^Zpriority_counts�tokenr`r�r�Zinsert_add_index�priorityrcrt�jrdr*�pr3r3r4�_set_rule_replace_priority2sj








z$ip4tables._set_rule_replace_prioritycCsPt�}i}tj|j�}tj|j�}tj|j�}�x�|D�]�}|dd�}	|j|	dddt|jg�|j|	dt	|jg�y|	j
d�}
Wntk
r�Yn8X|dkr�q6|d$kr�d
dd|g|	|
|
d
�<n
|	j|
�|j
|	|d�|j
|	|d�|j|	|�d}xZd%D]R}y|	j
|�}
Wntk
�r,Yn(Xt|	�|
d
k�r|	j|
�|	j|
�}�qWxhtt|	��D]X}
xPtjD]F}
|
|	|
k�rt|	|
jd��o�|	|
jd��rtd|	|
|	|
<�qtW�qhW|j|g�j|	�q6WxR|D]J}||}|jd|�x"|D]}	|jdj|	�d��qW|jd��q�W|j�tj|j�}tjd|j|j d|j|j!f�g}|j"�rz|j|j"�|jd�t#|j ||jd�\}}tj$�dk�r
t%|j�}|dk	�r
d
}
xH|D]@}tj&d|
|fd
dd �|jd��s�tj&d!d
d"�|
d
7}
�q�Wtj'|j�|dk�r:td#|j dj|�|f��||_||_||_dS)&Nz
%%REJECT%%�REJECTz
--reject-withz%%ICMP%%z%%LOGTYPE%%�off�unicast�	broadcast�	multicastz-m�pkttypez
--pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r#�-t�--table�"z"%s"z*%s
rW�
zCOMMIT
z	%s: %s %sz%s: %dz-n)�stdinr)z%8d: %sr)�nofmt�nlr)r�z'%s %s' failed: %s)r�r�r�)r�r�)(r�copy�deepcopyrJrKrLra�DEFAULT_REJECT_TYPErA�ICMPr*r8r-r�r�r<�range�stringZ
whitespace�
startswith�endswith�
setdefaultrf�writerZ�closerQ�stat�namerrXrYrC�st_sizerGrZgetDebugLogLevelrZdebug3�unlink)rN�rules�
log_denied�	temp_fileZtable_rulesrJrKrLZ_ruler^r`rcrt�cr�r.r[r\�lines�liner3r3r4�	set_rules�s�









zip4tables.set_rulesc
Cs�|j|dddt|jg�|j|dt|jg�y|jd�}Wntk
rRYn:X|dkr`dS|dkr�ddd
|g|||d�<n
|j|�tj|j	�}tj|j
�}tj|j�}|j||d�|j||d�|j
||�|j|�}||_	||_
||_|S)Nz
%%REJECT%%r�z
--reject-withz%%ICMP%%z%%LOGTYPE%%r�rr�r�r�z-mr�z
--pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%)r�r�r�)rar�rAr�r*r8r-r�r�rJrKrLr�r��_ip4tables__run)rNr^r�r`rJrKrL�outputr3r3r4�set_rule�s.

zip4tables.set_ruleNcCs�g}|r|gntj�}xx|D]p}||jkr6|j|�qy,|jd|ddg�|jj|�|j|�Wqtk
r�tjd|j|f�YqXqW|S)Nz-tz-Lz-nzA%s table '%s' does not exist (or not enough permission to check).)	rbr�rIrfr�r8r�debug1rA)rNrcr\Ztablesr3r3r4�get_available_tabless

zip4tables.get_available_tablescCs`d}t|jdddg�}|ddkr\d}t|jdddg�}|ddkrHd}tjd|j|j|�|S)Nrz-wz-Lz-nrz-w10z%s: %s will be using %s option.)rrBrrXrY)rNrEr\r3r3r4rDszip4tables._detect_wait_optioncCs�t�}|jd�|j�d}xJdD]B}t|j|g|jd�}|ddkr"d|dkr"d	|dkr"|}Pq"Wtjd
|j|j|�t	j
|j�|S)Nz#foor�-w�--wait=2)r�rzinvalid optionr]zunrecognized optionz%s: %s will be using %s option.)r�r�)rr�r�rrCr�rrXrYrQr�)rNr�rEZtest_optionr\r3r3r4rF"s

z%ip4tables._detect_restore_wait_optioncCsVi|_i|_g|_g}x:tj�D].}|j|�s0q xdD]}|jd||g�q6Wq W|S)N�-F�-X�-Zz-t)r�r�r�)rJrKrLrbr�r�rf)rNr�rc�flagr3r3r4�build_flush_rules5s

zip4tables.build_flush_rulescCsfg}|dkrdn|}xLtj�D]@}|j|�s.q|dkr8qx$t|D]}|jd|d||g�qBWqW|S)NZPANIC�DROPr"z-tz-P)rbr�r�rf)rN�policyr��_policyrcrdr3r3r4�build_set_policy_rulesDs
z ip4tables.build_set_policy_rulescCs g}d}y"|jd|jdkrdnddg�}WnJtk
rt}z.|jdkrVtjd|�ntjd|�WYd	d	}~XnX|j�}d
}x�|D]�}|r�|j�j�}|j�}xD|D]<}	|	j	d�r�|	j
d�r�|	d
d�}
n|	}
|
|kr�|j|
�q�W|jdko�|j	d��s|jdkr�|j	d�r�d}q�W|S)zQReturn ICMP types that are supported by the iptables/ip6tables command and kernelrz-pr$r&z	ipv6-icmpz--helpziptables error: %szip6tables error: %sNF�(�)r]zValid ICMP Types:r%zValid ICMPv6 Types:Tr�)r�rAr8rr��
splitlines�strip�lower�splitr�r�rf)rNrAr\r�Zexr�Zin_typesr�Zsplitsr�r9r3r3r4�supported_icmp_typesPs4
 

zip4tables.supported_icmp_typescCsgS)Nr3)rNr3r3r4�build_default_tablesqszip4tables.build_default_tablesr�c	Csi}|jd�rpg|d<t�|jd<xLtdD]@}|djd|�|djd||f�|jdjd|�q,W|jd��r\g|d<t�|jd<x�tdD]�}|djd|�|djd||f�|jdjd|�|dkr�xt|jjr�ddd	d
gndd	d
gD]R}|djd||f�|djd|||f�|jdjtd
||fg���qWq�W|jd��rNg|d<t�|jd<x�tdD]�}|djd|�|djd||f�|jdjd|�|dk�r�xv|jj�r�ddd	d
gndd	d
gD]R}|djd||f�|djd|||f�|jdjtd
||fg���q�W�q�W|jd��r@g|d<t�|jd<x�tdD]�}|djd|�|djd||f�|jdjd|�|d9k�rxxv|jj�r�ddd	d
gndd	d
gD]R}|djd||f�|djd|||f�|jdjtd
||fg���q�W�qxWg|d<t�|jd<|djd�|djd�|djd�|djd�|jdjtd��xf|jj�r�ddd	d
gndd	d
gD]B}|djd|�|djd|�|jdjtd|���q�W|dk�r |djd�|djd�|dk�rF|djd�|djd�|djd�|djd �|djd!�|djd"�|jdjtd#��xJd:D]B}|djd$|�|djd%|�|jdjtd&|���q�Wxzd;D]r}xj|jj�r
dd	gnd	gD]N}|djd)||f�|djd*||f�|jdjtd+||f���qW�q�WxJd<D]B}|djd$|�|djd%|�|jdjtd&|���qnW|dk�r�|djd,�|djd-�|dk�r�|djd.�|djd/�|dd0d1d2d3g7<|jdjtd4��xJd=D]B}|djd5|�|djd6|�|jdjtd7|���q2WxJd>D]B}|djd5|�|djd6|�|jdjtd7|���q~Wg}xJ|D]B}||j�k�r�q�x(||D]}|jd8|gt	|���q�W�q�W|S)?Nrz-N %s_directz-A %s -j %s_directz	%s_directr r�POLICIES_preZZONES_SOURCEZZONES�
POLICIES_postz-N %s_%sz-A %s -j %s_%sz%s_%sr!r"rr#zB-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A INPUT -i lo -j ACCEPTz-N INPUT_directz-A INPUT -j INPUT_directZINPUT_directz-N INPUT_%sz-A INPUT -j INPUT_%szINPUT_%sr�z^-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z/-A INPUT -m conntrack --ctstate INVALID -j DROPz9-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A INPUT -j %%REJECT%%zD-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A FORWARD -i lo -j ACCEPTz-N FORWARD_directz-A FORWARD -j FORWARD_directZFORWARD_directz
-N FORWARD_%sz-A FORWARD -j FORWARD_%sz
FORWARD_%s�IN�OUTz-N FORWARD_%s_%sz-A FORWARD -j FORWARD_%s_%sz
FORWARD_%s_%sz`-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z1-A FORWARD -m conntrack --ctstate INVALID -j DROPz;-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A FORWARD -j %%REJECT%%z-N OUTPUT_directz>-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPTz-A OUTPUT -o lo -j ACCEPTz-A OUTPUT -j OUTPUT_directZ
OUTPUT_directz-N OUTPUT_%sz-A OUTPUT -j OUTPUT_%sz	OUTPUT_%sz-t)rr)r�)r�r�)r�)r�)r�)
r�r;rMrbrfrgr@r�updater)	rNr�Z
default_rulesrdZdispatch_suffix�	directionZfinal_default_rulesrcr^r3r3r4�build_default_rulesus�
$(
&*
&*&



(






"zip4tables.build_default_rulescCsf|dkrdddhS|dkr,d|j�kr,dhS|dkrHd|j�krHddhS|d	krbd	|j�krbdhSiS)
Nr#r�
FORWARD_IN�FORWARD_OUTr!rr"rr )r�)rNrcr3r3r4�get_zone_table_chains�s
zip4tables.get_zone_table_chainsc	s�|jjj|���jdkrdnd��dkr4�dkr4dnd}	|jjj|�t|	��g}
g}x|D]}|
jd|g�qZWx|D]}|jd	|g�qvWxB|D]:}
|jjj|
�}|dkr�|j	|�r�q�|
j|j
d|
��q�Wx\|D]T}
|jjj|
�}|dk�r|j	|��rq�t|
��r�dk�rq�|j|j
d|
��q�W������fdd�}g}|
�r�x�|
D]F}|�r�x8|D]}|j|||���qdWn|�r�n|j||d���qTWnH|�r�n@|�r�x8|D]}|j|d|���q�Wn|�r�n|j|dd��|S)Nr�pre�postr"rTFz-iz-or$r%z-sr�rz-dcsVddd��}d�|d��fd�jg}|r6|j|�|rD|j|�|jd�g�|S)Nz-Az-D)TFz-tz%s_POLICIES_%sz%%POLICY_PRIORITY%%z-j)r��extend)�ingress_fragment�egress_fragment�add_delr^)r�rd�chain_suffix�enable�p_objrcr3r4�_generate_policy_dispatch_rules


zSip4tables.build_policy_ingress_egress_rules.<locals>._generate_policy_dispatch_rule)r$r%)r$r%)rr�r)r@r�Z
get_policyr��policy_base_chain_name�POLICY_CHAIN_PREFIXrfr�Zcheck_source�is_ipv_supported�_rule_addr_fragmentr)rNr�r�rcrdZingress_interfacesZegress_interfacesZingress_sourcesZegress_sources�isSNATZingress_fragmentsZegress_fragments�	interface�addrrAr�r�r�r�r3)r�rdr�r�r�rcr4�!build_policy_ingress_egress_rules�sR






z+ip4tables.build_policy_ingress_egress_rulesFc
Cs�|dkr|dkrdnd}|jjj||t|d�}	ddddddd�|}
d	}|rb|rbd
d|dg}n,|rtd
d|g}ndd|g}|s�|dg7}|d||
|||	g7}|gS)Nr"rTF)r�z-iz-o)rrrr�r�rz-gz-Iz%s_ZONESz%%ZONE_INTERFACE%%z-Az-Dz-t)r@r�r�r�)
rNr�r�r�r�rcrdrfr�r�rt�actionr^r3r3r4�!build_zone_source_interface_rulesKs&

z+ip4tables.build_zone_source_interface_rulescCs�|jd�rP|dd�}|dkr$d}nd}dj|g|jjj|��}ddd	||gSt|�rz|dkrjttd
��ddd|j�gSt	d
|�r�t
|�}n,td
|�r�|jd�}t
|d�d|d}||gSdS)Nzipset:�z-d�dst�src�,z-mr;z--match-setzCan't match a destination MAC.�macz--mac-sourcer%�/rr])
r�rZr@�ipsetZ
get_dimensionrr
r�upperr	rr
r�)rNrt�address�invertr��flags�
addr_splitr3r3r4r�es"





zip4tables._rule_addr_fragmentc
Cs�ddd�|}|dkr"|dkr"dnd}|jjj||t|d�}	d	d
d	d	d
d
d�|}
|jjrdd|}nd
|}t|�r�|dkr�gS||d|d|g}|j|j|
|��|jd|	g�|gS)Nz-Iz-D)TFr"rTF)r�z-sz-d)rrrr�r�rz%s_ZONES_SOURCEz%s_ZONESr�rz%%ZONE_SOURCE%%z-tz-g)rr�r)r@r�r�r�rrr�r�)
rNr�r�r�r�rcrdr�r�r�rtZzone_dispatch_chainr^r3r3r4�build_zone_source_address_rules{s&
z)ip4tables.build_zone_source_address_rulescCs>ddd�|}ddd�|}|dkr0|dkr0dnd	}|jjj||t|d
�}|j|jt|d|d|d
|d|d|g��g}	|	j||d|g�|	j|d
|d|g�|	j|d|d|g�|	j|d|d|g�|	j|d|d|g�|	j|d|d|g�|	j||d|dd
|g�|	j||d|dd|g�|	j||d|dd|g�|	j||d|dd|g�|	j||d|dd|g�|jjj|j	}
|jj
�dk�r|dk�r|
dk�r�|	j||d|ddddd|g	�|
dk�r|	j||d|ddddd|g	�|dk�r,|
dk�r,|	j||d|d|
g�|�s:|	j�|	S)Nz-Nz-X)TFz-Az-Dr"rTF)r�z%s_logz%s_denyz%s_prez%s_postz%s_allowz-tz-jr�r#r��
%%REJECT%%z%%LOGTYPE%%�LOGz--log-prefixz
"%s_REJECT: "r�z"%s_DROP: "�ACCEPT)r�r�)r�r�r�r�)r@r�r�r�rMr�r;rfZ	_policies�target�get_log_denied�reverse)rNr�r�rcrdZ
add_del_chainZadd_del_ruler�r�r�r�r3r3r4�build_policy_chain_rules�sN




z"ip4tables.build_policy_chain_rulescCs2|sgSddd|jg}|jdk	r.|d|jg7}|S)Nz-m�limitz--limitz
--limit-burst)�valueZburst)rNr�sr3r3r4�_rule_limit�s
zip4tables._rule_limitcCs�t|j�tttgkrn<|jrHt|j�tttt	gkrRt
tdt|j���n
t
td��|jdkr�t|j�ttgks�t|j�tt	gkr�dSt|j�tgks�t|j�ttgkr�dSn|jdkr�dSdSdS)NzUnknown action %szNo rule action specified.r�allowZdenyr�r�)
r��elementrrrr�rrrrr
rr�)rN�	rich_ruler3r3r4�_rich_rule_chain_suffix�s 


z!ip4tables._rich_rule_chain_suffixcCs>|jr|jrttd��|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrr�r�)r�auditr
rr�)rNrr3r3r4� _rich_rule_chain_suffix_from_log�s


z*ip4tables._rich_rule_chain_suffix_from_logcCs|jdkrgSd|jgS)Nrz%%RICH_RULE_PRIORITY%%)r�)rNrr3r3r4�_rich_rule_priority_fragment�s
z&ip4tables._rich_rule_priority_fragmentc
Cs�|js
gS|jjj||t�}ddd�|}|j|�}d||d||fg}	|	|j|�7}	|	|ddg7}	|jjr�|	dd	|jjg7}	|jjr�|	d
d|jjg7}	|	|j	|jj
�7}	|	S)Nz-Az-D)TFz-tz%s_%sz-jr�z--log-prefixz'%s'z--log-levelz%s)rr@r�r�r�rr�prefix�levelrr)
rNr�rr�rc�
rule_fragmentr�r�r�r^r3r3r4�_rich_rule_log�s
zip4tables._rich_rule_logcCs�|js
gSddd�|}|jjj||t�}|j|�}d||d||fg}	|	|j|�7}	|	|7}	t|j�t	krrd}
n,t|j�t
kr�d}
nt|j�tkr�d}
nd	}
|	d
dd|
g7}	|	|j|jj
�7}	|	S)
Nz-Az-D)TFz-tz%s_%sZacceptZrejectZdrop�unknownz-jZAUDITz--type)r
r@r�r�r�rrr�r�rrrrr)rNr�rr�rcrr�r�r�r^Z_typer3r3r4�_rich_rule_audits$
zip4tables._rich_rule_auditcCs2|js
gSddd�|}|jjj||t�}|j|�}d||f}	t|j�tkrXddg}
n�t|j�tkr�ddg}
|jjr�|
d|jjg7}
nnt|j�t	kr�dd	g}
nVt|j�t
kr�d
}|jjj||t�}d||f}	ddd|jjg}
ntt
d
t|j���d|||	g}||j|�7}|||
7}||j|jj�7}|S)Nz-Az-D)TFz%s_%sz-jr�r�z
--reject-withr�r!�MARKz--set-xmarkzUnknown action %sz-t)r�r@r�r�r�r	r�rrrrr;r
rrrr)rNr�rr�rcrr�r�r�rdZrule_actionr^r3r3r4�_rich_rule_action$s4


zip4tables._rich_rule_actioncCs�|sgSg}|jr�|jr"|jd�td|j�rB|dt|j�g7}q�td|j�r||jjd�}|dt|d�d|dg7}q�|d|jg7}nD|jr�|ddg7}|jr�|jd�|jj	j
|jd	�}|d
|j|g7}|S)N�!r%z-dr�rr]z-mr;r�z--match-set)r�r�rfr	rr
r�r�r@r��_ipset_match_flags)rNZ	rich_destrr�r�r3r3r4�_rich_rule_destination_fragmentFs&
"
z)ip4tables._rich_rule_destination_fragmentcCs|sgSg}|jr�|jr"|jd�td|j�rB|dt|j�g7}nHtd|j�r||jjd�}|dt|d�d|dg7}n|d|jg7}n�t|d�r�|jr�|ddg7}|jr�|jd�|d	|jg7}nPt|d
�o�|j	�r|ddg7}|jr�|jd�|j
jj|j	d�}|d
|j	|g7}|S)Nrr%z-sr�rr]r�z-mz--mac-sourcer�r;r�z--match-set)
r�r�rfr	rr
r��hasattrr�r�r@r�r)rNZrich_sourcerr�r�r3r3r4�_rich_rule_source_fragment^s0
"

z$ip4tables._rich_rule_source_fragmentcCsddd�|}d}|jjj||t�}	d|g}
|rD|
ddt|�g7}
|rT|
d|g7}
|rx|
|j|j�7}
|
|j|j�7}
|s�t	|j
�tkr�|
d	d
ddg7}
g}|r�|j|j
|||||
��|j|j|||||
��|j|j|||||
��n"|j|d
|	d|g|
ddg�|S)Nz-Az-D)TFr#z-pz--dportz%sz-dz-m�	conntrackz	--ctstatez
NEW,UNTRACKEDz%s_allowz-tz-jr�)r@r�r�r�rr�destinationr�sourcer�r�rrfrrr)rNr�r��proto�portrrr�rcr�rr�r3r3r4�build_policy_ports_rules{s*z"ip4tables.build_policy_ports_rulescCs�ddd�|}d}|jjj||t�}d|g}	|r<|	d|g7}	|r`|	|j|j�7}	|	|j|j�7}	|stt|j	�t
kr�|	ddd	d
g7}	g}
|r�|
j|j|||||	��|
j|j
|||||	��|
j|j|||||	��n"|
j|d|d|g|	d
dg�|
S)Nz-Az-D)TFr#z-pz-dz-mrz	--ctstatez
NEW,UNTRACKEDz%s_allowz-tz-jr�)r@r�r�r�rrrrr�r�rrfrrr)rNr�r��protocolrrr�rcr�rr�r3r3r4�build_policy_protocol_rules�s&z%ip4tables.build_policy_protocol_rulescCsddd�|}d}|jjj||t�}	d|g}
|rD|
ddt|�g7}
|rT|
d|g7}
|rx|
|j|j�7}
|
|j|j�7}
|s�t	|j
�tkr�|
d	d
ddg7}
g}|r�|j|j
|||||
��|j|j|||||
��|j|j|||||
��n"|j|d
|	d|g|
ddg�|S)Nz-Az-D)TFr#z-pz--sportz%sz-dz-mrz	--ctstatez
NEW,UNTRACKEDz%s_allowz-tz-jr�)r@r�r�r�rrrrrr�r�rrfrrr)rNr�r�rrrrr�rcr�rr�r3r3r4�build_policy_source_ports_rules�s*z)ip4tables.build_policy_source_ports_rulescCsvd}|jjj||t�}	ddd�|}
|
d|	ddd|g}|rP|dd	t|�g7}|r`|d
|g7}|ddd
|g7}|gS)Nr z-Az-D)TFz%s_allowz-tz-pz--dportz%sz-dz-jZCTz--helper)r@r�r�r�r)rNr�r�rrrZhelper_nameZmodule_short_namercr�r�r^r3r3r4�build_policy_helper_ports_rules�sz)ip4tables.build_policy_helper_ports_rulesc
	Cs�ddd�|}|jjj||t�}g}	|rH|	jdd|d|d|dd	g�n6t|�rTgS|	jdd|d|g|jd
|�dd	g�|	S)Nz-Az-D)TFz-tr#z%s_allowz-oz-jr�z-d)r@r�r�r�rfrr�)
rNr�r�r�rcr�rr�r�r�r3r3r4�build_zone_forward_rules�sz"ip4tables.build_zone_forward_rulesc
Cs,d}|jjj||tdd�}ddd�|}g}|rj|j|�}||j|�7}||j|j�7}||j|j	�7}nd}g}	|	j
dd|d	||fg|d
ddd
dg�g}|r�|j|�}||j|�7}||j|j�7}||j|j	�7}nd}d}|jjj||t�}|	j
dd|d	||fg|ddddd
dg�|	S)Nr"T)r�z-Az-D)TFrz-tz%s_%srz-o�loz-jZ
MASQUERADEr#z-mrz	--ctstatez
NEW,UNTRACKEDr�)r@r�r�r�r	rrrrrrf)
rNr�r�rrcr�r�rr�r�r3r3r4�build_policy_masquerade_rules�s6

z'ip4tables.build_policy_masquerade_rulesc
Cs
d}|jjj||t�}	ddd�|}
d}|rPtd|�rH|dt|�7}n||7}|rn|dkrn|dt|d	�7}g}|r�|j|�}
|j|�}||j	|j
�7}||j|j�7}nd
}
g}|r�|j
|j|||d|��|j
dd|
d|	|
fg|d
|dt|�ddd|g�|S)Nr"z-Az-D)TFrr%z[%s]z:%s�-rz-tz%s_%sz-pz--dportz-jZDNATz--to-destination)r@r�r�r�r	rrr	rrrrrrfr)rNr�r�rr ZtoportZtoaddrrrcr�r�Ztorr�r�r3r3r4�build_policy_forward_port_ruless2


z)ip4tables.build_policy_forward_port_rulescCs�d}|jjj||t�}ddd�|}|jdkrFddg}ddd	|jg}	ndd
g}ddd|jg}	g}
|jjj|�r|d
|}d}nd|}d}g}
|r�|
|j|j�7}
|
|j	|j
�7}
|
||	7}
|�rP|
j|j|||||
��|
j|j
|||||
��|j�r|
j|j|||||
��n:|j|�}|
jd||d||fg|j|�|
ddg�n`|jj�dk�r�|dk�r�|
j||d|g|
ddddd|g�|
j||d|g|
d|g�|
S)Nr#z-Az-D)TFr$z-pr&z-mz--icmp-typez	ipv6-icmpZicmp6z
--icmpv6-typez%s_allowr�z%s_denyz
%%REJECT%%z-tz%s_%sz-jr�z%%LOGTYPE%%r�z--log-prefixz"%s_ICMP_BLOCK: ")r@r�r�r�rAr��query_icmp_block_inversionrrrrrfrrr�rr	rr�)rNr�r�Zictrrcr�r�r�matchr�Zfinal_chainZfinal_targetrr�r3r3r4�build_policy_icmp_block_rules3sJ

 z'ip4tables.build_policy_icmp_block_rulesc	Cs�d}|jjj||t�}g}d}|jjj|�r�d}|jj�dkr�|rRd|t|�g}nd|g}|d|dd	d
ddd
d|g	}|j|�|d7}nd}|r�d|t|�g}nd|g}|d|dd	d|g}|j|�|S)Nr#r�z
%%REJECT%%r�z-Iz-Dz-tz-pz%%ICMP%%z%%LOGTYPE%%z-jr�z--log-prefixz"%s_ICMP_BLOCK: "r]r�)r@r�r�r�r)r�rirf)	rNr�r�rcr�r�Zrule_idxZ
ibi_targetr^r3r3r4�'build_policy_icmp_block_inversion_rulesds.



z1ip4tables.build_policy_icmp_block_inversion_rulescCsxd}g}||j|j�7}||j|j�7}g}|j|j|||||��|j|j|||||��|j|j|||||��|S)Nr#)rrrrrfrrr)rNr�r�rrcrr�r3r3r4�*build_policy_rich_source_destination_rules�sz4ip4tables.build_policy_rich_source_destination_rulescCs
||jkS)N)rA)rNrAr3r3r4r��szip4tables.is_ipv_supported)N)N)r�)F)F)NN)NN)NN)NN)N)N)N)7�__name__�
__module__�__qualname__rAr�Zpolicies_supportedrPrHr�rarerhrjrkrlrmrur�r�r�r�r�rDrFr�r�r�r�r�r�r�r�r�r�rrr	rrrrrrrrr!r"r#r$r&r(r+r,r-r�r3r3r3r4r?�sh

			)Pa#

!
zN

0"




&
!
1"r?c@s&eZdZdZdZddd�Zdd�ZdS)	�	ip6tablesr%Fc
Cs�g}|jddddddddd	d
g
�|dkrL|jddddddddd	dd
dg�|jdddddddd	dg	�|jdddddddd	dg	�|S)Nz-Irz-tr!z-mZrpfilterz--invertz--validmarkz-jr�r�r�z--log-prefixzrpfilter_DROP: z-pz	ipv6-icmpz$--icmpv6-type=neighbour-solicitationr�z"--icmpv6-type=router-advertisement)rf)rNr�r�r3r3r4�build_rpfilter_rules�s$



zip6tables.build_rpfilter_rulescCs�ddddddddd	g	}d
}|jdj|�g}|jddd
|g�xT|D]L}|jddd|d|ddddg
�|jjdkrF|jddd|d|ddddg
�qFW|jdddddd|g�|jdddddd|g�|S)Nz::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19ZRFC3964_IPv4r#z-tz-Nz-Iz-dz-jr�z
--reject-withzaddr-unreachr��allr�z--log-prefixz"RFC3964_IPv4_REJECT: "r�4r)r�r3)rMrgrfr@Z_log_denied)rNZ
daddr_listZ
chain_namer�Zdaddrr3r3r4�build_rfc3964_ipv4_rules�s4



z"ip6tables.build_rfc3964_ipv4_rulesN)F)r.r/r0rAr�r2r5r3r3r3r4r1�s
r1)+Zos.pathrQr�Zfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsrrrrrr	r
rZfirewallrZfirewall.errorsr
rrrrZfirewall.core.richrrrrrrrr�r�rbr�r�r5r:r>�objectr?r1r3r3r3r4�<module>s@($%* x__pycache__/fw_policy.cpython-36.pyc000064400000154111151731527030013404 0ustar003

��g=V�@s�ddlZddlZddlmZddlmZmZmZmZm	Z	m
Z
mZmZm
Z
mZddlmZmZmZmZmZmZmZmZmZmZmZddlmZddlmZddlm Z ddl!m"Z"dd	l#m$Z$Gd
d�de%�Z&dS)�N)�log)
�portStr�checkIPnMask�
checkIP6nMask�
checkProtocol�enable_ip_forwarding�check_single_address�portInPortRange�get_nf_conntrack_short_name�coalescePortRange�breakPortRange)�	Rich_Rule�Rich_Accept�Rich_Service�	Rich_Port�
Rich_Protocol�Rich_Masquerade�Rich_ForwardPort�Rich_SourcePort�Rich_IcmpBlock�
Rich_IcmpType�	Rich_Mark)�FirewallTransaction)�errors)�
FirewallError)�LastUpdatedOrderedDict)�SOURCE_IPSET_TYPESc@s�eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
�ddd�Zdd�Zdd�Zdd�Z�dd d!�Z�d
d"d#�Z�dd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Z�dd0d1�Zd2d3�Z�dd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Zd>d?�Z �dd@dA�Z!dBdC�Z"�ddDdE�Z#dFdG�Z$dHdI�Z%dJdK�Z&dLdM�Z'dNdO�Z(dPdQ�Z)dRdS�Z*�ddTdU�Z+dVdW�Z,�ddXdY�Z-dZd[�Z.d\d]�Z/d^d_�Z0d`da�Z1dbdc�Z2�dddde�Z3dfdg�Z4�ddhdi�Z5djdk�Z6dldm�Z7dndo�Z8dpdq�Z9drds�Z:dtdu�Z;dvdw�Z<�ddxdy�Z=dzd{�Z>�dd|d}�Z?d~d�Z@d�d��ZAd�d��ZBd�d��ZCd�d��ZD�dd�d��ZEd�d��ZF�dd�d��ZGd�d��ZHd�d��ZId�d��ZJd�d��ZK�dd�d��ZLd�d��ZM�dd�d��ZNd�d��ZOd�d��ZPd�d��ZQd�d��ZR�dd�d��ZSd�d��ZT�dd�d��ZUd�d��ZVd�d��ZW�dd�d��ZX�d d�d��ZY�d!d�d��ZZd�d��Z[�d"d�d��Z\d�d��Z]�d#d�d��Z^d�d��Z_d�d��Z`d�d��Za�d$d�dÄZbd�dńZc�d%d�dDŽZdd�dɄZed�d˄Zfd�d̈́Zgd�dτZh�d&d�dфZid�dӄZjd�dՄZk�d'd�dׄZld�dلZmd�dۄZnd�d݄Zod�d߄Zpd�d�Zqd�d�Zrd�d�Zsd�d�Ztd�d�Zu�d(d�d�Zv�d)d�d�Zwd�d�Zxd�d�Zyd�d�Zzd�d��Z{�d*d�d��Z|d�d��Z}d�d��Z~d�d��Zd�d��Z��d�d�Z��d�d�Z��d�d�Z��d�d�Z��d+�d	�d
�Z�dS(,�FirewallPolicycCs||_i|_i|_dS)N)�_fw�_chains�	_policies)�self�fw�r#�/usr/lib/python3.6/fw_policy.py�__init__szFirewallPolicy.__init__cCsd|j|j|jfS)Nz
%s(%r, %r))�	__class__rr )r!r#r#r$�__repr__szFirewallPolicy.__repr__cCs|jj�|jj�dS)N)r�clearr )r!r#r#r$�cleanups
zFirewallPolicy.cleanupcCs
t|j�S)N)rr)r!r#r#r$�new_transaction$szFirewallPolicy.new_transactioncCst|jj��S)N)�sortedr �keys)r!r#r#r$�get_policies)szFirewallPolicy.get_policiescCs8g}x*|j�D]}|j|�}|js|j|�qWt|�S)N)r-�
get_policy�derived_from_zone�appendr+)r!Zpolicies�p�p_objr#r#r$�"get_policies_not_derived_from_zone,s
z1FirewallPolicy.get_policies_not_derived_from_zonecCs~g}xt|j�D]h}|j|�}t|d�t|jjj��tddg�B@rt|d�t|jjj��tddg�B@r|j|�qW|S)N�
ingress_zones�HOST�ANY�egress_zones)r3�get_settings�setr�zoneZget_active_zonesr0)r!Zactive_policies�policy�settingsr#r#r$�)get_active_policies_not_derived_from_zone4s
((z8FirewallPolicy.get_active_policies_not_derived_from_zonecCs|jj|�}|j|S)N)r�check_policyr )r!r;r1r#r#r$r.>szFirewallPolicy.get_policycCs,dd�dD�|_||j|j<|j|j�dS)NcSsi|]}t�|�qSr#)r)�.0�xr#r#r$�
<dictcomp>Csz-FirewallPolicy.add_policy.<locals>.<dictcomp>�services�ports�
masquerade�
forward_ports�source_ports�icmp_blocks�rules�	protocols�icmp_block_inversionr4r7)rBrCrDrErFrGrHrIrJr4r7)r<r �name�copy_permanent_to_runtime)r!�objr#r#r$�
add_policyBs
zFirewallPolicy.add_policycCs0|j|}|jr|j|�|jj�|j|=dS)N)r �applied�unapply_policy_settingsr<r()r!r;rMr#r#r$�
remove_policyNs



zFirewallPolicy.remove_policycCs�|j|}|jrdSx|jD]}|j||dd�qWx|jD]}|j||dd�q<Wx|jD]}|j||�q\Wx|jD]}|j	|f|��qxWx|j
D]}|j||�q�Wxf|jD]\}y|j
|f|��Wq�tk
�r}z$|jtjgkr�tj|�n|�WYdd}~Xq�Xq�Wx|jD]}|j||��qWxj|jD]`}y|j|f|��WnDtk
�r�}z&|jtjgk�r�tj|�n|�WYdd}~XnX�q:Wx|jD]}|j||��q�W|j�r�|j|�dS)NF)�allow_apply)r rOr4�add_ingress_zoner7�add_egress_zonerG�add_icmp_blockrE�add_forward_portrB�add_servicerC�add_portr�coder�ALREADY_ENABLEDr�warningrI�add_protocolrF�add_source_portrH�add_rulerD�add_masquerade)r!r;rM�args�errorr#r#r$rLUsB
z(FirewallPolicy.copy_permanent_to_runtimeNcCsNxH|j�D]<}|j|}|jr q
||j�kr
tjd|�|j||d�q
WdS)NzApplying policy '%s')�use_transaction)r-r r/r=rZdebug1�apply_policy_settings)r!rbr;r2r#r#r$�apply_policies|s
zFirewallPolicy.apply_policiescCs|j|}||_dS)N)r rO)r!r;rOrMr#r#r$�set_policy_applied�s
z!FirewallPolicy.set_policy_appliedcCstj�||d�}|S)N)Zdate�sender�timeout)�time)r!rgrf�retr#r#r$Z__gen_settings�szFirewallPolicy.__gen_settingscCs|j|�jS)N)r.r<)r!r;r#r#r$r8�szFirewallPolicy.get_settingscCsj|jj|�}|j|}|r |js.|r2|jr2dS|r<d|_|dkrN|j�}n|}|r�x8|jsh|j|�n|j|�D]\}}|j|d|||�qrW|j	|�}	|js�|j
|||��xV|	D�]L}
�xD|	|
D�]6}|
dkr�|j||||�q�|
dkr�q�q�|
dk�r|j|||f|��q�|
dk�r0|j
||||�q�|
dk�rV|j|||d|d|�q�|
d	k�rr|j||||�q�|
d
k�r�|j|||d|d|�q�|
dk�r�|j|||�q�|
dk�r�|j||t|d
�|�q�|
dk�r�q�q�|
dk�r�q�q�tjd||
|�q�Wq�W|�sRx<|j�s"|j|�n|j|�D]\}}|j|d|||��q,Wd|_|dk�rf|j|�dS)NTrGrJrErBrCr�rIrFrDrH)�rule_strr4r7z5Policy '%s': Unknown setting '%s:%s', unable to applyF)rr>r rOr*r/�%_get_table_chains_for_policy_dispatch�#_get_table_chains_for_zone_dispatch�gen_chain_rulesr8�_ingress_egress_zones�_icmp_block�
_forward_port�_service�_port�	_protocol�_source_port�_masquerade�_FirewallPolicy__ruler
rr[�execute)r!�enabler;rb�_policyrM�transaction�table�chainr<�keyr`r#r#r$�_policy_settings�sj













zFirewallPolicy._policy_settingscCs|jd||d�dS)NT)rb)r)r!r;rbr#r#r$rc�sz$FirewallPolicy.apply_policy_settingscCs|jd||d�dS)NF)rb)r)r!r;rbr#r#r$rP�sz&FirewallPolicy.unapply_policy_settingscCsr|j|�j�}|j|�|j|�|j|�|j|�|j|�|j|�|j|�|j	|�|j
|�|j|�d�
}|jj
||�S)zH
        :return: exported config updated with runtime settings
        )
rBrCrGrDrE�
rich_rulesrIrFr4r7)r.Zexport_config_dict�
list_services�
list_ports�list_icmp_blocks�query_masquerade�list_forward_ports�
list_rules�list_protocols�list_source_ports�list_ingress_zones�list_egress_zonesrZ'combine_runtime_with_permanent_settings)r!r;Z	permanentZruntimer#r#r$�get_config_with_settings_dict�sz,FirewallPolicy.get_config_with_settings_dictcs�ddlm�d
��fdd�	}��fdd�}�j�jf�j�jf�j�jf�j�j	f�j
�jf||f�j�j
f�j�jf�j�jf�j�jfd�
}�j|�}�jj||�\}}	xt|	D]l}
t|	|
t��rxV|	|
D]8}t|t�r�||
d|f|��q�||
d||�q�Wq�||
d|�q�Wx�|D]�}
t||
t��r�xn||
D]J}t|t��rv||
d|f|�d|d	��n||
d||d|d	��qFWn||
d|d|d	��q(WdS)Nr)r
cs�j|�|d�d|d�dS)N)rkr)rgrf)r^)r;rkrgrf)r
r!r#r$�add_rule_wrapper�szFFirewallPolicy.set_config_with_settings_dict.<locals>.add_rule_wrappercs�j|�|d��dS)N)rk)�remove_rule)r;rk)r
r!r#r$�remove_rule_wrapper�szIFirewallPolicy.set_config_with_settings_dict.<locals>.remove_rule_wrapper)
rBrCrGrDrEr�rIrFr4r7rj)rgrf)rN)�firewall.core.richr
rW�remove_servicerX�remove_portrU�remove_icmp_blockr_�remove_masqueraderV�remove_forward_portr\�remove_protocolr]�remove_source_portrS�remove_ingress_zonerT�remove_egress_zoner�rZget_added_and_removed_settings�
isinstance�list�tuple)r!r;r<rfr�r�Z
setting_to_fnZold_settingsZadd_settingsZremove_settingsr~r`r#)r
r!r$�set_config_with_settings_dict�s:











  z,FirewallPolicy.set_config_with_settings_dictcCs&|sttj��|dkr"|jj|�dS)Nr5r6)r5r6)rr�INVALID_ZONEr�
check_zone)r!r:r#r#r$�check_ingress_zones
z!FirewallPolicy.check_ingress_zonecCs|j|�|S)N)r�)r!r:r#r#r$Z__ingress_zone_id"s
z FirewallPolicy.__ingress_zone_idrTcCs�|jj|�}|jj|�|jj�|j|}|j|�}	|	|jdkrXttj	d||f��d|jdks�d|jdks�|dkr�|jdr�ttj
d��|dkr�d|jdkr�ttj
d��|dkr�|j�}
n|}
|�rJ|jr�|j
d||
�|j||	||�|
j|j||	�|j�s:||j�k�rH|j||
d	�|
j|j|d�n|j
d
||
�n |j||	||�|
j|j||	�|dk�r~|
jd
�dS)Nr4z'%s' already in '%s'r6r5zI'ingress-zones' may only contain one of: many regular zones, ANY, or HOSTr7zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr>�
check_timeout�check_panicr � _FirewallPolicy__ingress_zone_idr<rrrZr�r*rOro�&_FirewallPolicy__register_ingress_zone�add_fail�(_FirewallPolicy__unregister_ingress_zoner=rcrerx)r!r;r:rgrfrbrRrz�_obj�zone_idr{r#r#r$rS&s<




zFirewallPolicy.add_ingress_zonecCs|j||�|jd|<dS)Nr4)�_FirewallPolicy__gen_settingsr<)r!r�r�rgrfr#r#r$Z__register_ingress_zoneSsz&FirewallPolicy.__register_ingress_zonecCs�|jj|�}|jj�|j|}|j|�}||jdkrLttjd||f��|dkr^|j	�}n|}|j
r�t|jd�dkr�|j||�n|j
d||�|j||�|j|j||dd�||j�kr�|j
d||�n|j|j||�|dkr�|jd�|S)Nr4z'%s' not in '%s'rjFT)rr>r�r r�r<rr�NOT_ENABLEDr*rO�lenrPror�r�r�r=�add_postrx)r!r;r:rbrzr�r�r{r#r#r$r�Vs,




z"FirewallPolicy.remove_ingress_zonecCs||jdkr|jd|=dS)Nr4)r<)r!r�r�r#r#r$Z__unregister_ingress_zoneysz(FirewallPolicy.__unregister_ingress_zonecCs|j|�|j|�dkS)Nr4)r�r8)r!r;r:r#r#r$�query_ingress_zone}sz!FirewallPolicy.query_ingress_zonecCst|j|�dj��S)Nr4)r�r8r,)r!r;r#r#r$r��sz!FirewallPolicy.list_ingress_zonescCs&|sttj��|dkr"|jj|�dS)Nr5r6)r5r6)rrr�rr�)r!r:r#r#r$�check_egress_zone�s
z FirewallPolicy.check_egress_zonecCs|j|�|S)N)r�)r!r:r#r#r$Z__egress_zone_id�s
zFirewallPolicy.__egress_zone_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}	|	|jdkrXttj	d||f��d|jdks�d|jdks�|dkr�|jdr�ttj
d��|dkr�d|jdkr�ttj
d��|dkr�|j�}
n|}
|�rJ|jr�|j
d||
�|j||	||�|
j|j||	�|j�s:||j�k�rH|j||
d	�|
j|j|d�n|j
d
||
�n |j||	||�|
j|j||	�|dk�r~|
jd
�dS)Nr7z'%s' already in '%s'r6r5zH'egress-zones' may only contain one of: many regular zones, ANY, or HOSTr4zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr>r�r�r �_FirewallPolicy__egress_zone_idr<rrrZr�r*rOro�%_FirewallPolicy__register_egress_zoner��'_FirewallPolicy__unregister_egress_zoner=rcrerx)r!r;r:rgrfrbrRrzr�r�r{r#r#r$rT�s<




zFirewallPolicy.add_egress_zonecCs|j||�|jd|<dS)Nr7)r�r<)r!r�r�rgrfr#r#r$Z__register_egress_zone�sz%FirewallPolicy.__register_egress_zonecCs�|jj|�}|jj�|j|}|j|�}||jdkrLttjd||f��|dkr^|j	�}n|}|j
r�t|jd�dkr�|j||�n|j
d||�|j||�|j|j||dd�||j�kr�|j
d||�n|j|j||�|dkr�|jd�|S)Nr7z'%s' not in '%s'rjFT)rr>r�r r�r<rrr�r*rOr�rPror�r�r�r=r�rx)r!r;r:rbrzr�r�r{r#r#r$r��s,




z!FirewallPolicy.remove_egress_zonecCs||jdkr|jd|=dS)Nr7)r<)r!r�r�r#r#r$Z__unregister_egress_zone�sz'FirewallPolicy.__unregister_egress_zonecCs|j|�|j|�dkS)Nr7)r�r8)r!r;r:r#r#r$�query_egress_zone�sz FirewallPolicy.query_egress_zonecCst|j|�dj��S)Nr7)r�r8r,)r!r;r#r#r$r��sz FirewallPolicy.list_egress_zonescCs|j�dS)N)Zcheck)r!�ruler#r#r$�
check_rule�szFirewallPolicy.check_rulecCs|j|�t|�S)N)r��str)r!r�r#r#r$Z	__rule_id�s
zFirewallPolicy.__rule_idcCsx|sdS|jr,t|j�rdSt|j�rtdSnHt|d�r@|jr@dSt|d�rt|jrt|j|j�|j|j�|j|j�SdS)N�ipv4�ipv6�mac��ipset)	Zaddrrr�hasattrr�r��_check_ipset_type_for_source�_check_ipset_applied�
_ipset_family)r!�sourcer#r#r$�_rule_source_ipv�s

zFirewallPolicy._rule_source_ipvcCs|j||||�dS)N)�
_rule_prepare)r!ryr;r�r{r#r#r$Z__ruleszFirewallPolicy.__rulecCsL|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|j�s�|jr�t|jt
�r�d|jdkr�tt	jd��d|jdkr�tt	jd��x6|jdD](}
|
dkr�q�|jjj|
�r�tt	jd	��q�W|j�r�t|jt��r�d|jdk�r,|jj�r�tt	jd
��nb|jd�r�|jj�sNtt	jd��x>|jdD]0}
|
dk�rl�qZ|jjj|
��rZtt	jd���qZW|j�r�t|jt��r�x>|jdD]0}
|
dk�rq�|jjj|
��r�tt	jd
���q�W|dk�r�|j�}n|}|j�r|jd|||�|j||||�|j|j||�|dk�rH|jd�|S)NrHz'%s' already in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfaceszAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesT)r6r5)rr>r�r�r �_FirewallPolicy__rule_idr<r/rrrZ�elementr�rr�r:�list_interfacesr�
to_address�INVALID_FORWARD�actionrr*rOrw�_FirewallPolicy__register_ruler�� _FirewallPolicy__unregister_rulerx)r!r;r�rgrfrbrzr��rule_id�_namer:r{r#r#r$r^
s`










zFirewallPolicy.add_rulecCs|j||�|jd|<dS)NrH)r�r<)r!r�r�rgrfr#r#r$Z__register_ruleEszFirewallPolicy.__register_rulec	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrHz'%s' not in '%s'FT)rr>r�r r�r<r/rrr�r*rOrwr�r�rx)	r!r;r�rbrzr�r�r�r{r#r#r$r�Is"




zFirewallPolicy.remove_rulecCs||jdkr|jd|=dS)NrH)r<)r!r�r�r#r#r$Z__unregister_ruledsz FirewallPolicy.__unregister_rulecCs|j|�|j|�dkS)NrH)r�r8)r!r;r�r#r#r$�
query_rulehszFirewallPolicy.query_rulecCst|j|�dj��S)NrH)r�r8r,)r!r;r#r#r$r�kszFirewallPolicy.list_rulescCs|jj|�dS)N)r�
check_service)r!�servicer#r#r$r�pszFirewallPolicy.check_servicecCs|j|�|S)N)r�)r!r�r#r#r$Z__service_idss
zFirewallPolicy.__service_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|dkrz|j�}
n|}
|jr�|j
d|||
�|j||||�|
j|j||�|dkr�|
jd�|S)NrBz'%s' already in '%s'T)rr>r�r�r �_FirewallPolicy__service_idr<r/rrrZr*rOrr�!_FirewallPolicy__register_servicer��#_FirewallPolicy__unregister_servicerx)r!r;r�rgrfrbrzr��
service_idr�r{r#r#r$rWws&




zFirewallPolicy.add_servicecCs|j||�|jd|<dS)NrB)r�r<)r!r�r�rgrfr#r#r$Z__register_service�sz!FirewallPolicy.__register_servicec	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrBz'%s' not in '%s'FT)rr>r�r r�r<r/rrr�r*rOrrr�r�rx)	r!r;r�rbrzr�r�r�r{r#r#r$r��s"




zFirewallPolicy.remove_servicecCs||jdkr|jd|=dS)NrB)r<)r!r�r�r#r#r$Z__unregister_service�sz#FirewallPolicy.__unregister_servicecCs|j|�|j|�dkS)NrB)r�r8)r!r;r�r#r#r$�
query_service�szFirewallPolicy.query_servicecCs|j|�dj�S)NrB)r8r,)r!r;r#r#r$r��szFirewallPolicy.list_servicescCsTg}xJ|D]B}y|jjj|�}Wn tk
r@ttj|��YnX|j|�q
W|S)N)r�helper�
get_helperrr�INVALID_HELPERr0)r!�helpers�_helpersr��_helperr#r#r$�get_helpers_for_service_helpers�s
z.FirewallPolicy.get_helpers_for_service_helperscCs�g}x�|D]�}y|jjj|�}Wn tk
r@ttj|��YnXt|j�dkr�t|j	�}y|jjj|�}|j
|�Wq�tk
r�|r�tjd|�w
Yq�Xq
|j
|�q
W|S)NrjzHelper '%s' is not available)
rr�r�rrr�r�rCr
�moduler0rr[)r!�modulesryr�r�r��_module_short_namer�r#r#r$�get_helpers_for_service_modules�s"


z.FirewallPolicy.get_helpers_for_service_modulescCs|jj|�|jj|�dS)N)r�
check_port�check_tcpudp)r!�port�protocolr#r#r$r��szFirewallPolicy.check_portcCs|j||�t|d�|fS)N�-)r�r)r!r�r�r#r#r$Z	__port_id�szFirewallPolicy.__port_idcs�|jj|�}|jj|�|jj�|j|}tt�fdd�|jd��}	x@|	D]8}
t||
d�rN|j	rl|j	n|}t
tjd|�|f��qNWt
|dd�|	D��\}}
|dkr�|j�}n|}|j�rx$|D]}|jd|t|d	��|�q�Wx$|
D]}|jd
|t|d	��|�q�Wx:|D]2}|j|��}
|j||
||�|j|j||
��qWx*|
D]"}|j|��}
|j|j||
��qNW|dk�r�|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$�<lambda>�sz)FirewallPolicy.add_port.<locals>.<lambda>rCrz'%s:%s' already in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$�
<listcomp>�sz+FirewallPolicy.add_port.<locals>.<listcomp>Tr�F)rr>r�r�r r��filterr<r	r/rrrZrr*rOrsr�_FirewallPolicy__port_id�_FirewallPolicy__register_portr�� _FirewallPolicy__unregister_portr�rx)r!r;r�r�rgrfrbrzr��existing_port_ids�port_idr��added_ranges�removed_rangesr{�ranger#)r�r$rX�s:









zFirewallPolicy.add_portcCs|j||�|jd|<dS)NrC)r�r<)r!r�r�rgrfr#r#r$Z__register_portszFirewallPolicy.__register_portcs�|jj|�}|jj�|j|}tt�fdd�|jd��}xB|D]}t||d�rBPqBW|jrf|jn|}	t	t
jd|�|	f��t|dd�|D��\}
}|dkr�|j
�}n|}|j�rx$|
D]}
|jd|t|
d	��|�q�Wx$|D]}
|jd
|t|
d	��|�q�Wx:|
D]2}
|j|
��}|j||dd�|j|j||��qWx*|D]"}
|j|
��}|j|j||��qDW|dk�r~|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$r�sz,FirewallPolicy.remove_port.<locals>.<lambda>rCrz'%s:%s' not in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$r�#sz.FirewallPolicy.remove_port.<locals>.<listcomp>Tr�F)rr>r�r r�r�r<r	r/rrr�rr*rOrsrr�r�r�r�r�rx)r!r;r�r�rbrzr�r�r�r�r�r�r{r�r#)r�r$r�s:









zFirewallPolicy.remove_portcCs||jdkr|jd|=dS)NrC)r<)r!r�r�r#r#r$Z__unregister_port=sz FirewallPolicy.__unregister_portcCs6x0|j|�dD]\}}t||�r||krdSqWdS)NrCTF)r8r	)r!r;r�r�rsrtr#r#r$�
query_portAszFirewallPolicy.query_portcCst|j|�dj��S)NrC)r�r8r,)r!r;r#r#r$r�HszFirewallPolicy.list_portscCst|�sttj|��dS)N)rrrZINVALID_PROTOCOL)r!r�r#r#r$�check_protocolMszFirewallPolicy.check_protocolcCs|j|�|S)N)r�)r!r�r#r#r$Z
__protocol_idQs
zFirewallPolicy.__protocol_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|dkrz|j�}
n|}
|jr�|j
d|||
�|j||||�|
j|j||�|dkr�|
jd�|S)NrIz'%s' already in '%s'T)rr>r�r�r �_FirewallPolicy__protocol_idr<r/rrrZr*rOrt�"_FirewallPolicy__register_protocolr��$_FirewallPolicy__unregister_protocolrx)r!r;r�rgrfrbrzr��protocol_idr�r{r#r#r$r\Us&




zFirewallPolicy.add_protocolcCs|j||�|jd|<dS)NrI)r�r<)r!r�r�rgrfr#r#r$Z__register_protocolrsz"FirewallPolicy.__register_protocolc	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrIz'%s' not in '%s'FT)rr>r�r r�r<r/rrr�r*rOrtr�r�rx)	r!r;r�rbrzr�r�r�r{r#r#r$r�vs$





zFirewallPolicy.remove_protocolcCs||jdkr|jd|=dS)NrI)r<)r!r�r�r#r#r$Z__unregister_protocol�sz$FirewallPolicy.__unregister_protocolcCs|j|�|j|�dkS)NrI)r�r8)r!r;r�r#r#r$�query_protocol�szFirewallPolicy.query_protocolcCst|j|�dj��S)NrI)r�r8r,)r!r;r#r#r$r��szFirewallPolicy.list_protocolscCs|j||�t|d�|fS)Nr�)r�r)r!r�r�r#r#r$Z__source_port_id�szFirewallPolicy.__source_port_idcs�|jj|�}|jj|�|jj�|j|}tt�fdd�|jd��}	x@|	D]8}
t||
d�rN|j	rl|j	n|}t
tjd|�|f��qNWt
|dd�|	D��\}}
|dkr�|j�}n|}|j�rx$|D]}|jd|t|d	��|�q�Wx$|
D]}|jd
|t|d	��|�q�Wx:|D]2}|j|��}
|j||
||�|j|j||
��qWx*|
D]"}|j|��}
|j|j||
��qNW|dk�r�|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$r��sz0FirewallPolicy.add_source_port.<locals>.<lambda>rFrz'%s:%s' already in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$r��sz2FirewallPolicy.add_source_port.<locals>.<listcomp>Tr�F)rr>r�r�r r�r�r<r	r/rrrZrr*rOrur�_FirewallPolicy__source_port_id�%_FirewallPolicy__register_source_portr��'_FirewallPolicy__unregister_source_portr�rx)r!r;r�r�rgrfrbrzr�r�r�r�r�r�r{r�r#)r�r$r]�s:









zFirewallPolicy.add_source_portcCs|j||�|jd|<dS)NrF)r�r<)r!r�r�rgrfr#r#r$Z__register_source_port�sz%FirewallPolicy.__register_source_portcs�|jj|�}|jj�|j|}tt�fdd�|jd��}xB|D]}t||d�rBPqBW|jrf|jn|}	t	t
jd|�|	f��t|dd�|D��\}
}|dkr�|j
�}n|}|j�rx$|
D]}
|jd|t|
d	��|�q�Wx$|D]}
|jd
|t|
d	��|�q�Wx:|
D]2}
|j|
��}|j||dd�|j|j||��qWx*|D]"}
|j|
��}|j|j||��qDW|dk�r~|jd�|S)Ncs|d�kS)Nrjr#)r@)r�r#r$r��sz3FirewallPolicy.remove_source_port.<locals>.<lambda>rFrz'%s:%s' not in '%s'cSsg|]\}}|�qSr#r#)r?rsrtr#r#r$r��sz5FirewallPolicy.remove_source_port.<locals>.<listcomp>Tr�F)rr>r�r r�r�r<r	r/rrr�rr*rOrurr�r�r�r�r�rx)r!r;r�r�rbrzr�r�r�r�r�r�r{r�r#)r�r$r��s:









z!FirewallPolicy.remove_source_portcCs||jdkr|jd|=dS)NrF)r<)r!r�r�r#r#r$Z__unregister_source_port�sz'FirewallPolicy.__unregister_source_portcCs6x0|j|�dD]\}}t||�r||krdSqWdS)NrFTF)r8r	)r!r;r�r�rsrtr#r#r$�query_source_port�sz FirewallPolicy.query_source_portcCst|j|�dj��S)NrF)r�r8r,)r!r;r#r#r$r�sz FirewallPolicy.list_source_portscCsdS)NTr#)r!r#r#r$Z__masquerade_idszFirewallPolicy.__masquerade_idcCs8|jj|�}|jj|�|jj�|j|}|j�}||jdkrb|jrN|jn|}tt	j
d|��|js�d|jdkr�tt	jd��d|jdkr�tt	jd��x6|jdD](}	|	dkr�q�|jjj
|	�r�tt	jd	��q�W|dkr�|j�}
n|}
|j�r|jd
||
�|j||||�|
j|j||�|dk�r4|
jd
�|S)NrDz"masquerade already enabled in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesT)rr>r�r�r �_FirewallPolicy__masquerade_idr<r/rrrZr�r:r�r*rOrv�$_FirewallPolicy__register_masquerader��&_FirewallPolicy__unregister_masqueraderx)r!r;rgrfrbrzr��
masquerade_idr�r:r{r#r#r$r_
s:





zFirewallPolicy.add_masqueradecCs|j||�|jd|<dS)NrD)r�r<)r!r�r�rgrfr#r#r$Z__register_masquerade2sz$FirewallPolicy.__register_masqueradecCs�|jj|�}|jj�|j|}|j�}||jdkrV|jrB|jn|}ttj	d|��|dkrh|j
�}n|}|jr�|jd||�|j
|j||�|dkr�|jd�|S)NrDzmasquerade not enabled in '%s'FT)rr>r�r r�r<r/rrr�r*rOrvr�r�rx)r!r;rbrzr�r�r�r{r#r#r$r�6s"




z FirewallPolicy.remove_masqueradecCs||jdkr|jd|=dS)NrD)r<)r!r�r�r#r#r$Z__unregister_masqueradePsz&FirewallPolicy.__unregister_masqueradecCs|j�|j|�dkS)NrD)r�r8)r!r;r#r#r$r�TszFirewallPolicy.query_masqueradecCs^|jj|�|jj|�|r(|jj|�|rBt||�sBttj|��|rZ|rZttjd��dS)Nz.port-forwarding is missing to-port AND to-addr)rr�r�rrrZINVALID_ADDRr�)r!�ipvr�r��toport�toaddrr#r#r$�check_forward_portYs
z!FirewallPolicy.check_forward_portcCsLtd|�r|jd||||�n|jd||||�t|d�|t|d�t|�fS)Nr�r�r�)rrrr�)r!r�r�r�r�r#r#r$Z__forward_port_idfs


z FirewallPolicy.__forward_port_idc	CsZ|jj|�}	|jj|�|jj�|j|	}
|j||||�}||
jdkrt|
jrV|
jn|	}tt	j
d|||||f��|
js�d|
jdkr�|r�tt	jd��nR|
jdr�|s�tt	jd��x6|
jdD](}
|
dkr�q�|jjj
|
�r�tt	jd��q�W|dk�r|j�}n|}|
j�r"|jd	|	|||||�|j|
|||�|j|j|
|�|dk�rV|jd	�|	S)
NrEz'%s:%s:%s:%s' already in '%s'r5r7zAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zoner6zS'forward-port' cannot be used in a policy if an egress zone has assigned interfacesT)rr>r�r�r � _FirewallPolicy__forward_port_idr<r/rrrZr�r:r�r�r*rOrq�&_FirewallPolicy__register_forward_portr��(_FirewallPolicy__unregister_forward_portrx)r!r;r�r�r�r�rgrfrbrzr��
forward_idr�r:r{r#r#r$rVnsB






zFirewallPolicy.add_forward_portcCs|j||�|jd|<dS)NrE)r�r<)r!r�rrgrfr#r#r$Z__register_forward_port�sz&FirewallPolicy.__register_forward_portcCs�|jj|�}|jj�|j|}|j||||�}	|	|jdkrh|jrJ|jn|}
ttj	d|||||
f��|dkrz|j
�}n|}|jr�|jd||||||�|j
|j||	�|dkr�|jd�|S)NrEz'%s:%s:%s:%s' not in '%s'FT)rr>r�r rr<r/rrr�r*rOrqr�rrx)r!r;r�r�r�r�rbrzr�rr�r{r#r#r$r��s&



z"FirewallPolicy.remove_forward_portcCs||jdkr|jd|=dS)NrE)r<)r!r�rr#r#r$Z__unregister_forward_port�sz(FirewallPolicy.__unregister_forward_portcCs"|j||||�}||j|�dkS)NrE)rr8)r!r;r�r�r�r�rr#r#r$�query_forward_port�sz!FirewallPolicy.query_forward_portcCst|j|�dj��S)NrE)r�r8r,)r!r;r#r#r$r��sz!FirewallPolicy.list_forward_portscCs|jj|�dS)N)rZcheck_icmptype)r!�icmpr#r#r$�check_icmp_block�szFirewallPolicy.check_icmp_blockcCs|j|�|S)N)r)r!rr#r#r$Z__icmp_block_id�s
zFirewallPolicy.__icmp_block_idcCs�|jj|�}|jj|�|jj�|j|}|j|�}||jdkrh|jrP|jn|}	tt	j
d||	f��|dkrz|j�}
n|}
|jr�|j
d|||
�|j||||�|
j|j||�|dkr�|
jd�|S)NrGz'%s' already in '%s'T)rr>r�r�r �_FirewallPolicy__icmp_block_idr<r/rrrZr*rOrp�$_FirewallPolicy__register_icmp_blockr��&_FirewallPolicy__unregister_icmp_blockrx)r!r;rrgrfrbrzr��icmp_idr�r{r#r#r$rU�s&




zFirewallPolicy.add_icmp_blockcCs|j||�|jd|<dS)NrG)r�r<)r!r�rrgrfr#r#r$Z__register_icmp_block�sz$FirewallPolicy.__register_icmp_blockc	Cs�|jj|�}|jj�|j|}|j|�}||jdkr\|jrD|jn|}ttj	d||f��|dkrn|j
�}n|}|jr�|jd|||�|j
|j||�|dkr�|jd�|S)NrGz'%s' not in '%s'FT)rr>r�r rr<r/rrr�r*rOrpr�r
rx)	r!r;rrbrzr�rr�r{r#r#r$r��s"




z FirewallPolicy.remove_icmp_blockcCs||jdkr|jd|=dS)NrG)r<)r!r�rr#r#r$Z__unregister_icmp_blocksz&FirewallPolicy.__unregister_icmp_blockcCs|j|�|j|�dkS)NrG)rr8)r!r;rr#r#r$�query_icmp_blockszFirewallPolicy.query_icmp_blockcCs|j|�dj�S)NrG)r8r,)r!r;r#r#r$r�szFirewallPolicy.list_icmp_blockscCsdS)NTr#)r!r#r#r$Z__icmp_block_inversion_idsz(FirewallPolicy.__icmp_block_inversion_idc
Cs|jj|�}|jj�|j|}|j�}||jdkrV|jrB|jn|}ttj	d|��|dkrh|j
�}n|}|jr�x&|j|�dD]}	|j
d||	|�q�W|jd||�|j|||�|j|j|||�|j�rx&|j|�dD]}	|j
d||	|�q�W|jd||�|dk�r|jd�|S)NrJz,icmp-block-inversion already enabled in '%s'rGFT)rr>r�r �(_FirewallPolicy__icmp_block_inversion_idr<r/rrrZr*rOr8rp�_icmp_block_inversion�._FirewallPolicy__register_icmp_block_inversionr��*_FirewallPolicy__undo_icmp_block_inversionrx)
r!r;rfrbrzr��icmp_block_inversion_idr�r{r`r#r#r$�add_icmp_block_inversions6





z'FirewallPolicy.add_icmp_block_inversioncCs|jd|�|jd|<dS)NrrJ)r�r<)r!r�rrfr#r#r$Z__register_icmp_block_inversionEsz.FirewallPolicy.__register_icmp_block_inversioncCs�|j�}|jr6x&|j|�dD]}|jd|||�qW||jdkrP|jd|=|jr~x&|j|�dD]}|jd|||�qfW|jd�dS)NrGFrJT)r*rOr8rpr<rx)r!rzr�rr{r`r#r#r$Z__undo_icmp_block_inversionJsz*FirewallPolicy.__undo_icmp_block_inversionc	Cs|jj|�}|jj�|j|}|j�}||jdkrV|jrB|jn|}ttj	d|��|dkrh|j
�}n|}|jr�x&|j|�dD]}|j
d|||�q�W|jd||�|j||�|j|j||d�|j�rx&|j|�dD]}|j
d|||�q�W|jd||�|dk�r|jd�|S)NrJz(icmp-block-inversion not enabled in '%s'rGFT)rr>r�r r
r<r/rrr�r*rOr8rpr�0_FirewallPolicy__unregister_icmp_block_inversionr�rrx)	r!r;rbrzr�rr�r{r`r#r#r$�remove_icmp_block_inversion\s6






z*FirewallPolicy.remove_icmp_block_inversioncCs||jdkr|jd|=dS)NrJ)r<)r!r�rr#r#r$Z!__unregister_icmp_block_inversion�sz0FirewallPolicy.__unregister_icmp_block_inversioncCs|j�|j|�dkS)NrJ)r
r8)r!r;r#r#r$�query_icmp_block_inversion�sz)FirewallPolicy.query_icmp_block_inversionc
Cs�|jjj|�}|jr*|jjj|jd}n|}|rT||jkrt||f|j|krtdSn ||jksp||f|j|krtdSx@|jj�D]2}|jr�||j	�kr�|j
||||�}	|j||	�q�W|j||||fg�|j
|j||||fg�dS)Nr)rr;r.r/r:Z_zone_policiesr�enabled_backends�policies_supportedZget_available_tablesZbuild_policy_chain_rules�	add_rules�_register_chainsr�)
r!r;�creater|r}r{rMZtracking_policy�backendrHr#r#r$rn�s$

zFirewallPolicy.gen_chain_rulescCsbx\|D]T\}}|r,|jj|g�j||f�q|j|j||f�t|j|�dkr|j|=qWdS)Nr)r�
setdefaultr0�remover�)r!r;rZtablesr|r}r#r#r$r�szFirewallPolicy._register_chainscCs$|jjj|�dkrdS|jjj|�S)Nzhash:mac)rr��get_typeZ
get_family)r!rKr#r#r$r��szFirewallPolicy._ipset_familycCs|jjj|�S)N)rr�r)r!rKr#r#r$Z__ipset_type�szFirewallPolicy.__ipset_typecCsdj|g|jjj|��S)N�,)�joinrr�Z
get_dimension)r!rK�flagr#r#r$�_ipset_match_flags�sz!FirewallPolicy._ipset_match_flagscCs|jjj|�S)N)rr�Z
check_applied)r!rKr#r#r$r��sz#FirewallPolicy._check_ipset_appliedcCs*|j|�}|tkr&ttjd||f��dS)Nz.ipset '%s' with type '%s' not usable as source)�_FirewallPolicy__ipset_typerrrZ
INVALID_IPSET)r!rKZ_typer#r#r$r��s
z+FirewallPolicy._check_ipset_type_for_sourcecs�t|j�tkr��jjj|jj�}|dkr2|jjg}xR|jD]H}||krHq:�j|�|j	|�t
j|�}||j_�j|||||d�q:Wg}	|j
r�|j
g}	nH|jr�t|jt�s�t|jt�r�jjj|jj���jr�fdd�dD�}	�j|j�}
|
�r&|j
�r |j
|
k�r&ttjd|
|j
f��n|
g}	|	�s4ddg}	�fdd�|	D�}	|	|_�x2t�fdd�|	D��D�]}t|j�tk�r��jjj|jj�}g}t|j�d	k�r�|j�r�ttjd
��xB|	D].}
|
|jk�r�|j|
��r�|j	|j|
��q�Wn
|j	d��x~|D�]�}t|j�tk�r�j|j |�}|�j!|j"�7}t#t|�dd�d
�}g}x�|D]�}|j$}t%|�}|j&dd�}|j	|�|j
dk�r�|j|j
��r��qTt|j'�dk�r�|j	|�n:x8|j'D].\}}|j(||||||j|�}|j)||��q�W�qTW|j*|�x4|j'D]*\}}|j+||||||�}|j)||��q
Wx.|j,D]$}|j-|||||�}|j)||��q@Wx4|j.D]*\}}|j/||||||�}|j)||��qpW�qW�qft|j�t0k�r�|jj1}|jj2}�j3||�|j+||||d|�}|j)||��qft|j�t4k�r<|jj5}�j6|�|j-|||d|�}|j)||��qft|j�t7k�r�|�rzx&|	D]}
|j|
��rX|j8t9|
��qXW|j:|||�}|j)||��qft|j�t;k�r4|jj1}|jj2}|jj<}|jj=}xD|	D]<}
|j|
��r�j>|
||||�|�r�|�r�|j8t9|
��q�W|j?|||||||�}|j)||��qft|j�t@k�r�|jj1}|jj2}�j3||�|j/||||d|�}|j)||�n�t|j�tk�s�t|j�tk�r>�jjj|jj��|j
�r�j�r�|j
�jk�r�ttjAd|j
|jjf��t|j�tk�r |j�r t|j�tk�r ttjd��|jB||�|�}|j)||�n>|jdk�rf|jC|||�}|j)||�nttjdt|j����qfWdS)N)�included_servicescsg|]}|�jkr|�qSr#)�destination)r?r�)�ictr#r$r��sz0FirewallPolicy._rule_prepare.<locals>.<listcomp>r�r�z;Source address family '%s' conflicts with rule family '%s'.csg|]}�jj|�r|�qSr#)r�is_ipv_enabled)r?r�)r!r#r$r��scsg|]}�jj|��qSr#)r�get_backend_by_ipv)r?r@)r!r#r$r��srz"Destination conflict with service.cSs|jS)N)rK)r@r#r#r$r�sz.FirewallPolicy._rule_prepare.<locals>.<lambda>)r~�	conntrack�natr�rjz3rich rule family '%s' conflicts with icmp type '%s'z'IcmpBlock not usable with accept actionzUnknown element %s)r�r�)D�typer�rrr��get_servicerK�includesr�r0�copy�deepcopyr��familyr�rr�config�get_icmptyper%r�r�rrZINVALID_RULE�ipvsr9r��is_ipv_supportedr�rr�r�r�r�r+r�r
�replacerC�build_policy_helper_ports_rulesrZadd_modules�build_policy_ports_rulesrI�build_policy_protocol_rulesrF�build_policy_source_ports_rulesrr�r�r�r�valuer�rr�r�build_policy_masquerade_rulesrZto_portr�r�build_policy_forward_port_rulesrZINVALID_ICMPTYPE�build_policy_icmp_block_rulesZ*build_policy_rich_source_destination_rules)r!ryr;r�r{r$�svc�includeZ_ruler3Z
source_ipvrZdestinationsr�r%r�r�r�r�r��
nat_moduler��protorHr�r�r�r#)r&r!r$r��s




 









zFirewallPolicy._rule_preparecCsb|jjj|�}|j|j|�}||j|j�7}tt|�dd�d�}|dkrN|g}x@|j	D]6}||krdqV|j
|�|j|�|j|||||d�qVWg}	xndD]f}
|jj
|
�s�q�|jj|
�}t|j�dkr�|
|jkr�|	j||j|
f�q�|df|	kr�|	j|df�q�W�xV|	D�]L\}}x�|D]�}
|
j}t|�}|
jjdd	�}|j|�|
jd
k�rf|j|
j��rf�qt|
j�dk�r�|j|�n:x8|
jD].\}}|j||||||
j|�}|j||��q�W�qWx2|jD](\}}|j|||||�}|j||��q�Wx,|jD]"}|j||||�}|j||��q�Wx2|jD](\}}|j|||||�}|j||��q,W�qWdS)
NcSs|jS)N)rK)r@r#r#r$r��sz)FirewallPolicy._service.<locals>.<lambda>)r~)r$r�r�rr)r*r�rj)r�r�) rr�r,r�r�r�r�r+r9r-r�r0rrr'r(r�r%r�r
r5Z
add_moduler0r4rCr6rKrr7rIr8rFr9)r!ryr;r�r{r$r>r�r?Zbackends_ipvr�rr%r�r�r�r@r�rArHr�r#r#r$rr�sb






zFirewallPolicy._servicecCs<x6|jj�D](}|jsq|j||||�}|j||�qWdS)N)rrrr7r)r!ryr;r�r�r{rrHr#r#r$rs�s
zFirewallPolicy._portcCs:x4|jj�D]&}|jsq|j|||�}|j||�qWdS)N)rrrr8r)r!ryr;r�r{rrHr#r#r$rt�s
zFirewallPolicy._protocolcCs<x6|jj�D](}|jsq|j||||�}|j||�qWdS)N)rrrr9r)r!ryr;r�r�r{rrHr#r#r$ru�s
zFirewallPolicy._source_portcCs8d}|jt|�|jj|�}|j||�}|j||�dS)Nr�)r�rrr(r;r)r!ryr;r{r�rrHr#r#r$rv�s
zFirewallPolicy._masqueradecCsXtd|�rd}nd}|r(|r(|jt|�|jj|�}	|	j||||||�}
|j|	|
�dS)Nr�r�)rr�rrr(r<r)r!ryr;r{r�r�r�r�r�rrHr#r#r$rq�s

zFirewallPolicy._forward_portc
Cs�|jjj|�}xl|jj�D]^}|js&qd}|jrXx&dD]}||jkr6|j|�s6d}Pq6W|r^q|j|||�}	|j||	�qWdS)NFr�r�T)r�r�)	rr1r2rrr%r4r=r)
r!ryr;rr{r&rZskip_backendr�rHr#r#r$rp�s


zFirewallPolicy._icmp_blockcCsh|j|j}|dkrdS|j|�r0|dkr0dSx2|jj�D]$}|jsHq<|j||�}|j||�q<WdS)N�DROP�
%%REJECT%%�REJECTZACCEPT)rBrCrD)r �targetrrrrZ'build_policy_icmp_block_inversion_rulesr)r!ryr;r{rErrHr#r#r$rsz$FirewallPolicy._icmp_block_inversionc	Cs�x|D]}|j|�qWx|D]}|j|�qWd|ks@d|krXt|�dkrXttjd��d|kshd|kr�t|�dkr�ttjd��|s�|r�|r�|r�d|kr�d|kr�ttjd|��|s�|r�|r�|r�d|kr�d|kr�ttjd|��dS)Nr6r5rjzI'ingress-zones' may only contain one of: many regular zones, ANY, or HOSTzH'egress-zones' may only contain one of: many regular zones, ANY, or HOSTzpolicy "%s" has no ingresszpolicy "%s" has no egress)r�r�r�rrr�)	r!r;r4r7�ingress_interfaces�egress_interfaces�ingress_sources�egress_sourcesr:r#r#r$�check_ingress_egress"s$

z#FirewallPolicy.check_ingress_egressc

Cs�|dkr&|dkr�|r�ttjd|��n�|dkrtd|krFttjd|��d|kr^ttjd|��|r�ttjd|��n||d	kr�d|kr�ttjd|��d|kr�ttjd|��nB|d
kr�d|kr�ttjd|��n |dkr�d|kr�ttjd
|��dS)N�
PREROUTING�rawzFpolicy "%s" egress-zones may not include a zone with added interfaces.�POSTROUTINGr5z/policy "%s" ingress-zones may not include HOST.z.policy "%s" egress-zones may not include HOST.zGpolicy "%s" ingress-zones may not include a zone with added interfaces.�FORWARD�INPUTz0policy "%s" egress-zones must include only HOST.�OUTPUTz1policy "%s" ingress-zones must include only HOST.)rrr�)
r!r;r|r}r4r7rFrGrHrIr#r#r$�check_ingress_egress_chain<s,z)FirewallPolicy.check_ingress_egress_chaincCs$|j�}|j|||�|jd�dS)NT)r*rorx)r!ryr;r{r#r#r$�!_ingress_egress_zones_transactionYsz0FirewallPolicy._ingress_egress_zones_transactioncCsL|j|}|jd}|jd}t�}t�}t�}	t�}
xB|D]:}|dkrJq<|t|jjj|��O}|	t|jjj|��O}	q<WxB|D]:}|dkr�q�|t|jjj|��O}|
t|jjj|��O}
q�W|j||||||	|
�xr|jj�D]d}|j	s�q�xV|j
|�D]H\}
}|j||
||||||	|
�	|j|||
||||	|
�}|j
||��q�Wq�WdS)Nr4r7r6r5)r6r5)r6r5)r r<r9rr:r�Zlist_sourcesrJrrrlrQZ!build_policy_ingress_egress_rulesr)r!ryr;r{rMr4r7rFrGrHrIr:rr|r}rHr#r#r$ro^s@






z$FirewallPolicy._ingress_egress_zonescCs6|j|}d|jdkrFd|jdkrFdddg}|jjsB|jd�|Sd|jdkrpdg}|jjsl|jd�|Sd|jdkr�dgSd|jdko�d|jdk�r�ddddg}|jj�s�|jd�|Sd|jdk�r.dddg}|jj�s�|jd�x4|jdD]}|jjj|�d�rP�qW|jd �|Sd|jdk�r�d!d"g}|jj�sZ|jd#�x>|jdD]}|jjj|�d�rfP�qfW|jd$�|jd%�|Sd&g}|jj�s�|jd'�x4|jdD]}|jjj|�d�r�P�q�W|jd(�x>|jdD]}|jjj|�d�r�P�q�W|jd)�|jd*�|SdS)+z:Create a list of (table, chain) needed for policy dispatchr6r4r5r7r�rOr*rK�manglerLrPrNrMZ
interfacesN)r�rO)r*rK)rSrK)rLrK)r�rO)rLrK)r�rP)r�rN)r*rK)r*rM)rSrK)rLrK)r�rN)r*rK)rSrK)rLrK)r*rM)r�rN)r*rM)rLrK)r*rK)rSrK)r�rN)rLrK)r*rM)r*rK)rSrK)r r<r�nftables_enabledr0r:r8)r!r;rM�tcr:r#r#r$rl�sj
















z4FirewallPolicy._get_table_chains_for_policy_dispatchcCsr|j|}d|jdkr4dg}|jjs0|jd�|Sd|jdkrLdddgSd|jdkrbddgStd|�SdS)z8Create a list of (table, chain) needed for zone dispatchr5r7r�rOrLrKr6�
FORWARD_INr*rSr4�FORWARD_OUTrMzInvalid policy: %sN)r�rO)rLrK)r�rV)r*rK)rSrK)r�rW)r*rM)r r<rrTr0r)r!r;rMrUr#r#r$rm�s

z2FirewallPolicy._get_table_chains_for_zone_dispatchFcCs�|jjj|�}|jr|j}n||}d|jdkrl|dkrBd|S|dkrRd|S|jsh|dkrhd|S�nJd|jd	kr�|js�|dkr�d
|S�n"d|jdk�r�|dkr�|jr�d|Sd
|Sn0|dkr�|r�d|Sd|Sn|dk�r�d|Sn�d|jd	k�rh|dk�r*|j�r d|Sd
|Sn<|dk�rL|�rBd|Sd|Sn|dk�r�|j�s�d|SnN|j�s�|dk�r�d
|S|dk�r�|�r�d|Sd|Sn|dk�r�d|Std|||f�S)Nr5r7r�ZIN_rLZPRE_rSr*r4ZOUT_r6ZFWDI_ZFWD_ZPOST_ZFWDO_z.Can't convert policy to chain name: %s, %s, %s)rSr*)rSrL)rSrL)rSrL)rr;r.r/r<r)r!r;r|Z
policy_prefixZisSNATrM�suffixr#r#r$�policy_base_chain_name�sb













z%FirewallPolicy.policy_base_chain_name)N)N)N)N)rNNT)N)rNNT)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)NN)NN)NNrNN)NNN)NN)rNN)N)NN)N)N)N)NN)F)��__name__�
__module__�__qualname__r%r'r)r*r-r3r=r.rNrQrLrdrer�r8rrcrPr�r�r�r�rSr�r�r�r�r�r�r�rTr�r�r�r�r�r�r�r�rwr^r�r�r�r�r�r�r�rWr�r�r�r�r�r�r�r�r�rXr�r�r�r�r�r�r�r\r�r�r�r�r�r�r]r�r�r�r�r�r�r_r�r�r�r�rrrVrr�rrr�rrrUr	r�r
rr�r
rrrrrrrnrr�r#r"r�r�r�rrrsrtrurvrqrprrJrQrRrorlrmrYr#r#r#r$rs$
'	?.,#,#:
'('('
+))@@		(Pr)'rhr.Zfirewall.core.loggerrZfirewall.functionsrrrrrrr	r
rrr�r
rrrrrrrrrrZfirewall.core.fw_transactionrZfirewallrZfirewall.errorsrZfirewall.fw_typesrZfirewall.core.baser�objectrr#r#r#r$�<module>s04__pycache__/fw_policies.cpython-36.pyc000064400000004432151731527030013714 0ustar003

��g�
�@sVdgZddlmZddlmZddlmZddlmZddlm	Z	Gdd�de
�ZdS)	�FirewallPolicies�)�config)�log)�LockdownWhitelist)�errors)�
FirewallErrorc@sDeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dS)rcCsd|_ttj�|_dS)NF)�	_lockdownrrZLOCKDOWN_WHITELIST�lockdown_whitelist)�self�r�!/usr/lib/python3.6/fw_policies.py�__init__szFirewallPolicies.__init__cCsd|j|j|jfS)Nz
%s(%r, %r))�	__class__rr	)r
rrr�__repr__#s
zFirewallPolicies.__repr__cCsd|_|jj�dS)NF)rr	�cleanup)r
rrrr'szFirewallPolicies.cleanupcCs�|dkr2tjd|�|jj|�r�tjd�dSn�|dkrdtjd|�|jj|�r�tjd�dSnb|dkr�tjd	|�|jj|�r�tjd
�dSn0|dkr�tjd|�|jj|�r�tjd
�dSdS)N�contextz#Doing access check for context "%s"zcontext matches.TZuidzDoing access check for uid %dzuid matches.�userz Doing access check for user "%s"z
user matches.Zcommandz#Doing access check for command "%s"zcommand matches.F)rZdebug2r	Z
match_contextZdebug3Z	match_uidZ
match_userZ
match_command)r
�key�valuerrr�access_check-s*



zFirewallPolicies.access_checkcCs|jrttjd��d|_dS)Nzenable_lockdown()T)rrrZALREADY_ENABLED)r
rrr�enable_lockdownDsz FirewallPolicies.enable_lockdowncCs|jsttjd��d|_dS)Nzdisable_lockdown()F)rrrZNOT_ENABLED)r
rrr�disable_lockdownIsz!FirewallPolicies.disable_lockdowncCs|jS)N)r)r
rrr�query_lockdownNszFirewallPolicies.query_lockdownN)
�__name__�
__module__�__qualname__r
rrrrrrrrrrrsN)�__all__ZfirewallrZfirewall.core.loggerrZ#firewall.core.io.lockdown_whitelistrrZfirewall.errorsr�objectrrrrr�<module>s__pycache__/icmp.cpython-36.opt-1.pyc000064400000004265151731527030013304 0ustar003

��g�#@s�ddddgZddddddd	d
ddd
dddddddddddddddddddd d!d"d#d$�"Zd%d&d'd(d)dddd*d+d,d,d-d-d.d/d0d0d1d1d2d3�Zd4d5�Zd6d�Zd7d8�Zd9d�Zd:S);�
ICMP_TYPES�ICMPV6_TYPES�check_icmp_type�check_icmpv6_typez0/0z3/0z3/1z3/2z3/3z3/4z3/5z3/6z3/7z3/9z3/10z3/11z3/12z3/13z3/14z3/15z4/0z5/0z5/1z5/2z5/3z8/0z9/0z10/0z11/0z11/1z12/0z12/1z13/0z14/0z17/0z18/0)"z
echo-reply�pongznetwork-unreachablezhost-unreachablezprotocol-unreachablezport-unreachablezfragmentation-neededzsource-route-failedznetwork-unknownzhost-unknownznetwork-prohibitedzhost-prohibitedzTOS-network-unreachablezTOS-host-unreachablezcommunication-prohibitedzhost-precedence-violationzprecedence-cutoffz
source-quenchznetwork-redirectz
host-redirectzTOS-network-redirectzTOS-host-redirectzecho-request�pingzrouter-advertisementzrouter-solicitationzttl-zero-during-transitzttl-zero-during-reassemblyz
ip-header-badzrequired-option-missingztimestamp-requestztimestamp-replyzaddress-mask-requestzaddress-mask-replyz1/0z1/1z1/3z1/4z2/0z4/1z4/2z128/0z129/0z133/0z134/0z135/0z136/0z137/0)zno-routezcommunication-prohibitedzaddress-unreachablezport-unreachablezpacket-too-bigzttl-zero-during-transitzttl-zero-during-reassemblyz
bad-headerzunknown-header-typezunknown-optionzecho-requestrz
echo-replyrzrouter-solicitationzrouter-advertisementzneighbour-solicitationzneigbour-solicitationzneighbour-advertisementzneigbour-advertisementZredirectcCs|tkrdSdS)NTF)r)�_name�r�/usr/lib/python3.6/icmp.py�check_icmp_nameVsr
cCs|tj�krdSdS)NTF)r�values)�_typerrr	r[scCs|tkrdSdS)NTF)r)rrrr	�check_icmpv6_name`sr
cCs|tj�krdSdS)NTF)rr)rrrr	resN)�__all__rrr
rr
rrrrr	�<module>sx__pycache__/ipset.cpython-36.opt-1.pyc000064400000021161151731527030013472 0ustar003

��gq2�@s�dZdddgZddlZddlZddlmZddlmZddl	m
Z
dd	lmZdd
l
mZmZddlmZdZd
ddddddddddgZddddd�Zdddd�ZGd d�de�Zd!d�Zd"d�Zd#d$�Zd%d&�Zd'd(�ZdS))zThe ipset command wrapper�ipset�check_ipset_name�remove_default_create_options�N)�errors)�
FirewallError)�runProg)�log)�tempFile�readfile)�COMMANDS� zhash:ipzhash:ip,portzhash:ip,port,ipzhash:ip,port,netzhash:ip,markzhash:netzhash:net,netz
hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz
inet|inet6�valuez
value in secs)�family�hashsize�maxelem�timeoutZinetZ1024Z65536)rrrc@s�eZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zd'd
d�Z	dd�Z
dd�Zdd�Zd(dd�Z
d)dd�Zdd�Zd*dd�Zd+dd�Zdd �Zd!d"�Zd#d$�Zd%d&�ZdS),rzipset command wrapper classcCstd|_d|_dS)Nr)r�_command�name)�self�r�/usr/lib/python3.6/ipset.py�__init__Ks
zipset.__init__cCs^dd�|D�}tjd|j|jdj|��t|j|�\}}|dkrZtd|jdj|�|f��|S)zCall ipset with argscSsg|]}d|�qS)z%sr)�.0�itemrrr�
<listcomp>Rszipset.__run.<locals>.<listcomp>z	%s: %s %s� rz'%s %s' failed: %s)r�debug2�	__class__r�joinr�
ValueError)r�argsZ_args�status�retrrrZ__runOszipset.__runcCs t|�tkrttjd|��dS)zCheck ipset namezipset name '%s' is not validN)�len�IPSET_MAXNAMELENrrZINVALID_NAME)rrrrr�
check_nameZszipset.check_namecCs�g}d}y|jdg�}Wn0tk
rH}ztjd|�WYdd}~XnX|j�}d}xT|D]L}|r�|j�jdd�}|d|kr�|dtkr�|j|d�|j	d�r\d	}q\W|S)
z?Return types that are supported by the ipset command and kernel�z--helpzipset error: %sNF�rzSupported set types:T)
�_ipset__runrrZdebug1�
splitlines�strip�split�IPSET_TYPES�append�
startswith)rr"�outputZex�linesZin_types�line�splitsrrr�set_supported_types`s  

zipset.set_supported_typescCs(t|�tks|tkr$ttjd|��dS)zCheck ipset typez!ipset type name '%s' is not validN)r#r$r,rrZINVALID_TYPE)r�	type_namerrr�
check_typeuszipset.check_typeNcCsd|j|�|j|�d||g}t|t�rZx0|j�D]$\}}|j|�|dkr2|j|�q2W|j|�S)z+Create an ipset with name, type and options�creater&)r%r5�
isinstance�dict�itemsr-r()r�set_namer4�optionsr �key�valrrr�
set_create{s




zipset.set_createcCs|j|�|jd|g�S)NZdestroy)r%r()rr:rrr�set_destroy�s
zipset.set_destroycCsd||g}|j|�S)N�add)r()rr:�entryr rrr�set_add�s
z
ipset.set_addcCsd||g}|j|�S)N�del)r()rr:rAr rrr�
set_delete�s
zipset.set_deletecCs,d||g}|r"|jddj|��|j|�S)N�testz%sr)r-rr()rr:rAr;r rrrrE�s
z
ipset.testcCs2dg}|r|j|�|r"|j|�|j|�jd�S)N�list�
)r-�extendr(r+)rr:r;r rrr�set_list�s

zipset.set_listcCs<|jdgd�}i}d}}i}�x|D�]}t|�dkr:q&dd�|jdd�D�}t|�dkr`q&q&|d	d
krv|d}q&|d	dkr�|d}q&|d	dkr&|dj�}d	}	x^|	t|�k�r||	}
|
dk�r�t|�|	kr�|	d7}	||	||
<ntjd|�iS|	d7}	q�W|�r$|�r$|t|�f||<d}}|j�q&W|S)z" Get active ipsets (only headers) z-terse)r;N�cSsg|]}|j��qSr)r*)r�xrrrr�sz.ipset.set_get_active_terse.<locals>.<listcomp>�:r'r�NameZTypeZHeaderrrrr�netmaskz&Malformed ipset list -terse output: %s)rrrrrN)rIr#r+r�errorr�clear)rr0r"�_nameZ_type�_optionsr1Zpairr2�i�optrrr�set_get_active_terse�sD

zipset.set_get_active_tersecCsdg}|r|j|�|j|�S)N�save)r-r()rr:r rrrrV�s
z
ipset.savecCs�|j|�|j|�t�}d|kr*d|}d||dg}|rlx0|j�D]$\}}	|j|�|	dkrD|j|	�qDW|jddj|��|jd|�xN|D]F}
d|
kr�d|
}
|r�|jd||
dj|�f�q�|jd	||
f�q�W|j�tj	|j
�}tjd
|j
|jd|j
|jf�dg}t|j||j
d
�\}}
tj�dk�r�yt|j
�Wntk
�r`YnVXd}xNt|j
�D]@}tjd||fddd�|jd��s�tjddd�|d7}�qrWtj|j
�|dk�r�td|jdj|�|
f��|
S)Nrz'%s'r6z-existr&z%s
z	flush %s
z
add %s %s %s
z
add %s %s
z%s: %s restore %sz%s: %dZrestore)�stdinr'rJz%8d: %sr)�nofmt�nlrG)rXz'%s %s' failed: %s)r%r5r	r9r-�writer�close�os�statrrrrr�st_sizerZgetDebugLogLevelr
�	ExceptionZdebug3�endswith�unlinkr)rr:r4�entriesZcreate_optionsZ
entry_optionsZ	temp_filer r<r=rAr]r!r"rSr1rrr�set_restore�sV




zipset.set_restorecCsdg}|r|j|�|j|�S)N�flush)r-r()rr:r rrr�	set_flushs
zipset.set_flushcCs|jd||g�S)N�rename)r()rZold_set_nameZnew_set_namerrrrf
szipset.renamecCs|jd||g�S)N�swap)r()rZ
set_name_1Z
set_name_2rrrrgsz
ipset.swapcCs|jdg�S)N�version)r()rrrrrhsz
ipset.version)N)N)NN)N)NN)�__name__�
__module__�__qualname__�__doc__rr(r%r3r5r>r?rBrDrErIrUrVrcrerfrgrhrrrrrHs&



'

7cCst|�tkrdSdS)z"Return true if ipset name is validFT)r#r$)rrrrrscCs8|j�}x*tD]"}||krt|||kr||=qW|S)z( Return only non default create options )�copy�IPSET_DEFAULT_CREATE_OPTIONS)r;rRrTrrrrs

c
Cshg}xX|jd�D]J}y&|jd�|jttj|dd���Wqtk
rX|j|�YqXqWdj|�S)z! Normalize IP addresses in entry �,�/F)�strict)r+�indexr-�str�	ipaddress�
ip_networkrr)rAZ_entryZ_partrrr�normalize_ipset_entry&s
rvcCsxt|jd��dkrdSytj|dd�}Wntk
r<dSXx4|D],}|jtj|dd��rDttjdj	||���qDWdS)z: Check if entry overlaps any entry in the list of entries rorJNF)rqz,Entry '{}' overlaps with existing entry '{}')
r#r+rtrur�overlapsrr�
INVALID_ENTRY�format)rArbZ
entry_networkZitrrrr�check_entry_overlaps_existing2s
rzcCs~ydd�|D�}Wntk
r&dSXt|�dkr8dS|j�|jd�}x.|D]&}|j|�rrttjdj||���|}qPWdS)z> Check if any entry overlaps any entry in the list of entries cSsg|]}tj|dd��qS)F)rq)rtru)rrKrrrrEsz1check_for_overlapping_entries.<locals>.<listcomp>NrzEntry '{}' overlaps entry '{}')	rr#�sort�poprwrrrxry)rbZprev_networkZcurrent_networkrrr�check_for_overlapping_entriesBs2


r})rl�__all__Zos.pathr\rtZfirewallrZfirewall.errorsrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsr	r
Zfirewall.configrr$r,ZIPSET_CREATE_OPTIONSrn�objectrrrrvrzr}rrrr�<module>sF
P	__pycache__/fw_config.cpython-36.pyc000064400000077161151731527030013363 0ustar003

��g��@s�dgZddlZddlZddlZddlZddlmZddlmZddl	m
Z
mZmZddl
mZmZmZddlmZmZmZddlmZmZmZdd	lmZmZmZdd
lmZmZm Z ddlm!Z!ddl"m#Z#Gd
d�de$�Z%dS)�FirewallConfig�N)�config)�log)�IcmpType�icmptype_reader�icmptype_writer)�Service�service_reader�service_writer)�Zone�zone_reader�zone_writer)�IPSet�ipset_reader�ipset_writer)�Helper�
helper_reader�
helper_writer)�Policy�
policy_reader�
policy_writer)�errors)�
FirewallErrorc@s$eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd#d$�Zd%d&�Zd'd(�Zd)d*�Zd+d,�Zd-d.�Zd/d0�Zd1d2�Zd3d4�Zd5d6�Zd7d8�Zd9d:�Zd;d<�Z d=d>�Z!d?d@�Z"dAdB�Z#dCdD�Z$dEdF�Z%dGdH�Z&dIdJ�Z'dKdL�Z(dMdN�Z)dOdP�Z*dQdR�Z+dSdT�Z,dUdV�Z-dWdX�Z.dYdZ�Z/d[d\�Z0d]d^�Z1d_d`�Z2dadb�Z3dcdd�Z4dedf�Z5dgdh�Z6didj�Z7dkdl�Z8dmdn�Z9dodp�Z:dqdr�Z;dsdt�Z<dudv�Z=dwdx�Z>dydz�Z?d{d|�Z@d}d~�ZAdd��ZBd�d��ZCd�d��ZDd�d��ZEd�d��ZFd�d��ZGd�d��ZHd�d��ZId�d��ZJd�d��ZKd�d��ZLd�d��ZMd�d��ZNd�d��ZOd�d��ZPd�d��ZQd�d��ZRd�d��ZSd�d��ZTd�d��ZUd�d��ZVd�d��ZWd�d��ZXd�d��ZYd�d��ZZd�d��Z[d�d��Z\d�d��Z]d�d��Z^d�d��Z_d�d��Z`d�d��Zad�d��Zbd�d„Zcd�dĄZdd�dƄZed�S)�rcCs||_|j�dS)N)�_fw�_FirewallConfig__init_vars)�self�fw�r�/usr/lib/python3.6/fw_config.py�__init__(szFirewallConfig.__init__cCsHd|j|j|j|j|j|j|j|j|j|j	|j
|j|j|j
|j|jfS)Nz>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r))�	__class__�_ipsets�
_icmptypes�	_services�_zones�_helpersZpolicy_objects�_builtin_ipsets�_builtin_icmptypes�_builtin_services�_builtin_zones�_builtin_helpers�_builtin_policy_objects�_firewalld_conf�	_policies�_direct)rrrr�__repr__,szFirewallConfig.__repr__cCs^i|_i|_i|_i|_i|_i|_i|_i|_i|_i|_	i|_
i|_d|_d|_
d|_dS)N)r!r"r#r$r%�_policy_objectsr&r'r(r)r*r+r,r-r.)rrrrZ__init_vars6szFirewallConfig.__init_varscCs4x,t|jj��D]}|j|j�|j|=qWx,t|jj��D]}|j|j�|j|=q>Wx,t|jj��D]}|j|j�|j|=qlWx,t|jj��D]}|j|j�|j|=q�Wx,t|jj��D]}|j|j�|j|=q�Wx,t|jj��D]}|j|j�|j|=q�Wx.t|j	j��D]}|j	|j�|j	|=�q$Wx.t|j
j��D]}|j
|j�|j
|=�qTWx.t|jj��D]}|j|j�|j|=�q�Wx.t|jj��D]}|j|j�|j|=�q�W|j
�r�|j
j�|`
d|_
|j�r|jj�|`d|_|j�r(|jj�|`d|_|j�dS)N)�listr&�keys�cleanupr!r'r"r(r#r)r$r*r%r,r-r.r)r�xrrrr3GsV


zFirewallConfig.cleanupcCs|jjj�S)N)r�policiesZquery_lockdown)rrrr�lockdown_enabled~szFirewallConfig.lockdown_enabledcCs|jjj||�S)N)rr5�access_check)r�key�valuerrrr7�szFirewallConfig.access_checkcCs
||_dS)N)r,)r�confrrr�set_firewalld_conf�sz!FirewallConfig.set_firewalld_confcCs|jS)N)r,)rrrr�get_firewalld_conf�sz!FirewallConfig.get_firewalld_confcCs(tjjtj�s|jj�n
|jj�dS)N)�os�path�existsrZFIREWALLD_CONFr,�clear�read)rrrr�update_firewalld_conf�sz$FirewallConfig.update_firewalld_confcCs
||_dS)N)r-)rr5rrr�set_policies�szFirewallConfig.set_policiescCs|jS)N)r-)rrrr�get_policies�szFirewallConfig.get_policiescCs,tjjtj�s|jjj�n|jjj�dS)N)	r=r>r?rZLOCKDOWN_WHITELISTr-Zlockdown_whitelistr3rA)rrrr�update_lockdown_whitelist�sz(FirewallConfig.update_lockdown_whitelistcCs
||_dS)N)r.)rZdirectrrr�
set_direct�szFirewallConfig.set_directcCs|jS)N)r.)rrrr�
get_direct�szFirewallConfig.get_directcCs(tjjtj�s|jj�n
|jj�dS)N)r=r>r?rZFIREWALLD_DIRECTr.r3rA)rrrr�
update_direct�szFirewallConfig.update_directcCs$ttt|jj��t|jj����S)N)�sorted�setr1r!r2r&)rrrr�
get_ipsets�szFirewallConfig.get_ipsetscCs$|jr||j|j<n||j|j<dS)N)�builtinr&�namer!)r�objrrr�	add_ipset�szFirewallConfig.add_ipsetcCs8||jkr|j|S||jkr(|j|Sttj|��dS)N)r!r&rr�
INVALID_IPSET)rrMrrr�	get_ipset�s




zFirewallConfig.get_ipsetcCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._ipsets[%s] != objz'%s' not a built-in ipset)rMr!rr�NO_DEFAULTSr&�
_remove_ipset)rrNrrr�load_ipset_defaults�s
z"FirewallConfig.load_ipset_defaultscCs|j�S)N)�
export_config)rrNrrr�get_ipset_config�szFirewallConfig.get_ipset_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rL�copy�
import_configr�ETC_FIREWALLD_IPSETSr>�defaultrOr)rrNr:r4rrr�set_ipset_config�s



zFirewallConfig.set_ipset_configcCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_ipset(): '%s'z%s.xmlFT)r!r&rr�
NAME_CONFLICTr�
check_namerXrM�filenamerrYr>rLrZrrO)rrMr:r4rrr�	new_ipset�s




zFirewallConfig.new_ipsetcCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)N�update�removezLoading ipset file '%s'z"Failed to load ipset file '%s': %s�new)NN)NN)NN)NN)NN)r=r>�basename�dirnamer?rrYr!r2r^rMr&r�debug1r�	Exception�errorrOrZ)rrMr^r>r4rN�msgrrr�update_ipset_from_path�sP






z%FirewallConfig.update_ipset_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr!rrrPr>rrY�INVALID_DIRECTORY�shutil�moverfrrgr=ra)rrNrMrhrrrrS8szFirewallConfig._remove_ipsetcCs$|js|jr ttjd|j��dS)Nz'%s' is built-in ipset)rLrZrrZ
BUILTIN_IPSETrM)rrNrrr�check_builtin_ipsetIsz"FirewallConfig.check_builtin_ipsetcCs|j|�|j|�dS)N)rmrS)rrNrrr�remove_ipsetNs
zFirewallConfig.remove_ipsetcCs$|j|�|j||�}|j|�|S)N)rm�_copy_ipsetrS)rrNrMr_rrr�rename_ipsetRs

zFirewallConfig.rename_ipsetcCs|j||j��S)N)r_rU)rrNrMrrrroXszFirewallConfig._copy_ipsetcCs$ttt|jj��t|jj����S)N)rIrJr1r"r2r')rrrr�
get_icmptypes]szFirewallConfig.get_icmptypescCs$|jr||j|j<n||j|j<dS)N)rLr'rMr")rrNrrr�add_icmptypeaszFirewallConfig.add_icmptypecCs8||jkr|j|S||jkr(|j|Sttj|��dS)N)r"r'rr�INVALID_ICMPTYPE)rrMrrr�get_icmptypegs




zFirewallConfig.get_icmptypecCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._icmptypes[%s] != objz'%s' not a built-in icmptype)rMr"rrrRr'�_remove_icmptype)rrNrrr�load_icmptype_defaultsns
z%FirewallConfig.load_icmptype_defaultscCs|j�S)N)rU)rrNrrr�get_icmptype_configzsz"FirewallConfig.get_icmptype_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rLrWrXr�ETC_FIREWALLD_ICMPTYPESr>rZrrr)rrNr:r4rrr�set_icmptype_config}s



z"FirewallConfig.set_icmptype_configcCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_icmptype(): '%s'z%s.xmlFT)r"r'rrr\rr]rXrMr^rrxr>rLrZrrr)rrMr:r4rrr�new_icmptype�s




zFirewallConfig.new_icmptypecCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)Nr`razLoading icmptype file '%s'z%Failed to load icmptype file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrxr"r2r^rMr'rrerrfrgrrrZ)rrMr^r>r4rNrhrrr�update_icmptype_from_path�sP






z(FirewallConfig.update_icmptype_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr"rrrsr>rrxrjrkrlrfrrgr=ra)rrNrMrhrrrru�szFirewallConfig._remove_icmptypecCs$|js|jr ttjd|j��dS)Nz'%s' is built-in icmp type)rLrZrrZBUILTIN_ICMPTYPErM)rrNrrr�check_builtin_icmptype�sz%FirewallConfig.check_builtin_icmptypecCs|j|�|j|�dS)N)r|ru)rrNrrr�remove_icmptype�s
zFirewallConfig.remove_icmptypecCs$|j|�|j||�}|j|�|S)N)r|�_copy_icmptyperu)rrNrMrzrrr�rename_icmptype�s

zFirewallConfig.rename_icmptypecCs|j||j��S)N)rzrU)rrNrMrrrr~szFirewallConfig._copy_icmptypecCs$ttt|jj��t|jj����S)N)rIrJr1r#r2r()rrrr�get_services
szFirewallConfig.get_servicescCs$|jr||j|j<n||j|j<dS)N)rLr(rMr#)rrNrrr�add_serviceszFirewallConfig.add_servicecCs<||jkr|j|S||jkr(|j|Sttjd|��dS)Nzget_service(): '%s')r#r(rr�INVALID_SERVICE)rrMrrr�get_services




zFirewallConfig.get_servicecCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._services[%s] != objz'%s' not a built-in service)rMr#rrrRr(�_remove_service)rrNrrr�load_service_defaultss
z$FirewallConfig.load_service_defaultscCsr|j�}g}x\td�D]P}|j|d|krN|jtjt||j|d���q|j||j|d�qWt|�S)N�r)�export_config_dict�range�IMPORT_EXPORT_STRUCTURE�appendrW�deepcopy�getattr�tuple)rrN�	conf_dict�	conf_list�irrr�get_service_config's"z!FirewallConfig.get_service_configcCs|j�S)N)r�)rrNrrr�get_service_config_dict3sz&FirewallConfig.get_service_config_dictcCs�i}x&t|�D]\}}|||j|d<qW|jr|tj|�}|j|�tj|_d|_|j|jkrfd|_|j	|�t
|�|S|j|�t
|�|SdS)NrF)�	enumerater�rLrW�import_config_dictr�ETC_FIREWALLD_SERVICESr>rZr�r
)rrNr:r�r�r9r4rrr�set_service_config6s 



z!FirewallConfig.set_service_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rLrWr�rr�r>rZr�r
)rrNr:r4rrr�set_service_config_dictJs



z&FirewallConfig.set_service_config_dictcCs�||jks||jkr$ttjd|��i}x&t|�D]\}}||tj|d<q2Wt�}|j|�|j	|�||_
d||_tj
|_d|_d|_t|�|j|�|S)Nznew_service(): '%s'rz%s.xmlFT)r#r(rrr\r�rr�r]r�rMr^rr�r>rLrZr
r�)rrMr:r�r�r9r4rrr�new_serviceZs"




zFirewallConfig.new_servicecCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_service(): '%s'z%s.xmlFT)r#r(rrr\rr]r�rMr^rr�r>rLrZr
r�)rrMr:r4rrr�new_service_dictqs




zFirewallConfig.new_service_dictcCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)Nr`razLoading service file '%s'z$Failed to load service file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rr�r#r2r^rMr(rrer	rfrgr�rZ)rrMr^r>r4rNrhrrr�update_service_from_path�sP






z'FirewallConfig.update_service_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr#rrr�r>rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr��szFirewallConfig._remove_servicecCs$|js|jr ttjd|j��dS)Nz'%s' is built-in service)rLrZrrZBUILTIN_SERVICErM)rrNrrr�check_builtin_service�sz$FirewallConfig.check_builtin_servicecCs|j|�|j|�dS)N)r�r�)rrNrrr�remove_service�s
zFirewallConfig.remove_servicecCs$|j|�|j||�}|j|�|S)N)r��
_copy_servicer�)rrNrMr�rrr�rename_service�s

zFirewallConfig.rename_servicecCs|j||j��S)N)r�r�)rrNrMrrrr��szFirewallConfig._copy_servicecCs$ttt|jj��t|jj����S)N)rIrJr1r$r2r))rrrr�	get_zones�szFirewallConfig.get_zonescCs$|jr||j|j<n||j|j<dS)N)rLr)rMr$)rrNrrr�add_zone�szFirewallConfig.add_zonecCs(||jkr|j|=||jkr$|j|=dS)N)r)r$)rrMrrr�forget_zone�s

zFirewallConfig.forget_zonecCs<||jkr|j|S||jkr(|j|Sttjd|��dS)Nzget_zone(): %s)r$r)rr�INVALID_ZONE)rrMrrr�get_zone�s




zFirewallConfig.get_zonecCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._zones[%s] != objz'%s' not a built-in zone)rMr$rrrRr)�_remove_zone)rrNrrr�load_zone_defaultss
z!FirewallConfig.load_zone_defaultscCsr|j�}g}x\td�D]P}|j|d|krN|jtjt||j|d���q|j||j|d�qWt|�S)N�r)r�r�r�r�rWr�r�r�)rrNr�r�r�rrr�get_zone_configs"zFirewallConfig.get_zone_configcCs|j�S)N)r�)rrNrrr�get_zone_config_dictsz#FirewallConfig.get_zone_config_dictcCs�i}x&t|�D]\}}|||j|d<qW|jr�tj|�}||_|j|�tj|_d|_|j|jkrld|_	|j
|�t|�|S||_|j|�t|�|SdS)NrF)r�r�rLrW�	fw_configr�r�ETC_FIREWALLD_ZONESr>rZr�r
)rrNr:r�r�r9r4rrr�set_zone_config s$



zFirewallConfig.set_zone_configcCsv|jrVtj|�}||_|j|�tj|_d|_|j|jkr@d|_|j|�t	|�|S||_|j|�t	|�|SdS)NF)
rLrWr�r�rr�r>rZr�r
)rrNr:r4rrr�set_zone_config_dict6s



z#FirewallConfig.set_zone_config_dictcCs�||jks||jkr$ttjd|��i}x&t|�D]\}}||tj|d<q2Wt�}||_|j	|�|j
|�||_d||_t
j|_d|_d|_t|�|j|�|S)Nznew_zone(): '%s'rz%s.xmlFT)r$r)rrr\r�rr�r�r]r�rMr^rr�r>rLrZr
r�)rrMr:r�r�r9r4rrr�new_zoneHs"



zFirewallConfig.new_zonecCs~||jks||jkr$ttjd|��t�}||_|j|�|j|�||_	d||_
tj|_
d|_d|_t|�|j|�|S)Nznew_zone(): '%s'z%s.xmlFT)r$r)rrr\rr�r]r�rMr^rr�r>rLrZr
r�)rrMr:r4rrr�
new_zone_dict_s



zFirewallConfig.new_zone_dictcCstjj|�}tjj|�}tjj|�s�|jtj�r�x�|jj	�D]D}|j|}|j
|kr<|j|=|j|jkrxd|j|jfSd|fSq<WnHxF|jj	�D]8}|j|}|j
|kr�|j|=|j|jkr�d|fSd	Sq�Wd
St
jd|�yt||�}Wn0tk
�r}zt
jd||�dSd}~XnX||_|jtj��rlt|�ttj�k�rldtjj|�tjj|�dd�f|_|j|jk�r�|j|jk�r�|j|�d|fS|jtj��r�|j|jk�r�|j|jj|_||j|j<d|fS|j|jk�r|j|j=||j|j<|j|jk�rd|fSd
SdS)Nr`razLoading zone file '%s'z!Failed to load zone file '%s': %sz%s/%sr�rb)NN)NN)NN���)NN)NN)r=r>rcrdr?�
startswithrr�r$r2r^rMr)rrerrfrgr��lenr�rZ)rrMr^r>r4rNrhrrr�update_zone_from_pathrsZ





z$FirewallConfig.update_zone_from_pathcCs�|j|jkrttj|j��|jjtj�s@ttj	d|jtjf��d|j|jf}yt
j|d|�Wn:tk
r�}zt
jd||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr$rrr�r>r�rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr��szFirewallConfig._remove_zonecCs$|js|jr ttjd|j��dS)Nz'%s' is built-in zone)rLrZrrZBUILTIN_ZONErM)rrNrrr�check_builtin_zone�sz!FirewallConfig.check_builtin_zonecCs|j|�|j|�dS)N)r�r�)rrNrrr�remove_zone�s
zFirewallConfig.remove_zonec	CsN|j|�|j�}|j|�y|j||�}Wn|j|j|��YnX|S)N)r�r�r�r�rM)rrNrMZobj_confr�rrr�rename_zone�s

zFirewallConfig.rename_zonecCs$ttt|jj��t|jj����S)N)rIrJr1r0r2r+)rrrr�get_policy_objects�sz!FirewallConfig.get_policy_objectscCs$|jr||j|j<n||j|j<dS)N)rLr+rMr0)rrNrrr�add_policy_object�sz FirewallConfig.add_policy_objectcCs<||jkr|j|S||jkr(|j|Sttjd|��dS)Nzget_policy_object(): %s)r0r+rr�INVALID_POLICY)rrMrrr�get_policy_object�s




z FirewallConfig.get_policy_objectcCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._policy_objects[%s] != objz'%s' not a built-in policy)rMr0rrrRr+�_remove_policy_object)rrNrrr�load_policy_object_defaults�s
z*FirewallConfig.load_policy_object_defaultscCs|j�S)N)r�)rrNrrr�get_policy_object_config_dictsz,FirewallConfig.get_policy_object_config_dictcCsv|jrVtj|�}||_|j|�tj|_d|_|j|jkr@d|_|j|�t	|�|S||_|j|�t	|�|SdS)NF)
rLrWr�r�r�ETC_FIREWALLD_POLICIESr>rZr�r)rrNr:r4rrr�set_policy_object_config_dicts



z,FirewallConfig.set_policy_object_config_dictcCs~||jks||jkr$ttjd|��t�}||_|j|�|j|�||_	d||_
tj|_
d|_d|_t|�|j|�|S)Nznew_policy_object(): '%s'z%s.xmlFT)r0r+rrr\rr�r]r�rMr^rr�r>rLrZrr�)rrMr:r4rrr�new_policy_object_dicts



z%FirewallConfig.new_policy_object_dictcCstjj|�}tjj|�}tjj|�s�|jtj�r�x�|jj	�D]D}|j|}|j
|kr<|j|=|j|jkrxd|j|jfSd|fSq<WnHxF|jj	�D]8}|j|}|j
|kr�|j|=|j|jkr�d|fSd	Sq�Wd
St
jd|�yt||�}Wn0tk
�r}zt
jd||�dSd}~XnX||_|jtj��rlt|�ttj�k�rldtjj|�tjj|�dd�f|_|j|jk�r�|j|jk�r�|j|�d|fS|jtj��r�|j|jk�r�|j|jj|_||j|j<d|fS|j|jk�r|j|j=||j|j<|j|jk�rd|fSd
SdS)Nr`razLoading policy file '%s'z#Failed to load policy file '%s': %sz%s/%srr�rb)NN)NN)NNr�)NN)NN)r=r>rcrdr?r�rr�r0r2r^rMr+rrerrfrgr�r�r�rZ)rrMr^r>r4rNrhrrr�update_policy_object_from_path,sZ





z-FirewallConfig.update_policy_object_from_pathcCs�|j|jkrttj|j��|jjtj�s@ttj	d|jtjf��d|j|jf}yt
j|d|�Wn:tk
r�}zt
jd||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr0rrr�r>r�rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr�ysz$FirewallConfig._remove_policy_objectcCs$|js|jr ttjd|j��dS)Nz'%s' is built-in policy)rLrZrrZBUILTIN_POLICYrM)rrNrrr�check_builtin_policy_object�sz*FirewallConfig.check_builtin_policy_objectcCs|j|�|j|�dS)N)r�r�)rrNrrr�remove_policy_object�s
z#FirewallConfig.remove_policy_objectcCs$|j|�|j||�}|j|�|S)N)r��_copy_policy_objectr�)rrNrMZnew_policy_objectrrr�rename_policy_object�s

z#FirewallConfig.rename_policy_objectcCs|j||j��S)N)r�r�)rrNrMrrrr��sz"FirewallConfig._copy_policy_objectcCs$ttt|jj��t|jj����S)N)rIrJr1r%r2r*)rrrr�get_helpers�szFirewallConfig.get_helperscCs$|jr||j|j<n||j|j<dS)N)rLr*rMr%)rrNrrr�
add_helper�szFirewallConfig.add_helpercCs8||jkr|j|S||jkr(|j|Sttj|��dS)N)r%r*rr�INVALID_HELPER)rrMrrr�
get_helper�s




zFirewallConfig.get_helpercCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._helpers[%s] != objz'%s' not a built-in helper)rMr%rrrRr*�_remove_helper)rrNrrr�load_helper_defaults�s
z#FirewallConfig.load_helper_defaultscCs|j�S)N)rU)rrNrrr�get_helper_config�sz FirewallConfig.get_helper_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rLrWrXr�ETC_FIREWALLD_HELPERSr>rZr�r)rrNr:r4rrr�set_helper_config�s



z FirewallConfig.set_helper_configcCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_helper(): '%s'z%s.xmlFT)r%r*rrr\rr]rXrMr^rr�r>rLrZrr�)rrMr:r4rrr�
new_helper�s




zFirewallConfig.new_helpercCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)Nr`razLoading helper file '%s'z#Failed to load helper file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rr�r%r2r^rMr*rrerrfrgr�rZ)rrMr^r>r4rNrhrrr�update_helper_from_path�sP






z&FirewallConfig.update_helper_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr%rrr�r>rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr�&szFirewallConfig._remove_helpercCs$|js|jr ttjd|j��dS)Nz'%s' is built-in helper)rLrZrrZBUILTIN_HELPERrM)rrNrrr�check_builtin_helper7sz#FirewallConfig.check_builtin_helpercCs|j|�|j|�dS)N)r�r�)rrNrrr�
remove_helper<s
zFirewallConfig.remove_helpercCs$|j|�|j||�}|j|�|S)N)r��_copy_helperr�)rrNrMr�rrr�
rename_helper@s

zFirewallConfig.rename_helpercCs|j||j��S)N)r�rU)rrNrMrrrr�FszFirewallConfig._copy_helperN)f�__name__�
__module__�__qualname__rr/rr3r6r7r;r<rBrCrDrErFrGrHrKrOrQrTrVr[r_rirSrmrnrprorqrrrtrvrwryrzr{rur|r}rr~r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�rrrrr's�
7EEEMME)&�__all__rWr=Zos.pathrkZfirewallrZfirewall.core.loggerrZfirewall.core.io.icmptyperrrZfirewall.core.io.servicerr	r
Zfirewall.core.io.zonerrr
Zfirewall.core.io.ipsetrrrZfirewall.core.io.helperrrrZfirewall.core.io.policyrrrrZfirewall.errorsr�objectrrrrr�<module>s__pycache__/fw_icmptype.cpython-36.opt-1.pyc000064400000004205151731527040014675 0ustar003

��g�	�@s>dgZddlmZddlmZddlmZGdd�de�ZdS)�FirewallIcmpType�)�log)�errors)�
FirewallErrorc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCs||_i|_dS)N)�_fw�
_icmptypes)�self�fw�r
�!/usr/lib/python3.6/fw_icmptype.py�__init__szFirewallIcmpType.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rr
r
r�__repr__!szFirewallIcmpType.__repr__cCs|jj�dS)N)r�clear)rr
r
r�cleanup$szFirewallIcmpType.cleanupcCst|jj��S)N)�sortedr�keys)rr
r
r�
get_icmptypes)szFirewallIcmpType.get_icmptypescCs||jkrttj|��dS)N)rrrZINVALID_ICMPTYPE)r�icmptyper
r
r�check_icmptype,s
zFirewallIcmpType.check_icmptypecCs|j|�|j|S)N)rr)rrr
r
r�get_icmptype0s
zFirewallIcmpType.get_icmptypecCs�|j}t|�dkrddg}x�|D]z}|dkrL|jjrB|jjrBq |jj}n,|dkrt|jjrj|jjrjq |jj}ng}|jj	�|kr t
jd|j|f�q W||j|j<dS)NrZipv4Zipv6z5ICMP type '%s' is not supported by the kernel for %s.)
Zdestination�lenrZip4tables_enabledZnftables_enabledZipv4_supported_icmp_typesZip6tables_enabledZipv6_supported_icmp_types�name�lowerrZinfo1r)r�objZ	orig_ipvsZipvZsupported_icmpsr
r
r�add_icmptype4s 


zFirewallIcmpType.add_icmptypecCs|j|�|j|=dS)N)rr)rrr
r
r�remove_icmptypeGs
z FirewallIcmpType.remove_icmptypeN)�__name__�
__module__�__qualname__rrrrrrrrr
r
r
rrsN)	�__all__Zfirewall.core.loggerrZfirewallrZfirewall.errorsr�objectrr
r
r
r�<module>s__pycache__/fw_ifcfg.cpython-36.pyc000064400000002613151731527040013163 0ustar003

��g
�@sTdZddgZddlZddlZddlmZddlmZddlm	Z	dd�Z
d	d�ZdS)
z.Functions to search for and change ifcfg files�search_ifcfg_of_interface�ifcfg_set_zone_of_interface�N)�config)�log)�ifcfgcCs�tjjtj�sdSxtttjtj��D]`}|jd�s4q$xd
D]}|j|�r:q:q:Wd	|krXq$t	d
tj|f�}|j
�|jd�|kr$|Sq$Wdtj|f}tjj|�r�t	|�}|j
�|SdS)z6search ifcfg file for the interface in config.IFCFGDIRNzifcfg-�.bak�.orig�.rpmnew�.rpmorig�.rpmsave�-range�.z%s/%sZDEVICEz%s/ifcfg-%s)rrr	r
rr)�os�path�existsrZIFCFGDIR�sorted�listdir�
startswith�endswithr�read�get)�	interface�filenameZignored�
ifcfg_file�r�/usr/lib/python3.6/fw_ifcfg.pyr!s*

cCsn|dkrd}t|�}|dk	rj|jd�|krj|jd�dko>|dkrjtjd||jf�|jd|�|j�dS)zYSet zone (ZONE=<zone>) in the ifcfg file that uses the interface
    (DEVICE=<interface>)N�ZZONEzSetting ZONE=%s in '%s')rrrZdebug1r�set�write)Zzonerrrrrr?s)�__doc__�__all__rZos.pathZfirewallrZfirewall.core.loggerrZfirewall.core.io.ifcfgrrrrrrr�<module>s__pycache__/fw_ifcfg.cpython-36.opt-1.pyc000064400000002613151731527040014122 0ustar003

��g
�@sTdZddgZddlZddlZddlmZddlmZddlm	Z	dd�Z
d	d�ZdS)
z.Functions to search for and change ifcfg files�search_ifcfg_of_interface�ifcfg_set_zone_of_interface�N)�config)�log)�ifcfgcCs�tjjtj�sdSxtttjtj��D]`}|jd�s4q$xd
D]}|j|�r:q:q:Wd	|krXq$t	d
tj|f�}|j
�|jd�|kr$|Sq$Wdtj|f}tjj|�r�t	|�}|j
�|SdS)z6search ifcfg file for the interface in config.IFCFGDIRNzifcfg-�.bak�.orig�.rpmnew�.rpmorig�.rpmsave�-range�.z%s/%sZDEVICEz%s/ifcfg-%s)rrr	r
rr)�os�path�existsrZIFCFGDIR�sorted�listdir�
startswith�endswithr�read�get)�	interface�filenameZignored�
ifcfg_file�r�/usr/lib/python3.6/fw_ifcfg.pyr!s*

cCsn|dkrd}t|�}|dk	rj|jd�|krj|jd�dko>|dkrjtjd||jf�|jd|�|j�dS)zYSet zone (ZONE=<zone>) in the ifcfg file that uses the interface
    (DEVICE=<interface>)N�ZZONEzSetting ZONE=%s in '%s')rrrZdebug1r�set�write)Zzonerrrrrr?s)�__doc__�__all__rZos.pathZfirewallrZfirewall.core.loggerrZfirewall.core.io.ifcfgrrrrrrr�<module>s__pycache__/fw_direct.cpython-36.opt-1.pyc000064400000031230151731527040014313 0ustar003

��g�W�@sndgZddlmZddlmZddlmZddlmZddlm	Z	ddl
mZddlm
Z
Gd	d�de�Zd
S)�FirewallDirect�)�LastUpdatedOrderedDict)�	ipXtables)�ebtables)�FirewallTransaction)�log)�errors)�
FirewallErrorc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dNdd�Zdd�Zdd�Z
dOdd�Zdd�Zdd�Zdd�Zd d!�ZdPd"d#�ZdQd$d%�Zd&d'�Zd(d)�Zd*d+�ZdRd,d-�ZdSd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�ZdTd<d=�Z dUd>d?�Z!d@dA�Z"dBdC�Z#dDdE�Z$dFdG�Z%dHdI�Z&dJdK�Z'dLdM�Z(dS)VrcCs||_|j�dS)N)�_fw�_FirewallDirect__init_vars)�self�fw�r�/usr/lib/python3.6/fw_direct.py�__init__'szFirewallDirect.__init__cCsd|j|j|j|jfS)Nz%s(%r, %r, %r))�	__class__�_chains�_rules�_rule_priority_positions)rrrr�__repr__+szFirewallDirect.__repr__cCs"i|_i|_i|_i|_d|_dS)N)rrr�
_passthroughs�_obj)rrrrZ__init_vars/s
zFirewallDirect.__init_varscCs|j�dS)N)r)rrrr�cleanup6szFirewallDirect.cleanupcCs
t|j�S)N)rr
)rrrr�new_transaction;szFirewallDirect.new_transactioncCs
||_dS)N)r)r�objrrr�set_permanent_config@sz#FirewallDirect.set_permanent_configcCs*t|j�t|j�t|j�dkr&dSdS)NrTF)�lenrrr)rrrr�has_runtime_configurationCs"z(FirewallDirect.has_runtime_configurationcCsB|j�rdSt|jj��t|jj��t|jj��dkr>dSdS)NTrF)rrr�get_all_chains�
get_all_rules�get_all_passthroughs)rrrr�has_configurationHsz FirewallDirect.has_configurationNcCsP|dkr|j�}n|}|j|jj�|jj�|jj�f|�|dkrL|jd�dS)NT)r�
set_configrrrr �execute)r�use_transaction�transactionrrr�apply_directQs

zFirewallDirect.apply_directcCsi}i}i}xL|jD]B}|\}}x4|j|D]&}|jj|||�s,|j|g�j|�q,WqWxf|jD]\}|\}}}xL|j|D]>\}	}
|jj||||	|
�s|||kr�t�||<|	|||	|
f<q|WqbWxP|jD]F}x@|j|D]2}
|jj	||
�s�||k�r�g||<||j|
�q�Wq�W|||fS)N)
rr�query_chain�
setdefault�appendr�
query_rulerr�query_passthrough)rZchains�rulesZpassthroughs�table_id�ipv�table�chain�chain_id�priority�argsrrr�get_runtime_configbs,


z!FirewallDirect.get_runtime_configcCs|j|j|jfS)N)rrr)rrrr�
get_config�szFirewallDirect.get_configcCs�|dkr|j�}n|}|\}}}x||D]t}|\}}	xf||D]Z}
|j||	|
�s<y|j||	|
|d�Wq<tk
r�}ztjt|��WYdd}~Xq<Xq<Wq&Wx�|D]�}|\}}	}
xt||D]h\}
}|j||	|
|
|�s�y|j||	|
|
||d�Wq�tk
�r"}ztjt|��WYdd}~Xq�Xq�Wq�Wxx|D]p}xh||D]\}|j	||��s@y|j
|||d�Wn2tk
�r�}ztjt|��WYdd}~XnX�q@W�q2W|dk�r�|jd�dS)N)r$T)rr'�	add_chainr	rZwarning�strr*�add_ruler+�add_passthroughr#)rZconfr$r%rrrr-r.r/r0�errorr1r2r3rrrr"�s@



(

(
,
zFirewallDirect.set_configcCs*dddg}||kr&ttjd||f��dS)N�ipv4�ipv6Zebz'%s' not in '%s')r	rZINVALID_IPV)rr.Zipvsrrr�
_check_ipv�s
zFirewallDirect._check_ipvcCsF|j|�|dkrtjj�ntjj�}||krBttjd||f��dS)Nr;r<z'%s' not in '%s')r;r<)r=r�BUILT_IN_CHAINS�keysrr	rZ
INVALID_TABLE)rr.r/Ztablesrrr�_check_ipv_table�s

zFirewallDirect._check_ipv_tablecCs�|dkr4tj|}|jjr i}qH|jj|�j|}ntj|}tj|}||kr`tt	j
d|��||krxtt	j
d|��|dkr�|jjj|�dk	r�tt	j
d|��dS)Nr;r<zchain '%s' is built-in chainzchain '%s' is reservedzChain '%s' is reserved)r;r<)r;r<)rr>r
�nftables_enabled�get_direct_backend_by_ipv�
our_chainsrZ
OUR_CHAINSr	rZ
BUILTIN_CHAIN�zoneZzone_from_chainZ
INVALID_CHAIN)rr.r/r0Zbuilt_in_chainsrCrrr�_check_builtin_chain�s"




z#FirewallDirect._check_builtin_chaincCsH|r|jj|g�j|�n*|j|j|�t|j|�dkrD|j|=dS)Nr)rr(r)�remover)rr-r0�addrrr�_register_chain�s
zFirewallDirect._register_chaincCsV|dkr|j�}n|}|jj�r.|j|jj�|jd||||�|dkrR|jd�dS)NT)rr
�may_skip_flush_direct_backends�add_pre�flush_direct_backends�_chainr#)rr.r/r0r$r%rrrr6�s

zFirewallDirect.add_chaincCs>|dkr|j�}n|}|jd||||�|dkr:|jd�dS)NFT)rrLr#)rr.r/r0r$r%rrr�remove_chain�s
zFirewallDirect.remove_chaincCs:|j||�|j|||�||f}||jko8||j|kS)N)r@rEr)rr.r/r0r-rrrr'�s

zFirewallDirect.query_chaincCs,|j||�||f}||jkr(|j|SgS)N)r@r)rr.r/r-rrr�
get_chains�s


zFirewallDirect.get_chainscCsDg}x:|jD]0}|\}}x"|j|D]}|j|||f�q$WqW|S)N)rr))r�r�keyr.r/r0rrrrszFirewallDirect.get_all_chainscCsZ|dkr|j�}n|}|jj�r.|j|jj�|jd||||||�|dkrV|jd�dS)NT)rr
rIrJrK�_ruler#)rr.r/r0r2r3r$r%rrrr8	s

zFirewallDirect.add_rulecCsB|dkr|j�}n|}|jd||||||�|dkr>|jd�dS)NFT)rrQr#)rr.r/r0r2r3r$r%rrr�remove_rules
zFirewallDirect.remove_rulecCs2|j||�|||f}||jko0||f|j|kS)N)r@r)rr.r/r0r2r3r1rrrr*#s

zFirewallDirect.query_rulecCs6|j||�|||f}||jkr2t|j|j��SgS)N)r@r�listr?)rr.r/r0r1rrr�	get_rules)s


zFirewallDirect.get_rulesc	CsRg}xH|jD]>}|\}}}x.|j|D] \}}|j||||t|�f�q&WqW|S)N)rr)rS)rrOrPr.r/r0r2r3rrrr0s
 zFirewallDirect.get_all_rulescCs�|rr||jkrt�|j|<||j||<||jkr<i|j|<||j|krb|j|||7<q�||j||<n<|j||=t|j|�dkr�|j|=|j|||8<dS)Nr)rrrr)r�rule_idr1r2�enable�countrrr�_register_rule8s


zFirewallDirect._register_rulecCsVy|jj|jj|�j|�Stk
rP}ztj|�ttj	|��WYdd}~XnXdS)N)
r
�rulerB�name�	ExceptionrZdebug2r	rZCOMMAND_FAILED)rr.r3�msgrrr�passthroughLs

zFirewallDirect.passthroughcCsX|r*||jkrg|j|<|j|j|�n*|j|j|�t|j|�dkrT|j|=dS)Nr)rr)rFr)rr.r3rVrrr�_register_passthroughTs

z$FirewallDirect._register_passthroughcCsX|dkr|j�}n|}|jj�r.|j|jj�|jd|t|�|�|dkrT|jd�dS)NT)rr
rIrJrK�_passthroughrSr#)rr.r3r$r%rrrr9^s

zFirewallDirect.add_passthroughcCs@|dkr|j�}n|}|jd|t|�|�|dkr<|jd�dS)NFT)rr_rSr#)rr.r3r$r%rrr�remove_passthroughls
z!FirewallDirect.remove_passthroughcCs||jkot|�|j|kS)N)r�tuple)rr.r3rrrr+ws
z FirewallDirect.query_passthroughcCs>g}x4|jD]*}x$|j|D]}|j|t|�f�qWqW|S)N)rr)rS)rrOr.r3rrrr {s
z#FirewallDirect.get_all_passthroughscCs4g}||jkr0x |j|D]}|jt|��qW|S)N)rr)rS)rr.rOr3rrr�get_passthroughs�s

zFirewallDirect.get_passthroughscCs�g}x�|D]�}d}x�|D]�}y|j|�}Wntk
r>YqXt|�|krd||dkrd}||djd�}x.|D]&}	|dd�}
|	|
|d<|j|
�qxWqW|s
|j|�q
W|S)z5Split values combined with commas for options in optsF�,�TN)�index�
ValueErrorr�splitr))rr,ZoptsZ	out_rulesrYZ	processed�opt�i�items�itemrQrrr�split_value�s$


zFirewallDirect.split_valuec
Cs*|j||�|jjr2|dkr2|jjj||||�|}|jj|�}	|jjrd|	j|||�rdd|}n:|jjr�|dd�dkr�|	j|||dd��r�|dd�}|||f}
||f}|r�|
|jkr�||j|
kr�tt	j
d||||f��nB|
|jk�s||j|
k�rtt	jd||||f��|j|
|}d}d	}
|
|jk�r�t
|j|
j��}d	}x@|t|�k�r�|||k�r�||j|
||7}|d7}�qTWt|�g}|j|d
dg�}|j|dd
g�}x<|D]4}|j|	|	j||||t|���|d7}|
d7}
�q�W|j||
|||
�|j|j||
|||
�dS)Nr;r<z	%s_direct�Z_directz"rule '%s' already is in '%s:%s:%s'zrule '%s' is not in '%s:%s:%s'rdrz-sz--sourcez-dz
--destination)r;r<i����i����i����)r@r
rArD�create_zone_base_by_chainrBZis_chain_builtinrr	r�ALREADY_ENABLED�NOT_ENABLEDr�sortedr?rrSrlr8Z
build_rulerarX�add_fail)rrVr.r/r0r2r3r%rL�backendr1rUrerWZ	positions�jZ	args_list�_argsrrrrQ�sZ




(

zFirewallDirect._rulecCs�|j||�|j|||�||f}|rV||jkr�||j|kr�ttjd|||f��n.||jksn||j|kr�ttjd|||f��|jj|�}|j	||j
|||��|j|||�|j|j|||�dS)Nz chain '%s' already is in '%s:%s'zchain '%s' is not in '%s:%s')
r@rErr	rrorpr
rBZ	add_rulesZbuild_chain_rulesrHrr)rrGr.r/r0r%r-rsrrrrLs$

zFirewallDirect._chainc
Cs�|j|�t|�}|rD||jkrp||j|krpttjd||f��n,||jks\||j|krpttjd||f��|jj|�}|r�|j	|�|dkr�|j
|�\}}|r�|r�|jjj|||�|}	n
|j
|�}	|j||	�|j|||�|j|j|||�dS)Nzpassthrough '%s', '%s'r;r<)r;r<)r=rarr	rrorpr
rBZcheck_passthroughZpassthrough_parse_table_chainrDrnZreverse_passthroughr8r^rr)
rrVr.r3r%Z
tuple_argsrsr/r0rurrrr_'s0




zFirewallDirect._passthrough)N)N)N)N)N)N)N)N))�__name__�
__module__�__qualname__rrrrrrrr!r&r4r5r"r=r@rErHr6rMr'rNrr8rRr*rTrrXr]r^r9r`r+r rbrlrQrLr_rrrrr&sL	

'	

	




jN)�__all__Zfirewall.fw_typesrZ
firewall.corerrZfirewall.core.fw_transactionrZfirewall.core.loggerrZfirewallrZfirewall.errorsr	�objectrrrrr�<module>s__pycache__/fw_nm.cpython-36.pyc000064400000011713151731527040012520 0ustar003

��g�@s dZddddddddgZd	d
lZd	dlmZyejdd
�Wnek
rTdZYn8Xyd	dlmZdZWn e	eej
fk
r�dZYnXd
ad	dlm
Z
d	dlmZd	dlmZd	d
lZdd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd �Zd!d�Zd"d�Zd#d�Zd
S)$z(Functions for NetworkManager interaction�check_nm_imported�nm_is_imported�nm_get_zone_of_connection�nm_set_zone_of_connection�nm_get_connections�nm_get_connection_of_interface�nm_get_bus_name�nm_get_dbus_interface�N)�GLib�NMz1.0F)rT)�errors)�
FirewallError)�logcCststtjd��dS)zNCheck function to raise a MISSING_IMPORT error if the import of NM failed
    zgi.repository.NM = 1.0N)�_nm_importedr
rZMISSING_IMPORT�rr�/usr/lib/python3.6/fw_nm.pyr0scCstS)znReturns true if NM has been properly imported
    @return True if import was successful, False otherwirse
    )rrrrrr6scCststjjd�atS)z�Returns the NM client object or None if the import of NM failed
    @return NM.Client instance if import was successful, None otherwise
    N)�
_nm_clientrZClient�newrrrr�
nm_get_client<srcCs�t�t�j|�}|dkrdS|j�}|dkr2dSy |j�tjjtjjB@rPdSWn t	k
rr|j
�rndSYnX|j�}|dkr�d}|S)z�Get zone of connection from NM
    @param connection name
    @return zone string setting of connection, empty string if not set, None if connection is unknown
    N�)rr�get_connection_by_uuid�get_setting_connection�	get_flagsr�SettingsConnectionFlags�NM_GENERATED�NM_VOLATILE�AttributeError�get_unsavedZget_zone)�
connection�con�setting_con�zonerrrrEs$
cCsVt�t�j|�}|dkrdS|j�}|dkr2dS|dkr>d}|jd|�|jdd�S)zSet the zone for a connection
    @param zone name
    @param connection name
    @return True if zone was set, else False
    NFrr!T)rrrrZset_propertyZcommit_changes)r!rrr rrrrcsc	Cs~|j�|j�t�t�j�}xX|D]P}|j�r4q&|j�}|j�}|j�}|||<x |D]}|j�}|rZ|||<qZWq&WdS)znGet active connections from NM
    @param connections return dict
    @param connections_name return dict
    N)	�clearrr�get_active_connections�get_vpnZget_id�get_uuid�get_devices�get_ip_iface)	ZconnectionsZconnections_nameZactive_connections�
active_con�nameZuuidZdevices�dev�ip_ifacerrrrxs


cCs�t�g}x�t�j�D]|}|j�r$qy&|j�}|j�tjjtjj	B@rHwWnt
k
rh|j�rdwYnXx&|j�D]}|j
�}|rt|j|�qtWqW|S)zGGet active interfaces from NM
    @returns list of interface names
    )rrr#r$�get_connectionrrrrrrrr&r'�append)Zactive_interfacesr(rr*r+rrr�nm_get_interfaces�s$r.cCs6g}x,t�D]"}t|�}|t|�kr|j|�qW|S)N)r.rrr-)r!Z
interfaces�	interfaceZconnrrr�nm_get_interfaces_in_zone�sr0cCs<t�x0t�j�D]"}|j�}|dkr(q||kr|SqWdS)zzGet device from NM which has the given IP interface
    @param interface name
    @returns NM.Device instance or None
    N)rrr&r')r/�devicer+rrr�nm_get_device_by_ip_iface�sr2cCsxt�t|�}|dkrdS|j�}|dkr.dSy |j�}|j�tjj@rLdSWn tk
rn|j	�rjdSYnX|j
�S)z�Get connection from NM that is using the interface
    @param interface name
    @returns connection that is using interface or None
    N)rr2Zget_active_connectionr,rrrrrrr%)r/r1r(rrrrr�s
cCsRtsdSy&tj�}|jtjtj�}|j}~~|Stk
rLt	j
d�YnXdS)Nz(Failed to get bus name of NetworkManager)r�dbusZ	SystemBusZ
get_objectr�DBUS_INTERFACEZ	DBUS_PATHZbus_name�	ExceptionrZdebug2)Zbus�objr)rrrr�scCstsdStjS)Nr)rrr4rrrrr�s)�__doc__�__all__ZgiZ
gi.repositoryr
Zrequire_version�
ValueErrorrr�ImportError�ErrorrZfirewallrZfirewall.errorsr
Zfirewall.core.loggerrr3rrrrrrr.r0r2rrrrrrr�<module>s@

	 	
__pycache__/ipXtables.cpython-36.pyc000064400000104137151731527040013350 0ustar003

��g���@s(ddlZddlZddlmZddlmZddlmZm	Z	m
Z
mZmZm
Z
mZmZddlmZddlmZmZmZmZmZddlmZmZmZmZmZmZmZddl Z dZ!d	d
dgdd
gdd
d	d
dgdd
d
gd	d
dgd�Z"ddd�Z#ddd�Z$dd�Z%dd�Z&dd�Z'Gdd�de(�Z)Gdd�de)�Z*dS)�N)�runProg)�log)�tempFile�readfile�	splitArgs�	check_mac�portStr�check_single_address�
check_address�normalizeIP6)�config)�
FirewallError�INVALID_PASSTHROUGH�INVALID_RULE�
UNKNOWN_ERROR�INVALID_ADDR)�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�Rich_Masquerade�Rich_ForwardPort�Rich_IcmpBlock��INPUT�OUTPUT�FORWARD�
PREROUTING�POSTROUTING)�security�raw�mangle�nat�filterzicmp-host-prohibitedzicmp6-adm-prohibited)�ipv4�ipv6�icmpz	ipv6-icmpcCs�ddddddd�}|dd�}x~|D]v}y|j|�}Wntk
rLw$YnX|d
kr�yt||d	�Wntk
r~YnX|j|d	�||||<q$W|S)z Inverse valid rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz--new-chainN�-I�--insert�)r'r()�index�	Exception�int�pop)�args�replace_args�ret_args�arg�idx�r3�/usr/lib/python3.6/ipXtables.py�common_reverse_rule9s(
r5cCs�ddddddd�}|dd�}x�|D]x}y|j|�}Wntk
rLw$YnX|dkr�yt||d	�Wntk
r~YnX|j|d	�||||<|SWttd
��dS)z Reverse valid passthough rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz--new-chainN�-I�--insertr)zno '-A', '-I' or '-N' arg)r6r7)r*�
ValueErrorr,r-r
r)r.r/r0�xr2r3r3r4�common_reverse_passthrough^s,
r:cCs�t|�}tddddddddd	d
ddd
dddddddg�}t||@�dkrbttdt||@�d��tddddddg�}t||@�dkr�ttd��dS)zZ Check if passthough rule is valid (only add, insert and new chain
    rules are allowed) z-Cz--checkz-Dz--deletez-Rz	--replacez-Lz--listz-Sz--list-rulesz-Fz--flushz-Zz--zeroz-Xz--delete-chainz-Pz--policyz-Ez--rename-chainrzarg '%s' is not allowedz-Az--appendz-Iz--insertz-Nz--new-chainzno '-A', '-I' or '-N' argN)�set�lenr
r�list)r.Znot_allowedZneededr3r3r4�common_check_passthrough�s*

r>c@s�eZdZdZdZdZdd�Zdd�Zdd�Zd	d
�Z	dd�Z
d
d�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd �Zdhd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zdid,d-�Zd.d/�Zdjd1d2�Zd3d4�Zd5d6�Zdkd8d9�Zdld:d;�Z d<d=�Z!d>d?�Z"d@dA�Z#dBdC�Z$dDdE�Z%dFdG�Z&dHdI�Z'dJdK�Z(dLdM�Z)dNdO�Z*dPdQ�Z+dmdRdS�Z,dndTdU�Z-dodVdW�Z.dXdY�Z/dpdZd[�Z0dqd\d]�Z1drd^d_�Z2dsd`da�Z3dbdc�Z4ddde�Z5dfdg�Z6d!S)t�	ip4tablesr$TcCsd||_tj|j|_tjd|j|_|j�|_|j�|_	|j
�g|_i|_i|_
g|_i|_dS)Nz
%s-restore)�_fwrZCOMMANDS�ipv�_command�_restore_command�_detect_wait_option�wait_option�_detect_restore_wait_option�restore_wait_option�fill_exists�available_tables�rich_rule_priority_counts�policy_priority_counts�zone_source_index_cache�
our_chains)�self�fwr3r3r4�__init__�s

zip4tables.__init__cCs$tjj|j�|_tjj|j�|_dS)N)�os�path�existsrBZcommand_existsrCZrestore_command_exists)rNr3r3r4rH�szip4tables.fill_existscCs�|jr(|j|kr(|jgdd�|D�}ndd�|D�}tjd|j|jdj|��t|j|�\}}|dkr�td|jdj|�|f��|S)NcSsg|]}d|�qS)z%sr3)�.0�itemr3r3r4�
<listcomp>�sz#ip4tables.__run.<locals>.<listcomp>cSsg|]}d|�qS)z%sr3)rTrUr3r3r4rV�sz	%s: %s %s� rz'%s %s' failed: %s)rEr�debug2�	__class__rB�joinrr8)rNr.Z_args�status�retr3r3r4Z__run�szip4tables.__runc
Cs<y|j|�}Wntk
r"dSX||||d�<dSdS)NF�T)r*r8)rN�rule�patternZreplacement�ir3r3r4�
_rule_replace�szip4tables._rule_replacecCs|tko|t|kS)N)�BUILT_IN_CHAINS)rNrA�table�chainr3r3r4�is_chain_builtin�szip4tables.is_chain_builtincCs2d|g}|r|jd�n
|jd�|j|�|gS)Nz-tz-Nz-X)�append)rN�addrcrdr^r3r3r4�build_chain_rules�s

zip4tables.build_chain_rulescCs8d|g}|r |d|t|�g7}n|d|g7}||7}|S)Nz-tz-Iz-D)�str)rNrgrcrdr*r.r^r3r3r4�
build_rule�szip4tables.build_rulecCst|�S)N)r5)rNr.r3r3r4�reverse_rule�szip4tables.reverse_rulecCst|�dS)N)r>)rNr.r3r3r4�check_passthrough�szip4tables.check_passthroughcCst|�S)N)r:)rNr.r3r3r4�reverse_passthrough�szip4tables.reverse_passthroughcCs�d}y|jd�}Wntk
r&YnXt|�|dkrD||d}d}xLd
D]D}y|j|�}Wntk
rtYqNXt|�|dkrN||d}qNW||fS)Nr#z-tr]�-A�--append�-I�--insert�-N�--new-chain)rnrorprqrrrs)r*r8r<)rNr.rcr`rd�optr3r3r4�passthrough_parse_table_chain�s$z'ip4tables.passthrough_parse_table_chaincCs4yH|jd�}|j|�|j|�}d|dkr:||df}n||df}WnFtk
r�y|jd�}|j|�d}Wntk
r�dSXYnXd}|ddkr�d}|r�|r�||kr�|j|�nn|�r0|�r�||kr�|j|�|jdd
�d�|j|�}n|jj�rd}nt|�}d|d<|j	dd|d�dS)Nz%%ZONE_SOURCE%%z-m���z%%ZONE_INTERFACE%%Tr�-D�--deleteFcSs|dS)Nrr3)r9r3r3r4�<lambda>&sz4ip4tables._run_replace_zone_source.<locals>.<lambda>)�keyz-Ir)z%dr])ryrz)
r*r-r8�removerf�sortr@�_allow_zone_driftingr<�insert)rNr^rLr`�zoneZzone_source�rule_addr*r3r3r4�_run_replace_zone_source	s>







z"ip4tables._run_replace_zone_sourcecCsy|j|�}Wntk
r$Y�n�Xd}d}d}|j|�|j|�}t|�tkr\ttd��d}	xLdD]D}
y|j|
�}Wntk
r�YqfXt|�|dkrf||d}	qfWxhdD]`}
y|j|
�}Wntk
r�Yq�Xt|�|dk�r�||d}|
dk�rd}|
dkr�d}q�W|	|f}|�sp||k�sP|||k�sP|||dk�rZttd��|||d8<n�||k�r�i||<|||k�r�d|||<d}
xHt	||j
��D]4}||k�r�|�r�P|
|||7}
||k�r�P�q�W|||d7<d
||<|j|dd|
�dS)a
        Change something like
          -t filter -I public_IN %%RICH_RULE_PRIORITY%% 123
        or
          -t filter -A public_IN %%RICH_RULE_PRIORITY%% 321
        into
          -t filter -I public_IN 4
        or
          -t filter -I public_IN
        TFr]z%priority must be followed by a numberr#�-t�--table�-A�--append�-I�--insert�-D�--deleterz*nonexistent or underflow of priority countr)z%dN���)r�r�)r�r�r�r�r�r�)r�r�)r�r�)r*r8r-�typer,r
rr<r�sorted�keysr�)rNr^Zpriority_counts�tokenr`r�r�Zinsert_add_index�priorityrcrt�jrdr*�pr3r3r4�_set_rule_replace_priority2sj








z$ip4tables._set_rule_replace_prioritycCsPt�}i}tj|j�}tj|j�}tj|j�}�x�|D�]�}|dd�}	|j|	dddt|jg�|j|	dt	|jg�y|	j
d�}
Wntk
r�Yn8X|dkr�q6|d$kr�d
dd|g|	|
|
d
�<n
|	j|
�|j
|	|d�|j
|	|d�|j|	|�d}xZd%D]R}y|	j
|�}
Wntk
�r,Yn(Xt|	�|
d
k�r|	j|
�|	j|
�}�qWxhtt|	��D]X}
xPtjD]F}
|
|	|
k�rt|	|
jd��o�|	|
jd��rtd|	|
|	|
<�qtW�qhW|j|g�j|	�q6WxR|D]J}||}|jd|�x"|D]}	|jdj|	�d��qW|jd��q�W|j�tj|j�}tjd|j|j d|j|j!f�g}|j"�rz|j|j"�|jd�t#|j ||jd�\}}tj$�dk�r
t%|j�}|dk	�r
d
}
xH|D]@}tj&d|
|fd
dd �|jd��s�tj&d!d
d"�|
d
7}
�q�Wtj'|j�|dk�r:td#|j dj|�|f��||_||_||_dS)&Nz
%%REJECT%%�REJECTz
--reject-withz%%ICMP%%z%%LOGTYPE%%�off�unicast�	broadcast�	multicastz-m�pkttypez
--pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r#�-t�--table�"z"%s"z*%s
rW�
zCOMMIT
z	%s: %s %sz%s: %dz-n)�stdinr)z%8d: %sr)�nofmt�nlr)r�z'%s %s' failed: %s)r�r�r�)r�r�)(r�copy�deepcopyrJrKrLra�DEFAULT_REJECT_TYPErA�ICMPr*r8r-r�r�r<�range�stringZ
whitespace�
startswith�endswith�
setdefaultrf�writerZ�closerQ�stat�namerrXrYrC�st_sizerGrZgetDebugLogLevelrZdebug3�unlink)rN�rules�
log_denied�	temp_fileZtable_rulesrJrKrLZ_ruler^r`rcrt�cr�r.r[r\�lines�liner3r3r4�	set_rules�s�









zip4tables.set_rulesc
Cs�|j|dddt|jg�|j|dt|jg�y|jd�}Wntk
rRYn:X|dkr`dS|dkr�ddd
|g|||d�<n
|j|�tj|j	�}tj|j
�}tj|j�}|j||d�|j||d�|j
||�|j|�}||_	||_
||_|S)Nz
%%REJECT%%r�z
--reject-withz%%ICMP%%z%%LOGTYPE%%r�rr�r�r�z-mr�z
--pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%)r�r�r�)rar�rAr�r*r8r-r�r�rJrKrLr�r��_ip4tables__run)rNr^r�r`rJrKrL�outputr3r3r4�set_rule�s.

zip4tables.set_ruleNcCs�g}|r|gntj�}xx|D]p}||jkr6|j|�qy,|jd|ddg�|jj|�|j|�Wqtk
r�tjd|j|f�YqXqW|S)Nz-tz-Lz-nzA%s table '%s' does not exist (or not enough permission to check).)	rbr�rIrfr�r8r�debug1rA)rNrcr\Ztablesr3r3r4�get_available_tabless

zip4tables.get_available_tablescCs`d}t|jdddg�}|ddkr\d}t|jdddg�}|ddkrHd}tjd|j|j|�|S)Nrz-wz-Lz-nrz-w10z%s: %s will be using %s option.)rrBrrXrY)rNrEr\r3r3r4rDszip4tables._detect_wait_optioncCs�t�}|jd�|j�d}xJdD]B}t|j|g|jd�}|ddkr"d|dkr"d	|dkr"|}Pq"Wtjd
|j|j|�t	j
|j�|S)Nz#foor�-w�--wait=2)r�rzinvalid optionr]zunrecognized optionz%s: %s will be using %s option.)r�r�)rr�r�rrCr�rrXrYrQr�)rNr�rEZtest_optionr\r3r3r4rF"s

z%ip4tables._detect_restore_wait_optioncCsVi|_i|_g|_g}x:tj�D].}|j|�s0q xdD]}|jd||g�q6Wq W|S)N�-F�-X�-Zz-t)r�r�r�)rJrKrLrbr�r�rf)rNr�rc�flagr3r3r4�build_flush_rules5s

zip4tables.build_flush_rulescCsfg}|dkrdn|}xLtj�D]@}|j|�s.q|dkr8qx$t|D]}|jd|d||g�qBWqW|S)NZPANIC�DROPr"z-tz-P)rbr�r�rf)rN�policyr��_policyrcrdr3r3r4�build_set_policy_rulesDs
z ip4tables.build_set_policy_rulescCs g}d}y"|jd|jdkrdnddg�}WnJtk
rt}z.|jdkrVtjd|�ntjd|�WYd	d	}~XnX|j�}d
}x�|D]�}|r�|j�j�}|j�}xD|D]<}	|	j	d�r�|	j
d�r�|	d
d�}
n|	}
|
|kr�|j|
�q�W|jdko�|j	d��s|jdkr�|j	d�r�d}q�W|S)zQReturn ICMP types that are supported by the iptables/ip6tables command and kernelrz-pr$r&z	ipv6-icmpz--helpziptables error: %szip6tables error: %sNF�(�)r]zValid ICMP Types:r%zValid ICMPv6 Types:Tr�)r�rAr8rr��
splitlines�strip�lower�splitr�r�rf)rNrAr\r�Zexr�Zin_typesr�Zsplitsr�r9r3r3r4�supported_icmp_typesPs4
 

zip4tables.supported_icmp_typescCsgS)Nr3)rNr3r3r4�build_default_tablesqszip4tables.build_default_tablesr�c	Csi}|jd�rpg|d<t�|jd<xLtdD]@}|djd|�|djd||f�|jdjd|�q,W|jd��r\g|d<t�|jd<x�tdD]�}|djd|�|djd||f�|jdjd|�|dkr�xt|jjr�ddd	d
gndd	d
gD]R}|djd||f�|djd|||f�|jdjtd
||fg���qWq�W|jd��rNg|d<t�|jd<x�tdD]�}|djd|�|djd||f�|jdjd|�|dk�r�xv|jj�r�ddd	d
gndd	d
gD]R}|djd||f�|djd|||f�|jdjtd
||fg���q�W�q�W|jd��r@g|d<t�|jd<x�tdD]�}|djd|�|djd||f�|jdjd|�|d9k�rxxv|jj�r�ddd	d
gndd	d
gD]R}|djd||f�|djd|||f�|jdjtd
||fg���q�W�qxWg|d<t�|jd<|djd�|djd�|djd�|djd�|jdjtd��xf|jj�r�ddd	d
gndd	d
gD]B}|djd|�|djd|�|jdjtd|���q�W|dk�r |djd�|djd�|dk�rF|djd�|djd�|djd�|djd �|djd!�|djd"�|jdjtd#��xJd:D]B}|djd$|�|djd%|�|jdjtd&|���q�Wxzd;D]r}xj|jj�r
dd	gnd	gD]N}|djd)||f�|djd*||f�|jdjtd+||f���qW�q�WxJd<D]B}|djd$|�|djd%|�|jdjtd&|���qnW|dk�r�|djd,�|djd-�|dk�r�|djd.�|djd/�|dd0d1d2d3g7<|jdjtd4��xJd=D]B}|djd5|�|djd6|�|jdjtd7|���q2WxJd>D]B}|djd5|�|djd6|�|jdjtd7|���q~Wg}xJ|D]B}||j�k�r�q�x(||D]}|jd8|gt	|���q�W�q�W|S)?Nrz-N %s_directz-A %s -j %s_directz	%s_directr r�POLICIES_preZZONES_SOURCEZZONES�
POLICIES_postz-N %s_%sz-A %s -j %s_%sz%s_%sr!r"rr#zB-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A INPUT -i lo -j ACCEPTz-N INPUT_directz-A INPUT -j INPUT_directZINPUT_directz-N INPUT_%sz-A INPUT -j INPUT_%szINPUT_%sr�z^-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z/-A INPUT -m conntrack --ctstate INVALID -j DROPz9-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A INPUT -j %%REJECT%%zD-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A FORWARD -i lo -j ACCEPTz-N FORWARD_directz-A FORWARD -j FORWARD_directZFORWARD_directz
-N FORWARD_%sz-A FORWARD -j FORWARD_%sz
FORWARD_%s�IN�OUTz-N FORWARD_%s_%sz-A FORWARD -j FORWARD_%s_%sz
FORWARD_%s_%sz`-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z1-A FORWARD -m conntrack --ctstate INVALID -j DROPz;-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A FORWARD -j %%REJECT%%z-N OUTPUT_directz>-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPTz-A OUTPUT -o lo -j ACCEPTz-A OUTPUT -j OUTPUT_directZ
OUTPUT_directz-N OUTPUT_%sz-A OUTPUT -j OUTPUT_%sz	OUTPUT_%sz-t)rr)r�)r�r�)r�)r�)r�)
r�r;rMrbrfrgr@r�updater)	rNr�Z
default_rulesrdZdispatch_suffix�	directionZfinal_default_rulesrcr^r3r3r4�build_default_rulesus�
$(
&*
&*&



(






"zip4tables.build_default_rulescCsf|dkrdddhS|dkr,d|j�kr,dhS|dkrHd|j�krHddhS|d	krbd	|j�krbdhSiS)
Nr#r�
FORWARD_IN�FORWARD_OUTr!rr"rr )r�)rNrcr3r3r4�get_zone_table_chains�s
zip4tables.get_zone_table_chainsc	s�|jjj|���jdkrdnd��dkr4�dkr4dnd}	|jjj|�t|	��g}
g}x|D]}|
jd|g�qZWx|D]}|jd	|g�qvWxB|D]:}
|jjj|
�}|dkr�|j	|�r�q�|
j|j
d|
��q�Wx\|D]T}
|jjj|
�}|dk�r|j	|��rq�t|
��r�dk�rq�|j|j
d|
��q�W������fdd�}g}|
�r�x�|
D]F}|�r�x8|D]}|j|||���qdWn|�r�n|j||d���qTWnH|�r�n@|�r�x8|D]}|j|d|���q�Wn|�r�n|j|dd��|S)Nr�pre�postr"rTFz-iz-or$r%z-sr�rz-dcsVddd��}d�|d��fd�jg}|r6|j|�|rD|j|�|jd�g�|S)Nz-Az-D)TFz-tz%s_POLICIES_%sz%%POLICY_PRIORITY%%z-j)r��extend)�ingress_fragment�egress_fragment�add_delr^)r�rd�chain_suffix�enable�p_objrcr3r4�_generate_policy_dispatch_rules


zSip4tables.build_policy_ingress_egress_rules.<locals>._generate_policy_dispatch_rule)r$r%)r$r%)rr�r)r@r�Z
get_policyr��policy_base_chain_name�POLICY_CHAIN_PREFIXrfr�Zcheck_source�is_ipv_supported�_rule_addr_fragmentr)rNr�r�rcrdZingress_interfacesZegress_interfacesZingress_sourcesZegress_sources�isSNATZingress_fragmentsZegress_fragments�	interface�addrrAr�r�r�r�r3)r�rdr�r�r�rcr4�!build_policy_ingress_egress_rules�sR






z+ip4tables.build_policy_ingress_egress_rulesFc
Cs�|dkr|dkrdnd}|jjj||t|d�}	ddddddd�|}
d	}|rb|rbd
d|dg}n,|rtd
d|g}ndd|g}|s�|dg7}|d||
|||	g7}|gS)Nr"rTF)r�z-iz-o)rrrr�r�rz-gz-Iz%s_ZONESz%%ZONE_INTERFACE%%z-Az-Dz-t)r@r�r�r�)
rNr�r�r�r�rcrdrfr�r�rt�actionr^r3r3r4�!build_zone_source_interface_rulesKs&

z+ip4tables.build_zone_source_interface_rulescCs�|jd�rP|dd�}|dkr$d}nd}dj|g|jjj|��}ddd	||gSt|�rz|dkrjttd
��ddd|j�gSt	d
|�r�t
|�}n,td
|�r�|jd�}t
|d�d|d}||gSdS)Nzipset:�z-d�dst�src�,z-mr;z--match-setzCan't match a destination MAC.�macz--mac-sourcer%�/rr])
r�rZr@�ipsetZ
get_dimensionrr
r�upperr	rr
r�)rNrt�address�invertr��flags�
addr_splitr3r3r4r�es"





zip4tables._rule_addr_fragmentc
Cs�ddd�|}|dkr"|dkr"dnd}|jjj||t|d�}	d	d
d	d	d
d
d�|}
|jjrdd|}nd
|}t|�r�|dkr�gS||d|d|g}|j|j|
|��|jd|	g�|gS)Nz-Iz-D)TFr"rTF)r�z-sz-d)rrrr�r�rz%s_ZONES_SOURCEz%s_ZONESr�rz%%ZONE_SOURCE%%z-tz-g)rr�r)r@r�r�r�rrr�r�)
rNr�r�r�r�rcrdr�r�r�rtZzone_dispatch_chainr^r3r3r4�build_zone_source_address_rules{s&
z)ip4tables.build_zone_source_address_rulescCs>ddd�|}ddd�|}|dkr0|dkr0dnd	}|jjj||t|d
�}|j|jt|d|d|d
|d|d|g��g}	|	j||d|g�|	j|d
|d|g�|	j|d|d|g�|	j|d|d|g�|	j|d|d|g�|	j|d|d|g�|	j||d|dd
|g�|	j||d|dd|g�|	j||d|dd|g�|	j||d|dd|g�|	j||d|dd|g�|jjj|j	}
|jj
�dk�r|dk�r|
dk�r�|	j||d|ddddd|g	�|
dk�r|	j||d|ddddd|g	�|dk�r,|
dk�r,|	j||d|d|
g�|�s:|	j�|	S)Nz-Nz-X)TFz-Az-Dr"rTF)r�z%s_logz%s_denyz%s_prez%s_postz%s_allowz-tz-jr�r#r��
%%REJECT%%z%%LOGTYPE%%�LOGz--log-prefixz
"%s_REJECT: "r�z"%s_DROP: "�ACCEPT)r�r�)r�r�r�r�)r@r�r�r�rMr�r;rfZ	_policies�target�get_log_denied�reverse)rNr�r�rcrdZ
add_del_chainZadd_del_ruler�r�r�r�r3r3r4�build_policy_chain_rules�sN




z"ip4tables.build_policy_chain_rulescCs2|sgSddd|jg}|jdk	r.|d|jg7}|S)Nz-m�limitz--limitz
--limit-burst)�valueZburst)rNr�sr3r3r4�_rule_limit�s
zip4tables._rule_limitcCs�t|j�tttgkrn<|jrHt|j�tttt	gkrRt
tdt|j���n
t
td��|jdkr�t|j�ttgks�t|j�tt	gkr�dSt|j�tgks�t|j�ttgkr�dSn|jdkr�dSdSdS)NzUnknown action %szNo rule action specified.r�allowZdenyr�r�)
r��elementrrrr�rrrrr
rr�)rN�	rich_ruler3r3r4�_rich_rule_chain_suffix�s 


z!ip4tables._rich_rule_chain_suffixcCs>|jr|jrttd��|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrr�r�)r�auditr
rr�)rNrr3r3r4� _rich_rule_chain_suffix_from_log�s


z*ip4tables._rich_rule_chain_suffix_from_logcCs|jdkrgSd|jgS)Nrz%%RICH_RULE_PRIORITY%%)r�)rNrr3r3r4�_rich_rule_priority_fragment�s
z&ip4tables._rich_rule_priority_fragmentc
Cs�|js
gS|jjj||t�}ddd�|}|j|�}d||d||fg}	|	|j|�7}	|	|ddg7}	|jjr�|	dd	|jjg7}	|jjr�|	d
d|jjg7}	|	|j	|jj
�7}	|	S)Nz-Az-D)TFz-tz%s_%sz-jr�z--log-prefixz'%s'z--log-levelz%s)rr@r�r�r�rr�prefix�levelrr)
rNr�rr�rc�
rule_fragmentr�r�r�r^r3r3r4�_rich_rule_log�s
zip4tables._rich_rule_logcCs�|js
gSddd�|}|jjj||t�}|j|�}d||d||fg}	|	|j|�7}	|	|7}	t|j�t	krrd}
n,t|j�t
kr�d}
nt|j�tkr�d}
nd	}
|	d
dd|
g7}	|	|j|jj
�7}	|	S)
Nz-Az-D)TFz-tz%s_%sZacceptZrejectZdrop�unknownz-jZAUDITz--type)r
r@r�r�r�rrr�r�rrrrr)rNr�rr�rcrr�r�r�r^Z_typer3r3r4�_rich_rule_audits$
zip4tables._rich_rule_auditcCs2|js
gSddd�|}|jjj||t�}|j|�}d||f}	t|j�tkrXddg}
n�t|j�tkr�ddg}
|jjr�|
d|jjg7}
nnt|j�t	kr�dd	g}
nVt|j�t
kr�d
}|jjj||t�}d||f}	ddd|jjg}
ntt
d
t|j���d|||	g}||j|�7}|||
7}||j|jj�7}|S)Nz-Az-D)TFz%s_%sz-jr�r�z
--reject-withr�r!�MARKz--set-xmarkzUnknown action %sz-t)r�r@r�r�r�r	r�rrrrr;r
rrrr)rNr�rr�rcrr�r�r�rdZrule_actionr^r3r3r4�_rich_rule_action$s4


zip4tables._rich_rule_actioncCs�|sgSg}|jr�|jr"|jd�td|j�rB|dt|j�g7}q�td|j�r||jjd�}|dt|d�d|dg7}q�|d|jg7}nD|jr�|ddg7}|jr�|jd�|jj	j
|jd	�}|d
|j|g7}|S)N�!r%z-dr�rr]z-mr;r�z--match-set)r�r�rfr	rr
r�r�r@r��_ipset_match_flags)rNZ	rich_destrr�r�r3r3r4�_rich_rule_destination_fragmentFs&
"
z)ip4tables._rich_rule_destination_fragmentcCs|sgSg}|jr�|jr"|jd�td|j�rB|dt|j�g7}nHtd|j�r||jjd�}|dt|d�d|dg7}n|d|jg7}n�t|d�r�|jr�|ddg7}|jr�|jd�|d	|jg7}nPt|d
�o�|j	�r|ddg7}|jr�|jd�|j
jj|j	d�}|d
|j	|g7}|S)Nrr%z-sr�rr]r�z-mz--mac-sourcer�r;r�z--match-set)
r�r�rfr	rr
r��hasattrr�r�r@r�r)rNZrich_sourcerr�r�r3r3r4�_rich_rule_source_fragment^s0
"

z$ip4tables._rich_rule_source_fragmentcCsddd�|}d}|jjj||t�}	d|g}
|rD|
ddt|�g7}
|rT|
d|g7}
|rx|
|j|j�7}
|
|j|j�7}
|s�t	|j
�tkr�|
d	d
ddg7}
g}|r�|j|j
|||||
��|j|j|||||
��|j|j|||||
��n"|j|d
|	d|g|
ddg�|S)Nz-Az-D)TFr#z-pz--dportz%sz-dz-m�	conntrackz	--ctstatez
NEW,UNTRACKEDz%s_allowz-tz-jr�)r@r�r�r�rr�destinationr�sourcer�r�rrfrrr)rNr�r��proto�portrrr�rcr�rr�r3r3r4�build_policy_ports_rules{s*z"ip4tables.build_policy_ports_rulescCs�ddd�|}d}|jjj||t�}d|g}	|r<|	d|g7}	|r`|	|j|j�7}	|	|j|j�7}	|stt|j	�t
kr�|	ddd	d
g7}	g}
|r�|
j|j|||||	��|
j|j
|||||	��|
j|j|||||	��n"|
j|d|d|g|	d
dg�|
S)Nz-Az-D)TFr#z-pz-dz-mrz	--ctstatez
NEW,UNTRACKEDz%s_allowz-tz-jr�)r@r�r�r�rrrrr�r�rrfrrr)rNr�r��protocolrrr�rcr�rr�r3r3r4�build_policy_protocol_rules�s&z%ip4tables.build_policy_protocol_rulescCsddd�|}d}|jjj||t�}	d|g}
|rD|
ddt|�g7}
|rT|
d|g7}
|rx|
|j|j�7}
|
|j|j�7}
|s�t	|j
�tkr�|
d	d
ddg7}
g}|r�|j|j
|||||
��|j|j|||||
��|j|j|||||
��n"|j|d
|	d|g|
ddg�|S)Nz-Az-D)TFr#z-pz--sportz%sz-dz-mrz	--ctstatez
NEW,UNTRACKEDz%s_allowz-tz-jr�)r@r�r�r�rrrrrr�r�rrfrrr)rNr�r�rrrrr�rcr�rr�r3r3r4�build_policy_source_ports_rules�s*z)ip4tables.build_policy_source_ports_rulescCsvd}|jjj||t�}	ddd�|}
|
d|	ddd|g}|rP|dd	t|�g7}|r`|d
|g7}|ddd
|g7}|gS)Nr z-Az-D)TFz%s_allowz-tz-pz--dportz%sz-dz-jZCTz--helper)r@r�r�r�r)rNr�r�rrrZhelper_nameZmodule_short_namercr�r�r^r3r3r4�build_policy_helper_ports_rules�sz)ip4tables.build_policy_helper_ports_rulesc
	Cs�ddd�|}|jjj||t�}g}	|rH|	jdd|d|d|dd	g�n6t|�rTgS|	jdd|d|g|jd
|�dd	g�|	S)Nz-Az-D)TFz-tr#z%s_allowz-oz-jr�z-d)r@r�r�r�rfrr�)
rNr�r�r�rcr�rr�r�r�r3r3r4�build_zone_forward_rules�sz"ip4tables.build_zone_forward_rulesc
Cs,d}|jjj||tdd�}ddd�|}g}|rj|j|�}||j|�7}||j|j�7}||j|j	�7}nd}g}	|	j
dd|d	||fg|d
ddd
dg�g}|r�|j|�}||j|�7}||j|j�7}||j|j	�7}nd}d}|jjj||t�}|	j
dd|d	||fg|ddddd
dg�|	S)Nr"T)r�z-Az-D)TFrz-tz%s_%srz-o�loz-jZ
MASQUERADEr#z-mrz	--ctstatez
NEW,UNTRACKEDr�)r@r�r�r�r	rrrrrrf)
rNr�r�rrcr�r�rr�r�r3r3r4�build_policy_masquerade_rules�s6

z'ip4tables.build_policy_masquerade_rulesc
Cs
d}|jjj||t�}	ddd�|}
d}|rPtd|�rH|dt|�7}n||7}|rn|dkrn|dt|d	�7}g}|r�|j|�}
|j|�}||j	|j
�7}||j|j�7}nd
}
g}|r�|j
|j|||d|��|j
dd|
d|	|
fg|d
|dt|�ddd|g�|S)Nr"z-Az-D)TFrr%z[%s]z:%s�-rz-tz%s_%sz-pz--dportz-jZDNATz--to-destination)r@r�r�r�r	rrr	rrrrrrfr)rNr�r�rr ZtoportZtoaddrrrcr�r�Ztorr�r�r3r3r4�build_policy_forward_port_ruless2


z)ip4tables.build_policy_forward_port_rulescCs�d}|jjj||t�}ddd�|}|jdkrFddg}ddd	|jg}	ndd
g}ddd|jg}	g}
|jjj|�r|d
|}d}nd|}d}g}
|r�|
|j|j�7}
|
|j	|j
�7}
|
||	7}
|�rP|
j|j|||||
��|
j|j
|||||
��|j�r|
j|j|||||
��n:|j|�}|
jd||d||fg|j|�|
ddg�n`|jj�dk�r�|dk�r�|
j||d|g|
ddddd|g�|
j||d|g|
d|g�|
S)Nr#z-Az-D)TFr$z-pr&z-mz--icmp-typez	ipv6-icmpZicmp6z
--icmpv6-typez%s_allowr�z%s_denyz
%%REJECT%%z-tz%s_%sz-jr�z%%LOGTYPE%%r�z--log-prefixz"%s_ICMP_BLOCK: ")r@r�r�r�rAr��query_icmp_block_inversionrrrrrfrrr�rr	rr�)rNr�r�Zictrrcr�r�r�matchr�Zfinal_chainZfinal_targetrr�r3r3r4�build_policy_icmp_block_rules3sJ

 z'ip4tables.build_policy_icmp_block_rulesc	Cs�d}|jjj||t�}g}d}|jjj|�r�d}|jj�dkr�|rRd|t|�g}nd|g}|d|dd	d
ddd
d|g	}|j|�|d7}nd}|r�d|t|�g}nd|g}|d|dd	d|g}|j|�|S)Nr#r�z
%%REJECT%%r�z-Iz-Dz-tz-pz%%ICMP%%z%%LOGTYPE%%z-jr�z--log-prefixz"%s_ICMP_BLOCK: "r]r�)r@r�r�r�r)r�rirf)	rNr�r�rcr�r�Zrule_idxZ
ibi_targetr^r3r3r4�'build_policy_icmp_block_inversion_rulesds.



z1ip4tables.build_policy_icmp_block_inversion_rulescCsxd}g}||j|j�7}||j|j�7}g}|j|j|||||��|j|j|||||��|j|j|||||��|S)Nr#)rrrrrfrrr)rNr�r�rrcrr�r3r3r4�*build_policy_rich_source_destination_rules�sz4ip4tables.build_policy_rich_source_destination_rulescCs
||jkS)N)rA)rNrAr3r3r4r��szip4tables.is_ipv_supported)N)N)r�)F)F)NN)NN)NN)NN)N)N)N)7�__name__�
__module__�__qualname__rAr�Zpolicies_supportedrPrHr�rarerhrjrkrlrmrur�r�r�r�r�rDrFr�r�r�r�r�r�r�r�r�r�rrr	rrrrrrrrr!r"r#r$r&r(r+r,r-r�r3r3r3r4r?�sh

			)Pa#

!
zN

0"




&
!
1"r?c@s&eZdZdZdZddd�Zdd�ZdS)	�	ip6tablesr%Fc
Cs�g}|jddddddddd	d
g
�|dkrL|jddddddddd	dd
dg�|jdddddddd	dg	�|jdddddddd	dg	�|S)Nz-Irz-tr!z-mZrpfilterz--invertz--validmarkz-jr�r�r�z--log-prefixzrpfilter_DROP: z-pz	ipv6-icmpz$--icmpv6-type=neighbour-solicitationr�z"--icmpv6-type=router-advertisement)rf)rNr�r�r3r3r4�build_rpfilter_rules�s$



zip6tables.build_rpfilter_rulescCs�ddddddddd	g	}d
}|jdj|�g}|jddd
|g�xT|D]L}|jddd|d|ddddg
�|jjdkrF|jddd|d|ddddg
�qFW|jdddddd|g�|jdddddd|g�|S)Nz::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19ZRFC3964_IPv4r#z-tz-Nz-Iz-dz-jr�z
--reject-withzaddr-unreachr��allr�z--log-prefixz"RFC3964_IPv4_REJECT: "r�4r)r�r3)rMrgrfr@Z_log_denied)rNZ
daddr_listZ
chain_namer�Zdaddrr3r3r4�build_rfc3964_ipv4_rules�s4



z"ip6tables.build_rfc3964_ipv4_rulesN)F)r.r/r0rAr�r2r5r3r3r3r4r1�s
r1)+Zos.pathrQr�Zfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsrrrrrr	r
rZfirewallrZfirewall.errorsr
rrrrZfirewall.core.richrrrrrrrr�r�rbr�r�r5r:r>�objectr?r1r3r3r3r4�<module>s@($%* x__pycache__/fw_helper.cpython-36.pyc000064400000003705151731527040013367 0ustar003

��g)�@s6dZdgZddlmZddlmZGdd�de�ZdS)zhelper backend�FirewallHelper�)�errors)�
FirewallErrorc@s\eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�ZdS)rcCs||_i|_dS)N)Z_fw�_helpers)�self�fw�r�/usr/lib/python3.6/fw_helper.py�__init__szFirewallHelper.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rrrr	�__repr__"szFirewallHelper.__repr__cCs|jj�dS)N)r�clear)rrrr	�cleanup'szFirewallHelper.cleanupcCs||j�krttj|��dS)N)�get_helpersrr�INVALID_HELPER)r�namerrr	�check_helper*szFirewallHelper.check_helpercCs||j�kS)N)r)rrrrr	�query_helper.szFirewallHelper.query_helpercCst|jj��S)N)�sortedr�keys)rrrr	r1szFirewallHelper.get_helperscCst|j�dkS)Nr)�lenr)rrrr	�has_helpers4szFirewallHelper.has_helperscCs|j|�|j|S)N)rr)rrrrr	�
get_helper7s
zFirewallHelper.get_helpercCs||j|j<dS)N)rr)r�objrrr	�
add_helper;szFirewallHelper.add_helpercCs"||jkrttj|��|j|=dS)N)rrrr)rrrrr	�
remove_helper>s
zFirewallHelper.remove_helperN)
�__name__�
__module__�__qualname__r
rrrrrrrrrrrrr	rsN)�__doc__�__all__ZfirewallrZfirewall.errorsr�objectrrrrr	�<module>s__pycache__/__init__.cpython-36.pyc000064400000000161151731527040013144 0ustar003

��g�@sdS)N�rrr�/usr/lib/python3.6/__init__.py�<module>s__pycache__/fw_ipset.cpython-36.pyc000064400000016503151731527040013234 0ustar003

��g�%�@sfdZdgZddlmZddlmZmZmZm	Z	ddl
mZddlm
Z
ddlmZGdd�de�Zd	S)
z
ipset backend�
FirewallIPSet�)�log)�remove_default_create_options�normalize_ipset_entry�check_entry_overlaps_existing�check_for_overlapping_entries)�IPSet)�errors)�
FirewallErrorc@s�eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	d4dd�Z
dd�Zdd�Zd5dd�Z
dd�Zdd�Zdd�Zd6dd �Zd!d"�Zd#d$�Zd%d&�Zd7d'd(�Zd)d*�Zd+d,�Zd-d.�Zd/d0�Zd1d2�Zd3S)8rcCs||_i|_dS)N)�_fw�_ipsets)�self�fw�r�/usr/lib/python3.6/fw_ipset.py�__init__#szFirewallIPSet.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)r
rrr�__repr__'szFirewallIPSet.__repr__cCs|jj�dS)N)r�clear)r
rrr�cleanup,szFirewallIPSet.cleanupcCs||j�krttj|��dS)N)�
get_ipsetsr
r	Z
INVALID_IPSET)r
�namerrr�check_ipset/szFirewallIPSet.check_ipsetcCs||j�kS)N)r)r
rrrr�query_ipset3szFirewallIPSet.query_ipsetcCst|jj��S)N)�sortedr�keys)r
rrrr6szFirewallIPSet.get_ipsetscCst|j�dkS)Nr)�lenr)r
rrr�
has_ipsets9szFirewallIPSet.has_ipsetsFcCs&|j|�|j|}|r"|j|�|S)N)rr�check_applied_obj)r
r�applied�objrrr�	get_ipset<s



zFirewallIPSet.get_ipsetcCs4g}|jjr|j|jj�|jjr0|j|jj�|S)N)rZnftables_enabled�appendZnftables_backendZ
ipset_enabledZ
ipset_backend)r
�backendsrrrr#CszFirewallIPSet.backendscCs0|j|jjkr ttjd|j��||j|j<dS)Nz'%s' is not supported by ipset.)�typerZipset_supported_typesr
r	ZINVALID_TYPErr)r
r rrr�	add_ipsetKszFirewallIPSet.add_ipsetcCs�|j|}|jrh|rhy x|j�D]}|j|�q"WWqttk
rd}zttj|��WYdd}~XqtXntj	d|�|j|=dS)Nz,Keeping ipset '%s' because of timeout option)
rrr#�set_destroy�	Exceptionr
r	�COMMAND_FAILEDr�debug1)r
rZkeepr �backend�msgrrr�remove_ipsetQs
 zFirewallIPSet.remove_ipsetc<Cs$|j|}�x|j�D�]}|jdkr�|j�}||kr�d|jksv|jddksv|j||dksvt|j�||dkr�y|j|�Wn.tk
r�}zt	t
j|��WYdd}~XnX|jj
�r�y|j|j|j|j�Wn0tk
�r}zt	t
j|��WYdd}~Xn&Xd|_d|jk�r,|jddk�r,qy|j|j�Wn0tk
�rl}zt	t
j|��WYdd}~XnXx�|jD]J}y|j|j|�Wn0tk
�r�}zt	t
j|��WYdd}~XnX�qvWqy|j|j|j|j|jd�Wn0tk
�r}zt	t
j|��WYdd}~XqXd|_qWdS)N�ipset�timeout�0r�T)rr#rZset_get_active_terse�optionsr$�rm_def_cr_optsr&r'r
r	r(r�_individual_callsZ
set_creater�	set_flush�entries�set_add�set_restore)r
rr r*Zactiver+�entryrrr�apply_ipset]sL


&
zFirewallIPSet.apply_ipsetcCs>x8|j�D],}|j|}d|_tjd|�|j|�q
WdS)NFzApplying ipset '%s')rrrrr)r9)r
rr rrr�apply_ipsets�s

zFirewallIPSet.apply_ipsetscCs�xz|j�D]n}|jdkrq
x\|j�D]P}y|j|�|j|�Wq$tk
rr}z|jtjkrb|�WYdd}~Xq$Xq$Wq
WdS)NZnftables)	r#rr�
check_appliedr&r
�coder	�NOT_APPLIED)r
r*r-r+rrr�flush�s

zFirewallIPSet.flushTcCs|j||d�jS)N)r)r!r$)r
rrrrr�get_type�szFirewallIPSet.get_typecCst|j|dd�jjd��S)NT)r�,)rr!r$�split)r
rrrr�
get_dimension�szFirewallIPSet.get_dimensioncCs|j|�}|j|�dS)N)r!r)r
rr rrrr;�s
zFirewallIPSet.check_appliedcCs|jsttj|j��dS)N)rr
r	r=r)r
r rrrr�szFirewallIPSet.check_applied_objcCs.|j||d�}d|jkr*|jddkr*dSdS)N)rZfamilyZinet6Zipv6Zipv4)r!r1)r
rrr rrr�
get_family�s

zFirewallIPSet.get_familycCs�|j|dd�}t|�}tj||j|j�||jkrFttj	d||f��t
||j�y$x|j�D]}|j|j
|�q^WWn.tk
r�}zttj|��WYdd}~Xn&Xd|jks�|jddkr�|jj|�dS)NT)rz'%s' already is in '%s'r.r/)r!rr�check_entryr1r$r5r
r	ZALREADY_ENABLEDrr#r6rr'r(r")r
rr8r r*r+rrr�	add_entry�s
zFirewallIPSet.add_entrycCs�|j|dd�}t|�}||jkr4ttjd||f��y$x|j�D]}|j|j|�q@WWn.t	k
r�}zttj
|��WYdd}~Xn&Xd|jks�|jddkr�|jj|�dS)NT)rz'%s' not in '%s'r.r/)
r!rr5r
r	ZNOT_ENABLEDr#Z
set_deleterr'r(r1�remove)r
rr8r r*r+rrr�remove_entry�s
zFirewallIPSet.remove_entrycCsD|j|dd�}t|�}d|jkr:|jddkr:ttj|��||jkS)NT)rr.r/)r!rr1r
r	ZIPSET_WITH_TIMEOUTr5)r
rr8r rrr�query_entry�s
zFirewallIPSet.query_entrycCs|j|dd�}|jS)NT)r)r!r5)r
rr rrr�get_entries�szFirewallIPSet.get_entriescCs@|j|dd�}t|�x|D]}tj||j|j�qWd|jksN|jddkrT||_y"x|j�D]}|j|j	�q`WWn.t
k
r�}zttj
|��WYdd}~XnXd|_yXxR|j�D]F}|jjr�x8|jD]}|j|j	|�q�Wq�|j|j	|j|j|jd�q�WWn0t
k
�r4}zttj
|��WYdd}~XnXd|_dS)NT)rr.r/)r!rrrDr1r$r5r#r4rr'r
r	r(rrr3r6r7)r
rr5r r8r*r+rrr�set_entries�s.
zFirewallIPSet.set_entriesN)F)F)T)T)�__name__�
__module__�__qualname__rrrrrrrr!r#r%r,r9r:r>r?rBr;rrCrErGrHrIrJrrrrr"s0

1

		N)�__doc__�__all__Zfirewall.core.loggerrZfirewall.core.ipsetrr2rrrZfirewall.core.io.ipsetrZfirewallr	Zfirewall.errorsr
�objectrrrrr�<module>s__pycache__/fw_helper.cpython-36.opt-1.pyc000064400000003705151731527040014326 0ustar003

��g)�@s6dZdgZddlmZddlmZGdd�de�ZdS)zhelper backend�FirewallHelper�)�errors)�
FirewallErrorc@s\eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�ZdS)rcCs||_i|_dS)N)Z_fw�_helpers)�self�fw�r�/usr/lib/python3.6/fw_helper.py�__init__szFirewallHelper.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rrrr	�__repr__"szFirewallHelper.__repr__cCs|jj�dS)N)r�clear)rrrr	�cleanup'szFirewallHelper.cleanupcCs||j�krttj|��dS)N)�get_helpersrr�INVALID_HELPER)r�namerrr	�check_helper*szFirewallHelper.check_helpercCs||j�kS)N)r)rrrrr	�query_helper.szFirewallHelper.query_helpercCst|jj��S)N)�sortedr�keys)rrrr	r1szFirewallHelper.get_helperscCst|j�dkS)Nr)�lenr)rrrr	�has_helpers4szFirewallHelper.has_helperscCs|j|�|j|S)N)rr)rrrrr	�
get_helper7s
zFirewallHelper.get_helpercCs||j|j<dS)N)rr)r�objrrr	�
add_helper;szFirewallHelper.add_helpercCs"||jkrttj|��|j|=dS)N)rrrr)rrrrr	�
remove_helper>s
zFirewallHelper.remove_helperN)
�__name__�
__module__�__qualname__r
rrrrrrrrrrrrr	rsN)�__doc__�__all__ZfirewallrZfirewall.errorsr�objectrrrrr	�<module>s__pycache__/fw_nm.cpython-36.opt-1.pyc000064400000011713151731527040013457 0ustar003

��g�@s dZddddddddgZd	d
lZd	dlmZyejdd
�Wnek
rTdZYn8Xyd	dlmZdZWn e	eej
fk
r�dZYnXd
ad	dlm
Z
d	dlmZd	dlmZd	d
lZdd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd�Zdd �Zd!d�Zd"d�Zd#d�Zd
S)$z(Functions for NetworkManager interaction�check_nm_imported�nm_is_imported�nm_get_zone_of_connection�nm_set_zone_of_connection�nm_get_connections�nm_get_connection_of_interface�nm_get_bus_name�nm_get_dbus_interface�N)�GLib�NMz1.0F)rT)�errors)�
FirewallError)�logcCststtjd��dS)zNCheck function to raise a MISSING_IMPORT error if the import of NM failed
    zgi.repository.NM = 1.0N)�_nm_importedr
rZMISSING_IMPORT�rr�/usr/lib/python3.6/fw_nm.pyr0scCstS)znReturns true if NM has been properly imported
    @return True if import was successful, False otherwirse
    )rrrrrr6scCststjjd�atS)z�Returns the NM client object or None if the import of NM failed
    @return NM.Client instance if import was successful, None otherwise
    N)�
_nm_clientrZClient�newrrrr�
nm_get_client<srcCs�t�t�j|�}|dkrdS|j�}|dkr2dSy |j�tjjtjjB@rPdSWn t	k
rr|j
�rndSYnX|j�}|dkr�d}|S)z�Get zone of connection from NM
    @param connection name
    @return zone string setting of connection, empty string if not set, None if connection is unknown
    N�)rr�get_connection_by_uuid�get_setting_connection�	get_flagsr�SettingsConnectionFlags�NM_GENERATED�NM_VOLATILE�AttributeError�get_unsavedZget_zone)�
connection�con�setting_con�zonerrrrEs$
cCsVt�t�j|�}|dkrdS|j�}|dkr2dS|dkr>d}|jd|�|jdd�S)zSet the zone for a connection
    @param zone name
    @param connection name
    @return True if zone was set, else False
    NFrr!T)rrrrZset_propertyZcommit_changes)r!rrr rrrrcsc	Cs~|j�|j�t�t�j�}xX|D]P}|j�r4q&|j�}|j�}|j�}|||<x |D]}|j�}|rZ|||<qZWq&WdS)znGet active connections from NM
    @param connections return dict
    @param connections_name return dict
    N)	�clearrr�get_active_connections�get_vpnZget_id�get_uuid�get_devices�get_ip_iface)	ZconnectionsZconnections_nameZactive_connections�
active_con�nameZuuidZdevices�dev�ip_ifacerrrrxs


cCs�t�g}x�t�j�D]|}|j�r$qy&|j�}|j�tjjtjj	B@rHwWnt
k
rh|j�rdwYnXx&|j�D]}|j
�}|rt|j|�qtWqW|S)zGGet active interfaces from NM
    @returns list of interface names
    )rrr#r$�get_connectionrrrrrrrr&r'�append)Zactive_interfacesr(rr*r+rrr�nm_get_interfaces�s$r.cCs6g}x,t�D]"}t|�}|t|�kr|j|�qW|S)N)r.rrr-)r!Z
interfaces�	interfaceZconnrrr�nm_get_interfaces_in_zone�sr0cCs<t�x0t�j�D]"}|j�}|dkr(q||kr|SqWdS)zzGet device from NM which has the given IP interface
    @param interface name
    @returns NM.Device instance or None
    N)rrr&r')r/�devicer+rrr�nm_get_device_by_ip_iface�sr2cCsxt�t|�}|dkrdS|j�}|dkr.dSy |j�}|j�tjj@rLdSWn tk
rn|j	�rjdSYnX|j
�S)z�Get connection from NM that is using the interface
    @param interface name
    @returns connection that is using interface or None
    N)rr2Zget_active_connectionr,rrrrrrr%)r/r1r(rrrrr�s
cCsRtsdSy&tj�}|jtjtj�}|j}~~|Stk
rLt	j
d�YnXdS)Nz(Failed to get bus name of NetworkManager)r�dbusZ	SystemBusZ
get_objectr�DBUS_INTERFACEZ	DBUS_PATHZbus_name�	ExceptionrZdebug2)Zbus�objr)rrrr�scCstsdStjS)Nr)rrr4rrrrr�s)�__doc__�__all__ZgiZ
gi.repositoryr
Zrequire_version�
ValueErrorrr�ImportError�ErrorrZfirewallrZfirewall.errorsr
Zfirewall.core.loggerrr3rrrrrrr.r0r2rrrrrrr�<module>s@

	 	
__pycache__/fw_config.cpython-36.opt-1.pyc000064400000077161151731527040014323 0ustar003

��g��@s�dgZddlZddlZddlZddlZddlmZddlmZddl	m
Z
mZmZddl
mZmZmZddlmZmZmZddlmZmZmZdd	lmZmZmZdd
lmZmZm Z ddlm!Z!ddl"m#Z#Gd
d�de$�Z%dS)�FirewallConfig�N)�config)�log)�IcmpType�icmptype_reader�icmptype_writer)�Service�service_reader�service_writer)�Zone�zone_reader�zone_writer)�IPSet�ipset_reader�ipset_writer)�Helper�
helper_reader�
helper_writer)�Policy�
policy_reader�
policy_writer)�errors)�
FirewallErrorc@s$eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd#d$�Zd%d&�Zd'd(�Zd)d*�Zd+d,�Zd-d.�Zd/d0�Zd1d2�Zd3d4�Zd5d6�Zd7d8�Zd9d:�Zd;d<�Z d=d>�Z!d?d@�Z"dAdB�Z#dCdD�Z$dEdF�Z%dGdH�Z&dIdJ�Z'dKdL�Z(dMdN�Z)dOdP�Z*dQdR�Z+dSdT�Z,dUdV�Z-dWdX�Z.dYdZ�Z/d[d\�Z0d]d^�Z1d_d`�Z2dadb�Z3dcdd�Z4dedf�Z5dgdh�Z6didj�Z7dkdl�Z8dmdn�Z9dodp�Z:dqdr�Z;dsdt�Z<dudv�Z=dwdx�Z>dydz�Z?d{d|�Z@d}d~�ZAdd��ZBd�d��ZCd�d��ZDd�d��ZEd�d��ZFd�d��ZGd�d��ZHd�d��ZId�d��ZJd�d��ZKd�d��ZLd�d��ZMd�d��ZNd�d��ZOd�d��ZPd�d��ZQd�d��ZRd�d��ZSd�d��ZTd�d��ZUd�d��ZVd�d��ZWd�d��ZXd�d��ZYd�d��ZZd�d��Z[d�d��Z\d�d��Z]d�d��Z^d�d��Z_d�d��Z`d�d��Zad�d��Zbd�d„Zcd�dĄZdd�dƄZed�S)�rcCs||_|j�dS)N)�_fw�_FirewallConfig__init_vars)�self�fw�r�/usr/lib/python3.6/fw_config.py�__init__(szFirewallConfig.__init__cCsHd|j|j|j|j|j|j|j|j|j|j	|j
|j|j|j
|j|jfS)Nz>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r))�	__class__�_ipsets�
_icmptypes�	_services�_zones�_helpersZpolicy_objects�_builtin_ipsets�_builtin_icmptypes�_builtin_services�_builtin_zones�_builtin_helpers�_builtin_policy_objects�_firewalld_conf�	_policies�_direct)rrrr�__repr__,szFirewallConfig.__repr__cCs^i|_i|_i|_i|_i|_i|_i|_i|_i|_i|_	i|_
i|_d|_d|_
d|_dS)N)r!r"r#r$r%�_policy_objectsr&r'r(r)r*r+r,r-r.)rrrrZ__init_vars6szFirewallConfig.__init_varscCs4x,t|jj��D]}|j|j�|j|=qWx,t|jj��D]}|j|j�|j|=q>Wx,t|jj��D]}|j|j�|j|=qlWx,t|jj��D]}|j|j�|j|=q�Wx,t|jj��D]}|j|j�|j|=q�Wx,t|jj��D]}|j|j�|j|=q�Wx.t|j	j��D]}|j	|j�|j	|=�q$Wx.t|j
j��D]}|j
|j�|j
|=�qTWx.t|jj��D]}|j|j�|j|=�q�Wx.t|jj��D]}|j|j�|j|=�q�W|j
�r�|j
j�|`
d|_
|j�r|jj�|`d|_|j�r(|jj�|`d|_|j�dS)N)�listr&�keys�cleanupr!r'r"r(r#r)r$r*r%r,r-r.r)r�xrrrr3GsV


zFirewallConfig.cleanupcCs|jjj�S)N)r�policiesZquery_lockdown)rrrr�lockdown_enabled~szFirewallConfig.lockdown_enabledcCs|jjj||�S)N)rr5�access_check)r�key�valuerrrr7�szFirewallConfig.access_checkcCs
||_dS)N)r,)r�confrrr�set_firewalld_conf�sz!FirewallConfig.set_firewalld_confcCs|jS)N)r,)rrrr�get_firewalld_conf�sz!FirewallConfig.get_firewalld_confcCs(tjjtj�s|jj�n
|jj�dS)N)�os�path�existsrZFIREWALLD_CONFr,�clear�read)rrrr�update_firewalld_conf�sz$FirewallConfig.update_firewalld_confcCs
||_dS)N)r-)rr5rrr�set_policies�szFirewallConfig.set_policiescCs|jS)N)r-)rrrr�get_policies�szFirewallConfig.get_policiescCs,tjjtj�s|jjj�n|jjj�dS)N)	r=r>r?rZLOCKDOWN_WHITELISTr-Zlockdown_whitelistr3rA)rrrr�update_lockdown_whitelist�sz(FirewallConfig.update_lockdown_whitelistcCs
||_dS)N)r.)rZdirectrrr�
set_direct�szFirewallConfig.set_directcCs|jS)N)r.)rrrr�
get_direct�szFirewallConfig.get_directcCs(tjjtj�s|jj�n
|jj�dS)N)r=r>r?rZFIREWALLD_DIRECTr.r3rA)rrrr�
update_direct�szFirewallConfig.update_directcCs$ttt|jj��t|jj����S)N)�sorted�setr1r!r2r&)rrrr�
get_ipsets�szFirewallConfig.get_ipsetscCs$|jr||j|j<n||j|j<dS)N)�builtinr&�namer!)r�objrrr�	add_ipset�szFirewallConfig.add_ipsetcCs8||jkr|j|S||jkr(|j|Sttj|��dS)N)r!r&rr�
INVALID_IPSET)rrMrrr�	get_ipset�s




zFirewallConfig.get_ipsetcCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._ipsets[%s] != objz'%s' not a built-in ipset)rMr!rr�NO_DEFAULTSr&�
_remove_ipset)rrNrrr�load_ipset_defaults�s
z"FirewallConfig.load_ipset_defaultscCs|j�S)N)�
export_config)rrNrrr�get_ipset_config�szFirewallConfig.get_ipset_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rL�copy�
import_configr�ETC_FIREWALLD_IPSETSr>�defaultrOr)rrNr:r4rrr�set_ipset_config�s



zFirewallConfig.set_ipset_configcCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_ipset(): '%s'z%s.xmlFT)r!r&rr�
NAME_CONFLICTr�
check_namerXrM�filenamerrYr>rLrZrrO)rrMr:r4rrr�	new_ipset�s




zFirewallConfig.new_ipsetcCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)N�update�removezLoading ipset file '%s'z"Failed to load ipset file '%s': %s�new)NN)NN)NN)NN)NN)r=r>�basename�dirnamer?rrYr!r2r^rMr&r�debug1r�	Exception�errorrOrZ)rrMr^r>r4rN�msgrrr�update_ipset_from_path�sP






z%FirewallConfig.update_ipset_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr!rrrPr>rrY�INVALID_DIRECTORY�shutil�moverfrrgr=ra)rrNrMrhrrrrS8szFirewallConfig._remove_ipsetcCs$|js|jr ttjd|j��dS)Nz'%s' is built-in ipset)rLrZrrZ
BUILTIN_IPSETrM)rrNrrr�check_builtin_ipsetIsz"FirewallConfig.check_builtin_ipsetcCs|j|�|j|�dS)N)rmrS)rrNrrr�remove_ipsetNs
zFirewallConfig.remove_ipsetcCs$|j|�|j||�}|j|�|S)N)rm�_copy_ipsetrS)rrNrMr_rrr�rename_ipsetRs

zFirewallConfig.rename_ipsetcCs|j||j��S)N)r_rU)rrNrMrrrroXszFirewallConfig._copy_ipsetcCs$ttt|jj��t|jj����S)N)rIrJr1r"r2r')rrrr�
get_icmptypes]szFirewallConfig.get_icmptypescCs$|jr||j|j<n||j|j<dS)N)rLr'rMr")rrNrrr�add_icmptypeaszFirewallConfig.add_icmptypecCs8||jkr|j|S||jkr(|j|Sttj|��dS)N)r"r'rr�INVALID_ICMPTYPE)rrMrrr�get_icmptypegs




zFirewallConfig.get_icmptypecCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._icmptypes[%s] != objz'%s' not a built-in icmptype)rMr"rrrRr'�_remove_icmptype)rrNrrr�load_icmptype_defaultsns
z%FirewallConfig.load_icmptype_defaultscCs|j�S)N)rU)rrNrrr�get_icmptype_configzsz"FirewallConfig.get_icmptype_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rLrWrXr�ETC_FIREWALLD_ICMPTYPESr>rZrrr)rrNr:r4rrr�set_icmptype_config}s



z"FirewallConfig.set_icmptype_configcCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_icmptype(): '%s'z%s.xmlFT)r"r'rrr\rr]rXrMr^rrxr>rLrZrrr)rrMr:r4rrr�new_icmptype�s




zFirewallConfig.new_icmptypecCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)Nr`razLoading icmptype file '%s'z%Failed to load icmptype file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrxr"r2r^rMr'rrerrfrgrrrZ)rrMr^r>r4rNrhrrr�update_icmptype_from_path�sP






z(FirewallConfig.update_icmptype_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr"rrrsr>rrxrjrkrlrfrrgr=ra)rrNrMrhrrrru�szFirewallConfig._remove_icmptypecCs$|js|jr ttjd|j��dS)Nz'%s' is built-in icmp type)rLrZrrZBUILTIN_ICMPTYPErM)rrNrrr�check_builtin_icmptype�sz%FirewallConfig.check_builtin_icmptypecCs|j|�|j|�dS)N)r|ru)rrNrrr�remove_icmptype�s
zFirewallConfig.remove_icmptypecCs$|j|�|j||�}|j|�|S)N)r|�_copy_icmptyperu)rrNrMrzrrr�rename_icmptype�s

zFirewallConfig.rename_icmptypecCs|j||j��S)N)rzrU)rrNrMrrrr~szFirewallConfig._copy_icmptypecCs$ttt|jj��t|jj����S)N)rIrJr1r#r2r()rrrr�get_services
szFirewallConfig.get_servicescCs$|jr||j|j<n||j|j<dS)N)rLr(rMr#)rrNrrr�add_serviceszFirewallConfig.add_servicecCs<||jkr|j|S||jkr(|j|Sttjd|��dS)Nzget_service(): '%s')r#r(rr�INVALID_SERVICE)rrMrrr�get_services




zFirewallConfig.get_servicecCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._services[%s] != objz'%s' not a built-in service)rMr#rrrRr(�_remove_service)rrNrrr�load_service_defaultss
z$FirewallConfig.load_service_defaultscCsr|j�}g}x\td�D]P}|j|d|krN|jtjt||j|d���q|j||j|d�qWt|�S)N�r)�export_config_dict�range�IMPORT_EXPORT_STRUCTURE�appendrW�deepcopy�getattr�tuple)rrN�	conf_dict�	conf_list�irrr�get_service_config's"z!FirewallConfig.get_service_configcCs|j�S)N)r�)rrNrrr�get_service_config_dict3sz&FirewallConfig.get_service_config_dictcCs�i}x&t|�D]\}}|||j|d<qW|jr|tj|�}|j|�tj|_d|_|j|jkrfd|_|j	|�t
|�|S|j|�t
|�|SdS)NrF)�	enumerater�rLrW�import_config_dictr�ETC_FIREWALLD_SERVICESr>rZr�r
)rrNr:r�r�r9r4rrr�set_service_config6s 



z!FirewallConfig.set_service_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rLrWr�rr�r>rZr�r
)rrNr:r4rrr�set_service_config_dictJs



z&FirewallConfig.set_service_config_dictcCs�||jks||jkr$ttjd|��i}x&t|�D]\}}||tj|d<q2Wt�}|j|�|j	|�||_
d||_tj
|_d|_d|_t|�|j|�|S)Nznew_service(): '%s'rz%s.xmlFT)r#r(rrr\r�rr�r]r�rMr^rr�r>rLrZr
r�)rrMr:r�r�r9r4rrr�new_serviceZs"




zFirewallConfig.new_servicecCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_service(): '%s'z%s.xmlFT)r#r(rrr\rr]r�rMr^rr�r>rLrZr
r�)rrMr:r4rrr�new_service_dictqs




zFirewallConfig.new_service_dictcCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)Nr`razLoading service file '%s'z$Failed to load service file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rr�r#r2r^rMr(rrer	rfrgr�rZ)rrMr^r>r4rNrhrrr�update_service_from_path�sP






z'FirewallConfig.update_service_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr#rrr�r>rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr��szFirewallConfig._remove_servicecCs$|js|jr ttjd|j��dS)Nz'%s' is built-in service)rLrZrrZBUILTIN_SERVICErM)rrNrrr�check_builtin_service�sz$FirewallConfig.check_builtin_servicecCs|j|�|j|�dS)N)r�r�)rrNrrr�remove_service�s
zFirewallConfig.remove_servicecCs$|j|�|j||�}|j|�|S)N)r��
_copy_servicer�)rrNrMr�rrr�rename_service�s

zFirewallConfig.rename_servicecCs|j||j��S)N)r�r�)rrNrMrrrr��szFirewallConfig._copy_servicecCs$ttt|jj��t|jj����S)N)rIrJr1r$r2r))rrrr�	get_zones�szFirewallConfig.get_zonescCs$|jr||j|j<n||j|j<dS)N)rLr)rMr$)rrNrrr�add_zone�szFirewallConfig.add_zonecCs(||jkr|j|=||jkr$|j|=dS)N)r)r$)rrMrrr�forget_zone�s

zFirewallConfig.forget_zonecCs<||jkr|j|S||jkr(|j|Sttjd|��dS)Nzget_zone(): %s)r$r)rr�INVALID_ZONE)rrMrrr�get_zone�s




zFirewallConfig.get_zonecCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._zones[%s] != objz'%s' not a built-in zone)rMr$rrrRr)�_remove_zone)rrNrrr�load_zone_defaultss
z!FirewallConfig.load_zone_defaultscCsr|j�}g}x\td�D]P}|j|d|krN|jtjt||j|d���q|j||j|d�qWt|�S)N�r)r�r�r�r�rWr�r�r�)rrNr�r�r�rrr�get_zone_configs"zFirewallConfig.get_zone_configcCs|j�S)N)r�)rrNrrr�get_zone_config_dictsz#FirewallConfig.get_zone_config_dictcCs�i}x&t|�D]\}}|||j|d<qW|jr�tj|�}||_|j|�tj|_d|_|j|jkrld|_	|j
|�t|�|S||_|j|�t|�|SdS)NrF)r�r�rLrW�	fw_configr�r�ETC_FIREWALLD_ZONESr>rZr�r
)rrNr:r�r�r9r4rrr�set_zone_config s$



zFirewallConfig.set_zone_configcCsv|jrVtj|�}||_|j|�tj|_d|_|j|jkr@d|_|j|�t	|�|S||_|j|�t	|�|SdS)NF)
rLrWr�r�rr�r>rZr�r
)rrNr:r4rrr�set_zone_config_dict6s



z#FirewallConfig.set_zone_config_dictcCs�||jks||jkr$ttjd|��i}x&t|�D]\}}||tj|d<q2Wt�}||_|j	|�|j
|�||_d||_t
j|_d|_d|_t|�|j|�|S)Nznew_zone(): '%s'rz%s.xmlFT)r$r)rrr\r�rr�r�r]r�rMr^rr�r>rLrZr
r�)rrMr:r�r�r9r4rrr�new_zoneHs"



zFirewallConfig.new_zonecCs~||jks||jkr$ttjd|��t�}||_|j|�|j|�||_	d||_
tj|_
d|_d|_t|�|j|�|S)Nznew_zone(): '%s'z%s.xmlFT)r$r)rrr\rr�r]r�rMr^rr�r>rLrZr
r�)rrMr:r4rrr�
new_zone_dict_s



zFirewallConfig.new_zone_dictcCstjj|�}tjj|�}tjj|�s�|jtj�r�x�|jj	�D]D}|j|}|j
|kr<|j|=|j|jkrxd|j|jfSd|fSq<WnHxF|jj	�D]8}|j|}|j
|kr�|j|=|j|jkr�d|fSd	Sq�Wd
St
jd|�yt||�}Wn0tk
�r}zt
jd||�dSd}~XnX||_|jtj��rlt|�ttj�k�rldtjj|�tjj|�dd�f|_|j|jk�r�|j|jk�r�|j|�d|fS|jtj��r�|j|jk�r�|j|jj|_||j|j<d|fS|j|jk�r|j|j=||j|j<|j|jk�rd|fSd
SdS)Nr`razLoading zone file '%s'z!Failed to load zone file '%s': %sz%s/%sr�rb)NN)NN)NN���)NN)NN)r=r>rcrdr?�
startswithrr�r$r2r^rMr)rrerrfrgr��lenr�rZ)rrMr^r>r4rNrhrrr�update_zone_from_pathrsZ





z$FirewallConfig.update_zone_from_pathcCs�|j|jkrttj|j��|jjtj�s@ttj	d|jtjf��d|j|jf}yt
j|d|�Wn:tk
r�}zt
jd||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr$rrr�r>r�rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr��szFirewallConfig._remove_zonecCs$|js|jr ttjd|j��dS)Nz'%s' is built-in zone)rLrZrrZBUILTIN_ZONErM)rrNrrr�check_builtin_zone�sz!FirewallConfig.check_builtin_zonecCs|j|�|j|�dS)N)r�r�)rrNrrr�remove_zone�s
zFirewallConfig.remove_zonec	CsN|j|�|j�}|j|�y|j||�}Wn|j|j|��YnX|S)N)r�r�r�r�rM)rrNrMZobj_confr�rrr�rename_zone�s

zFirewallConfig.rename_zonecCs$ttt|jj��t|jj����S)N)rIrJr1r0r2r+)rrrr�get_policy_objects�sz!FirewallConfig.get_policy_objectscCs$|jr||j|j<n||j|j<dS)N)rLr+rMr0)rrNrrr�add_policy_object�sz FirewallConfig.add_policy_objectcCs<||jkr|j|S||jkr(|j|Sttjd|��dS)Nzget_policy_object(): %s)r0r+rr�INVALID_POLICY)rrMrrr�get_policy_object�s




z FirewallConfig.get_policy_objectcCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._policy_objects[%s] != objz'%s' not a built-in policy)rMr0rrrRr+�_remove_policy_object)rrNrrr�load_policy_object_defaults�s
z*FirewallConfig.load_policy_object_defaultscCs|j�S)N)r�)rrNrrr�get_policy_object_config_dictsz,FirewallConfig.get_policy_object_config_dictcCsv|jrVtj|�}||_|j|�tj|_d|_|j|jkr@d|_|j|�t	|�|S||_|j|�t	|�|SdS)NF)
rLrWr�r�r�ETC_FIREWALLD_POLICIESr>rZr�r)rrNr:r4rrr�set_policy_object_config_dicts



z,FirewallConfig.set_policy_object_config_dictcCs~||jks||jkr$ttjd|��t�}||_|j|�|j|�||_	d||_
tj|_
d|_d|_t|�|j|�|S)Nznew_policy_object(): '%s'z%s.xmlFT)r0r+rrr\rr�r]r�rMr^rr�r>rLrZrr�)rrMr:r4rrr�new_policy_object_dicts



z%FirewallConfig.new_policy_object_dictcCstjj|�}tjj|�}tjj|�s�|jtj�r�x�|jj	�D]D}|j|}|j
|kr<|j|=|j|jkrxd|j|jfSd|fSq<WnHxF|jj	�D]8}|j|}|j
|kr�|j|=|j|jkr�d|fSd	Sq�Wd
St
jd|�yt||�}Wn0tk
�r}zt
jd||�dSd}~XnX||_|jtj��rlt|�ttj�k�rldtjj|�tjj|�dd�f|_|j|jk�r�|j|jk�r�|j|�d|fS|jtj��r�|j|jk�r�|j|jj|_||j|j<d|fS|j|jk�r|j|j=||j|j<|j|jk�rd|fSd
SdS)Nr`razLoading policy file '%s'z#Failed to load policy file '%s': %sz%s/%srr�rb)NN)NN)NNr�)NN)NN)r=r>rcrdr?r�rr�r0r2r^rMr+rrerrfrgr�r�r�rZ)rrMr^r>r4rNrhrrr�update_policy_object_from_path,sZ





z-FirewallConfig.update_policy_object_from_pathcCs�|j|jkrttj|j��|jjtj�s@ttj	d|jtjf��d|j|jf}yt
j|d|�Wn:tk
r�}zt
jd||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr0rrr�r>r�rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr�ysz$FirewallConfig._remove_policy_objectcCs$|js|jr ttjd|j��dS)Nz'%s' is built-in policy)rLrZrrZBUILTIN_POLICYrM)rrNrrr�check_builtin_policy_object�sz*FirewallConfig.check_builtin_policy_objectcCs|j|�|j|�dS)N)r�r�)rrNrrr�remove_policy_object�s
z#FirewallConfig.remove_policy_objectcCs$|j|�|j||�}|j|�|S)N)r��_copy_policy_objectr�)rrNrMZnew_policy_objectrrr�rename_policy_object�s

z#FirewallConfig.rename_policy_objectcCs|j||j��S)N)r�r�)rrNrMrrrr��sz"FirewallConfig._copy_policy_objectcCs$ttt|jj��t|jj����S)N)rIrJr1r%r2r*)rrrr�get_helpers�szFirewallConfig.get_helperscCs$|jr||j|j<n||j|j<dS)N)rLr*rMr%)rrNrrr�
add_helper�szFirewallConfig.add_helpercCs8||jkr|j|S||jkr(|j|Sttj|��dS)N)r%r*rr�INVALID_HELPER)rrMrrr�
get_helper�s




zFirewallConfig.get_helpercCst|j|jkrttj|j��nB|j|j|kr@ttjd|j��n|j|jkr^ttjd|j��|j|�|j|jS)Nzself._helpers[%s] != objz'%s' not a built-in helper)rMr%rrrRr*�_remove_helper)rrNrrr�load_helper_defaults�s
z#FirewallConfig.load_helper_defaultscCs|j�S)N)rU)rrNrrr�get_helper_config�sz FirewallConfig.get_helper_configcCsj|jrPtj|�}|j|�tj|_d|_|j|jkr:d|_|j|�t|�|S|j|�t|�|SdS)NF)	rLrWrXr�ETC_FIREWALLD_HELPERSr>rZr�r)rrNr:r4rrr�set_helper_config�s



z FirewallConfig.set_helper_configcCsx||jks||jkr$ttjd|��t�}|j|�|j|�||_d||_	t
j|_d|_
d|_t|�|j|�|S)Nznew_helper(): '%s'z%s.xmlFT)r%r*rrr\rr]rXrMr^rr�r>rLrZrr�)rrMr:r4rrr�
new_helper�s




zFirewallConfig.new_helpercCs�tjj|�}tjj|�}tjj|�s�|tjkr�x�|jj�D]D}|j|}|j	|kr:|j|=|j
|jkrvd|j|j
fSd|fSq:WnHxF|jj�D]8}|j|}|j	|kr�|j|=|j
|jkr�d|fSdSq�WdStj
d|�yt||�}Wn0tk
�r}ztjd||�dSd}~XnX|j
|jk�rJ|j
|jk�rJ|j|�d|fS|tjk�r�|j
|jk�r�|j|j
j|_||j|j
<d|fS|j
|jk�r�|j|j
=||j|j
<|j
|jk�r�d|fSd	Sd
S)Nr`razLoading helper file '%s'z#Failed to load helper file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rr�r%r2r^rMr*rrerrfrgr�rZ)rrMr^r>r4rNrhrrr�update_helper_from_path�sP






z&FirewallConfig.update_helper_from_pathcCs�|j|jkrttj|j��|jtjkr>ttjd|jtjf��d|j|jf}yt	j
|d|�Wn:tk
r�}ztj
d||�tj|�WYdd}~XnX|j|j=dS)Nz'%s' != '%s'z	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr%rrr�r>rr�rjrkrlrfrrgr=ra)rrNrMrhrrrr�&szFirewallConfig._remove_helpercCs$|js|jr ttjd|j��dS)Nz'%s' is built-in helper)rLrZrrZBUILTIN_HELPERrM)rrNrrr�check_builtin_helper7sz#FirewallConfig.check_builtin_helpercCs|j|�|j|�dS)N)r�r�)rrNrrr�
remove_helper<s
zFirewallConfig.remove_helpercCs$|j|�|j||�}|j|�|S)N)r��_copy_helperr�)rrNrMr�rrr�
rename_helper@s

zFirewallConfig.rename_helpercCs|j||j��S)N)r�rU)rrNrMrrrr�FszFirewallConfig._copy_helperN)f�__name__�
__module__�__qualname__rr/rr3r6r7r;r<rBrCrDrErFrGrHrKrOrQrTrVr[r_rirSrmrnrprorqrrrtrvrwryrzr{rur|r}rr~r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�rrrrr's�
7EEEMME)&�__all__rWr=Zos.pathrkZfirewallrZfirewall.core.loggerrZfirewall.core.io.icmptyperrrZfirewall.core.io.servicerr	r
Zfirewall.core.io.zonerrr
Zfirewall.core.io.ipsetrrrZfirewall.core.io.helperrrrZfirewall.core.io.policyrrrrZfirewall.errorsr�objectrrrrr�<module>s__pycache__/prog.cpython-36.opt-1.pyc000064400000001266151731527040013322 0ustar003

��g��@sddlZdgZddd�ZdS)�N�runProgc
Cs�|dkrg}|g|}d}|r@t|d��}|j�j�}WdQRXddi}y tj|tjtjtjd|d�}Wntk
r|d
SX|j|�\}}	|j	dd	�}|j
|fS)N�rZLANG�CT)�stdin�stderr�stdoutZ	close_fds�env��zutf-8�replace)r	r
)�open�read�encode�
subprocess�Popen�PIPEZSTDOUT�OSErrorZcommunicate�decode�
returncode)
�prog�argvr�argsZinput_stringZhandlerZprocess�outputZ
err_output�r�/usr/lib/python3.6/prog.pyrs$

)NN)r�__all__rrrrr�<module>s__pycache__/fw_direct.cpython-36.pyc000064400000031230151731527040013354 0ustar003

��g�W�@sndgZddlmZddlmZddlmZddlmZddlm	Z	ddl
mZddlm
Z
Gd	d�de�Zd
S)�FirewallDirect�)�LastUpdatedOrderedDict)�	ipXtables)�ebtables)�FirewallTransaction)�log)�errors)�
FirewallErrorc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dNdd�Zdd�Zdd�Z
dOdd�Zdd�Zdd�Zdd�Zd d!�ZdPd"d#�ZdQd$d%�Zd&d'�Zd(d)�Zd*d+�ZdRd,d-�ZdSd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�ZdTd<d=�Z dUd>d?�Z!d@dA�Z"dBdC�Z#dDdE�Z$dFdG�Z%dHdI�Z&dJdK�Z'dLdM�Z(dS)VrcCs||_|j�dS)N)�_fw�_FirewallDirect__init_vars)�self�fw�r�/usr/lib/python3.6/fw_direct.py�__init__'szFirewallDirect.__init__cCsd|j|j|j|jfS)Nz%s(%r, %r, %r))�	__class__�_chains�_rules�_rule_priority_positions)rrrr�__repr__+szFirewallDirect.__repr__cCs"i|_i|_i|_i|_d|_dS)N)rrr�
_passthroughs�_obj)rrrrZ__init_vars/s
zFirewallDirect.__init_varscCs|j�dS)N)r)rrrr�cleanup6szFirewallDirect.cleanupcCs
t|j�S)N)rr
)rrrr�new_transaction;szFirewallDirect.new_transactioncCs
||_dS)N)r)r�objrrr�set_permanent_config@sz#FirewallDirect.set_permanent_configcCs*t|j�t|j�t|j�dkr&dSdS)NrTF)�lenrrr)rrrr�has_runtime_configurationCs"z(FirewallDirect.has_runtime_configurationcCsB|j�rdSt|jj��t|jj��t|jj��dkr>dSdS)NTrF)rrr�get_all_chains�
get_all_rules�get_all_passthroughs)rrrr�has_configurationHsz FirewallDirect.has_configurationNcCsP|dkr|j�}n|}|j|jj�|jj�|jj�f|�|dkrL|jd�dS)NT)r�
set_configrrrr �execute)r�use_transaction�transactionrrr�apply_directQs

zFirewallDirect.apply_directcCsi}i}i}xL|jD]B}|\}}x4|j|D]&}|jj|||�s,|j|g�j|�q,WqWxf|jD]\}|\}}}xL|j|D]>\}	}
|jj||||	|
�s|||kr�t�||<|	|||	|
f<q|WqbWxP|jD]F}x@|j|D]2}
|jj	||
�s�||k�r�g||<||j|
�q�Wq�W|||fS)N)
rr�query_chain�
setdefault�appendr�
query_rulerr�query_passthrough)rZchains�rulesZpassthroughs�table_id�ipv�table�chain�chain_id�priority�argsrrr�get_runtime_configbs,


z!FirewallDirect.get_runtime_configcCs|j|j|jfS)N)rrr)rrrr�
get_config�szFirewallDirect.get_configcCs�|dkr|j�}n|}|\}}}x||D]t}|\}}	xf||D]Z}
|j||	|
�s<y|j||	|
|d�Wq<tk
r�}ztjt|��WYdd}~Xq<Xq<Wq&Wx�|D]�}|\}}	}
xt||D]h\}
}|j||	|
|
|�s�y|j||	|
|
||d�Wq�tk
�r"}ztjt|��WYdd}~Xq�Xq�Wq�Wxx|D]p}xh||D]\}|j	||��s@y|j
|||d�Wn2tk
�r�}ztjt|��WYdd}~XnX�q@W�q2W|dk�r�|jd�dS)N)r$T)rr'�	add_chainr	rZwarning�strr*�add_ruler+�add_passthroughr#)rZconfr$r%rrrr-r.r/r0�errorr1r2r3rrrr"�s@



(

(
,
zFirewallDirect.set_configcCs*dddg}||kr&ttjd||f��dS)N�ipv4�ipv6Zebz'%s' not in '%s')r	rZINVALID_IPV)rr.Zipvsrrr�
_check_ipv�s
zFirewallDirect._check_ipvcCsF|j|�|dkrtjj�ntjj�}||krBttjd||f��dS)Nr;r<z'%s' not in '%s')r;r<)r=r�BUILT_IN_CHAINS�keysrr	rZ
INVALID_TABLE)rr.r/Ztablesrrr�_check_ipv_table�s

zFirewallDirect._check_ipv_tablecCs�|dkr4tj|}|jjr i}qH|jj|�j|}ntj|}tj|}||kr`tt	j
d|��||krxtt	j
d|��|dkr�|jjj|�dk	r�tt	j
d|��dS)Nr;r<zchain '%s' is built-in chainzchain '%s' is reservedzChain '%s' is reserved)r;r<)r;r<)rr>r
�nftables_enabled�get_direct_backend_by_ipv�
our_chainsrZ
OUR_CHAINSr	rZ
BUILTIN_CHAIN�zoneZzone_from_chainZ
INVALID_CHAIN)rr.r/r0Zbuilt_in_chainsrCrrr�_check_builtin_chain�s"




z#FirewallDirect._check_builtin_chaincCsH|r|jj|g�j|�n*|j|j|�t|j|�dkrD|j|=dS)Nr)rr(r)�remover)rr-r0�addrrr�_register_chain�s
zFirewallDirect._register_chaincCsV|dkr|j�}n|}|jj�r.|j|jj�|jd||||�|dkrR|jd�dS)NT)rr
�may_skip_flush_direct_backends�add_pre�flush_direct_backends�_chainr#)rr.r/r0r$r%rrrr6�s

zFirewallDirect.add_chaincCs>|dkr|j�}n|}|jd||||�|dkr:|jd�dS)NFT)rrLr#)rr.r/r0r$r%rrr�remove_chain�s
zFirewallDirect.remove_chaincCs:|j||�|j|||�||f}||jko8||j|kS)N)r@rEr)rr.r/r0r-rrrr'�s

zFirewallDirect.query_chaincCs,|j||�||f}||jkr(|j|SgS)N)r@r)rr.r/r-rrr�
get_chains�s


zFirewallDirect.get_chainscCsDg}x:|jD]0}|\}}x"|j|D]}|j|||f�q$WqW|S)N)rr))r�r�keyr.r/r0rrrrszFirewallDirect.get_all_chainscCsZ|dkr|j�}n|}|jj�r.|j|jj�|jd||||||�|dkrV|jd�dS)NT)rr
rIrJrK�_ruler#)rr.r/r0r2r3r$r%rrrr8	s

zFirewallDirect.add_rulecCsB|dkr|j�}n|}|jd||||||�|dkr>|jd�dS)NFT)rrQr#)rr.r/r0r2r3r$r%rrr�remove_rules
zFirewallDirect.remove_rulecCs2|j||�|||f}||jko0||f|j|kS)N)r@r)rr.r/r0r2r3r1rrrr*#s

zFirewallDirect.query_rulecCs6|j||�|||f}||jkr2t|j|j��SgS)N)r@r�listr?)rr.r/r0r1rrr�	get_rules)s


zFirewallDirect.get_rulesc	CsRg}xH|jD]>}|\}}}x.|j|D] \}}|j||||t|�f�q&WqW|S)N)rr)rS)rrOrPr.r/r0r2r3rrrr0s
 zFirewallDirect.get_all_rulescCs�|rr||jkrt�|j|<||j||<||jkr<i|j|<||j|krb|j|||7<q�||j||<n<|j||=t|j|�dkr�|j|=|j|||8<dS)Nr)rrrr)r�rule_idr1r2�enable�countrrr�_register_rule8s


zFirewallDirect._register_rulecCsVy|jj|jj|�j|�Stk
rP}ztj|�ttj	|��WYdd}~XnXdS)N)
r
�rulerB�name�	ExceptionrZdebug2r	rZCOMMAND_FAILED)rr.r3�msgrrr�passthroughLs

zFirewallDirect.passthroughcCsX|r*||jkrg|j|<|j|j|�n*|j|j|�t|j|�dkrT|j|=dS)Nr)rr)rFr)rr.r3rVrrr�_register_passthroughTs

z$FirewallDirect._register_passthroughcCsX|dkr|j�}n|}|jj�r.|j|jj�|jd|t|�|�|dkrT|jd�dS)NT)rr
rIrJrK�_passthroughrSr#)rr.r3r$r%rrrr9^s

zFirewallDirect.add_passthroughcCs@|dkr|j�}n|}|jd|t|�|�|dkr<|jd�dS)NFT)rr_rSr#)rr.r3r$r%rrr�remove_passthroughls
z!FirewallDirect.remove_passthroughcCs||jkot|�|j|kS)N)r�tuple)rr.r3rrrr+ws
z FirewallDirect.query_passthroughcCs>g}x4|jD]*}x$|j|D]}|j|t|�f�qWqW|S)N)rr)rS)rrOr.r3rrrr {s
z#FirewallDirect.get_all_passthroughscCs4g}||jkr0x |j|D]}|jt|��qW|S)N)rr)rS)rr.rOr3rrr�get_passthroughs�s

zFirewallDirect.get_passthroughscCs�g}x�|D]�}d}x�|D]�}y|j|�}Wntk
r>YqXt|�|krd||dkrd}||djd�}x.|D]&}	|dd�}
|	|
|d<|j|
�qxWqW|s
|j|�q
W|S)z5Split values combined with commas for options in optsF�,�TN)�index�
ValueErrorr�splitr))rr,ZoptsZ	out_rulesrYZ	processed�opt�i�items�itemrQrrr�split_value�s$


zFirewallDirect.split_valuec
Cs*|j||�|jjr2|dkr2|jjj||||�|}|jj|�}	|jjrd|	j|||�rdd|}n:|jjr�|dd�dkr�|	j|||dd��r�|dd�}|||f}
||f}|r�|
|jkr�||j|
kr�tt	j
d||||f��nB|
|jk�s||j|
k�rtt	jd||||f��|j|
|}d}d	}
|
|jk�r�t
|j|
j��}d	}x@|t|�k�r�|||k�r�||j|
||7}|d7}�qTWt|�g}|j|d
dg�}|j|dd
g�}x<|D]4}|j|	|	j||||t|���|d7}|
d7}
�q�W|j||
|||
�|j|j||
|||
�dS)Nr;r<z	%s_direct�Z_directz"rule '%s' already is in '%s:%s:%s'zrule '%s' is not in '%s:%s:%s'rdrz-sz--sourcez-dz
--destination)r;r<i����i����i����)r@r
rArD�create_zone_base_by_chainrBZis_chain_builtinrr	r�ALREADY_ENABLED�NOT_ENABLEDr�sortedr?rrSrlr8Z
build_rulerarX�add_fail)rrVr.r/r0r2r3r%rL�backendr1rUrerWZ	positions�jZ	args_list�_argsrrrrQ�sZ




(

zFirewallDirect._rulecCs�|j||�|j|||�||f}|rV||jkr�||j|kr�ttjd|||f��n.||jksn||j|kr�ttjd|||f��|jj|�}|j	||j
|||��|j|||�|j|j|||�dS)Nz chain '%s' already is in '%s:%s'zchain '%s' is not in '%s:%s')
r@rErr	rrorpr
rBZ	add_rulesZbuild_chain_rulesrHrr)rrGr.r/r0r%r-rsrrrrLs$

zFirewallDirect._chainc
Cs�|j|�t|�}|rD||jkrp||j|krpttjd||f��n,||jks\||j|krpttjd||f��|jj|�}|r�|j	|�|dkr�|j
|�\}}|r�|r�|jjj|||�|}	n
|j
|�}	|j||	�|j|||�|j|j|||�dS)Nzpassthrough '%s', '%s'r;r<)r;r<)r=rarr	rrorpr
rBZcheck_passthroughZpassthrough_parse_table_chainrDrnZreverse_passthroughr8r^rr)
rrVr.r3r%Z
tuple_argsrsr/r0rurrrr_'s0




zFirewallDirect._passthrough)N)N)N)N)N)N)N)N))�__name__�
__module__�__qualname__rrrrrrrr!r&r4r5r"r=r@rErHr6rMr'rNrr8rRr*rTrrXr]r^r9r`r+r rbrlrQrLr_rrrrr&sL	

'	

	




jN)�__all__Zfirewall.fw_typesrZ
firewall.corerrZfirewall.core.fw_transactionrZfirewall.core.loggerrZfirewallrZfirewall.errorsr	�objectrrrrr�<module>s__pycache__/rich.cpython-36.opt-1.pyc000064400000050640151731527040013300 0ustar003

��g8��@s�dddddddddd	d
ddd
ddddgZddlmZddlmZddlmZddlmZddlm	Z	Gdd�de
�ZGdd�de
�ZGdd�de
�Z
Gdd�de
�ZGdd�de�ZGdd�de
�ZGdd�de
�ZGdd�de
�ZGd d�de
�ZGd!d	�d	e
�ZGd"d
�d
e
�ZGd#d�de
�ZGd$d�de
�ZGd%d
�d
e
�ZGd&d�de�ZGd'd�de
�Zd(d)d/d1d+�ZGd,d�de
�ZGd-d�de
�Zd.S)2�Rich_Source�Rich_Destination�Rich_Service�	Rich_Port�
Rich_Protocol�Rich_Masquerade�Rich_IcmpBlock�
Rich_IcmpType�Rich_SourcePort�Rich_ForwardPort�Rich_Log�
Rich_Audit�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�
Rich_Limit�	Rich_Rule�)�	functions)�check_ipset_name)�REJECT_TYPES)�errors)�
FirewallErrorc@seZdZddd�Zdd�ZdS)rFcCs�||_|jdkrd|_||_|jdks0|jdkr8d|_n|jdk	rN|jj�|_||_|jdkrdd|_||_|jdkr�|jdkr�|jdkr�ttjd��dS)N�zno address, mac and ipset)�addr�mac�upper�ipset�invertrr�INVALID_RULE)�selfrrrr�r!�/usr/lib/python3.6/rich.py�__init__$s


zRich_Source.__init__cCsjd|jrdnd}|jdk	r*|d|jS|jdk	rB|d|jS|jdk	rZ|d|jSttjd��dS)Nz	source%s z NOTrzaddress="%s"zmac="%s"z
ipset="%s"zno address, mac and ipset)rrrrrrr)r �retr!r!r"�__str__5s


zRich_Source.__str__N)F)�__name__�
__module__�__qualname__r#r%r!r!r!r"r#s
c@seZdZddd�Zdd�ZdS)rFcCsV||_|jdkrd|_||_|jdkr,d|_||_|jdkrR|jdkrRttjd��dS)Nrzno address and ipset)rrrrrr)r rrrr!r!r"r#Bs

zRich_Destination.__init__cCsRd|jrdnd}|jdk	r*|d|jS|jdk	rB|d|jSttjd��dS)Nzdestination%s z NOTrzaddress="%s"z
ipset="%s"zno address and ipset)rrrrrr)r r$r!r!r"r%Ns

zRich_Destination.__str__N)F)r&r'r(r#r%r!r!r!r"rAs
c@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)�name)r r)r!r!r"r#YszRich_Service.__init__cCs
d|jS)Nzservice name="%s")r))r r!r!r"r%\szRich_Service.__str__N)r&r'r(r#r%r!r!r!r"rXsc@seZdZdd�Zdd�ZdS)rcCs||_||_dS)N)�port�protocol)r r*r+r!r!r"r#`szRich_Port.__init__cCsd|j|jfS)Nzport port="%s" protocol="%s")r*r+)r r!r!r"r%dszRich_Port.__str__N)r&r'r(r#r%r!r!r!r"r_sc@seZdZdd�ZdS)r	cCsd|j|jfS)Nz#source-port port="%s" protocol="%s")r*r+)r r!r!r"r%hszRich_SourcePort.__str__N)r&r'r(r%r!r!r!r"r	gsc@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)�value)r r,r!r!r"r#mszRich_Protocol.__init__cCs
d|jS)Nzprotocol value="%s")r,)r r!r!r"r%pszRich_Protocol.__str__N)r&r'r(r#r%r!r!r!r"rlsc@seZdZdd�Zdd�ZdS)rcCsdS)Nr!)r r!r!r"r#tszRich_Masquerade.__init__cCsdS)N�
masquerader!)r r!r!r"r%wszRich_Masquerade.__str__N)r&r'r(r#r%r!r!r!r"rssc@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)r))r r)r!r!r"r#{szRich_IcmpBlock.__init__cCs
d|jS)Nzicmp-block name="%s")r))r r!r!r"r%~szRich_IcmpBlock.__str__N)r&r'r(r#r%r!r!r!r"rzsc@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)r))r r)r!r!r"r#�szRich_IcmpType.__init__cCs
d|jS)Nzicmp-type name="%s")r))r r!r!r"r%�szRich_IcmpType.__str__N)r&r'r(r#r%r!r!r!r"r�sc@seZdZdd�Zdd�ZdS)r
cCs<||_||_||_||_|jdkr(d|_|jdkr8d|_dS)Nr)r*r+�to_port�
to_address)r r*r+r.r/r!r!r"r#�s

zRich_ForwardPort.__init__cCs<d|j|j|jdkrd|jnd|jdkr4d|jndfS)Nz(forward-port port="%s" protocol="%s"%s%srz
 to-port="%s"z
 to-addr="%s")r*r+r.r/)r r!r!r"r%�szRich_ForwardPort.__str__N)r&r'r(r#r%r!r!r!r"r
�sc@seZdZddd�Zdd�ZdS)rNcCs||_||_||_dS)N)�prefix�level�limit)r r0r1r2r!r!r"r#�szRich_Log.__init__cCs>d|jrd|jnd|jr$d|jnd|jr6d|jndfS)Nz	log%s%s%sz prefix="%s"rz level="%s"z %s)r0r1r2)r r!r!r"r%�szRich_Log.__str__)NNN)r&r'r(r#r%r!r!r!r"r�s
c@seZdZddd�Zdd�ZdS)rNcCs
||_dS)N)r2)r r2r!r!r"r#�szRich_Audit.__init__cCsd|jrd|jndS)Nzaudit%sz %sr)r2)r r!r!r"r%�szRich_Audit.__str__)N)r&r'r(r#r%r!r!r!r"r�s
c@seZdZddd�Zdd�ZdS)r
NcCs
||_dS)N)r2)r r2r!r!r"r#�szRich_Accept.__init__cCsd|jrd|jndS)Nzaccept%sz %sr)r2)r r!r!r"r%�szRich_Accept.__str__)N)r&r'r(r#r%r!r!r!r"r
�s
c@s&eZdZddd�Zdd�Zdd�ZdS)	rNcCs||_||_dS)N)�typer2)r Z_typer2r!r!r"r#�szRich_Reject.__init__cCs,d|jrd|jnd|jr$d|jndfS)Nz
reject%s%sz
 type="%s"rz %s)r3r2)r r!r!r"r%�szRich_Reject.__str__cCsT|jrP|sttjd��|dkrP|jt|krPdjt|�}ttjd|j|f��dS)Nz9When using reject type you must specify also rule family.�ipv4�ipv6z, z%Wrong reject type %s.
Use one of: %s.)r4r5)r3rrrr�join)r �familyZvalid_typesr!r!r"�check�szRich_Reject.check)NN)r&r'r(r#r%r8r!r!r!r"r�s
c@seZdZdd�ZdS)rcCsd|jrd|jndS)Nzdrop%sz %sr)r2)r r!r!r"r%�szRich_Drop.__str__N)r&r'r(r%r!r!r!r"r�sc@s&eZdZddd�Zdd�Zdd�ZdS)	rNcCs||_||_dS)N)�setr2)r Z_setr2r!r!r"r#�szRich_Mark.__init__cCsd|j|jrd|jndfS)Nz
mark set=%s%sz %sr)r9r2)r r!r!r"r%�szRich_Mark.__str__cCs�|jdk	r|j}nttjd��d|krv|jd�}t|�dkrHttj|��tj|d�shtj|d�r�ttj|��ntj|�s�ttj|��dS)Nzno value set�/�r�)r9rrZINVALID_MARK�split�lenrZcheckUINT32)r �x�splitsr!r!r"r8�s


zRich_Mark.check)N)r&r'r(r#r%r8r!r!r!r"r�s
r<�<�)�s�m�h�dc@s�eZdZddd�Zdd�Zedd��Zejdd��Zed	d
��Zejdd
��Ze	dd
��Z
dd�Ze	dd��Zdd�Z
dd�ZdS)rNcCs||_||_dS)N)r,�burst)r r,rGr!r!r"r#�szRich_Limit.__init__cCs|j�|j�dS)N)�value_parse�burst_parse)r r!r!r"r8�szRich_Limit.checkcCs|jS)N)�_value)r r!r!r"r,�szRich_Limit.valuecCsf|dkrd|_dSy|j|�\}}Wntk
r<|}YnX|�d|��}t|dd�|krb||_dS)Nr:rJ)rJ�_value_parser�getattr)r r,�rate�duration�vr!r!r"r,�s
cCs|jS)N)�_burst)r r!r!r"rGszRich_Limit.burstcCs\|dkrd|_dSy|j|�}Wntk
r8|}Yn
Xt|�}t|dd�|krX||_dS)NrP)rP�_burst_parser�strrL)r rG�br!r!r"rGs
cCs�d}d|kr|jd�}|s(t|�dkr4ttj|��|\}}yt|�}Wnttj|��YnX|dkrv|dd�}|dks�|dkr�ttj|��dt||d
kr�ttjd|f��|dkr�|dkr�ttjd|f��||fS)Nr:r;�second�minute�hour�dayr<rCrDrErFi'rz%s too fastz%s too slow)rTrUrVrW)rCrDrErF)r=r>rr�
INVALID_LIMIT�int�DURATION_TO_MULT)r,r@rMrNr!r!r"rKs&
zRich_Limit._value_parsecCs|j|j�S)N)rKrJ)r r!r!r"rH:szRich_Limit.value_parsec	CsR|dkrdSyt|�}Wnttj|��YnX|dksB|dkrNttj|��|S)Nr<i���)rYrrrX)rGrSr!r!r"rQ=szRich_Limit._burst_parsecCs|j|j�S)N)rQrP)r r!r!r"rIKszRich_Limit.burst_parsecCs,d|j�d�}|jdk	r(|d|j��7}|S)Nz
limit value="�"z burst=)rJrP)r rCr!r!r"r%Ns
zRich_Limit.__str__)N)r&r'r(r#r8�propertyr,�setterrG�staticmethodrKrHrQrIr%r!r!r!r"r�s
c@s>eZdZdZdZddd�Zdd�Zd	d
�Zdd�Zd
d�Z	dS)ri�i�NrcCsV|dk	rt|�|_nd|_||_d|_d|_d|_d|_d|_d|_|rR|j	|�dS)N)
rRr7�priority�source�destination�element�log�audit�action�_import_from_string)r r7�rule_strr_r!r!r"r#XszRich_Rule.__init__cCs�g}x|tj|�D]n}d|krp|jd�}t|�dksF|dsF|drVttjd|��|j|d|dd��q|jd|i�qW|jddi�|S)	z Lexical analysis �=r;rr<zinternal error in _lexer(): %s)�	attr_name�
attr_valuerb�EOL)rZ	splitArgsr=r>rrr�append)r rg�tokens�r�attrr!r!r"�_lexeris
 
zRich_Rule._lexercCs�|sttjd��tj|�}d|_d|_d|_d|_d|_	d|_
d|_d|_|j
|�}|rv|djd�dkrvttjd��i}g}d}�x`||jd�dko�|dgk�s�||jd�}||jd�}||jd�}|�r�|dHk�r�ttjd|���n�|dIk�r�|dk�r|j�rttjd+��n�|dk�r<|j�r<ttjd,��n�|dJk�rf|j	�rfttjd-||j	f��nh|d"k�r�|j
�r�ttjd.��nH|d#k�r�|j�r�ttjd/��n(|dKk�r�|j�r�ttjd0||jf��nttjd1|��t|�dk�r�|t|�d2nd3}	|	d3k�r�|�r`|�r`|d	k�r2ttjd4��n,|dk�rJttjd5��nttjd6||f��n*d|k�r�ttjd7||f��n
|jd��nL|	dk�rD|d	k�r�|dLk�r�ttjd:|��||_n||dk�ryt|�|_Wn&tk
�rttjd;|��YnXn:|�r6|dk�rd<}
nd=||f}
ttj|
��n
|j|��n�|	dk�r�|dMk�rb|||<nV|dNk�rvd>|d
<nBt|jd
�|jd�|jd�|jd
d?��|_|j�|j�|d2}�n|	dk�r,|dOk�r�|||<nN|dPk�r�d>|d
<n:t|jd
�|jd�|jd
d?��|_|j�|j�|d2}�n�|	dk�rd|dk�rTt|�|_	|j�nttjd@���nv|	dk�r�|dk�r�t|�|_	|j�nttjdA���n>|	dk�r�|dQk�r�|||<n0t|jd�|jd��|_	|j�|j�|d2}�n�|	dk�r&|dk�rt|�|_	|j�nttjdB���n�|	dk�r^|dk�rNt|�|_	|j�nttjdC���n||	dk�r�t�|_	|j�|j�|d2}�nN|	d k�r�|dRk�r�|||<n@t|jd�|jd�|jd�|jd��|_	|j�|j�|d2}�n�|	d!k�r@|dSk�r|||<n0t|jd�|jd��|_	|j�|j�|d2}�n�|	d"k�r�|dTk�r^|||<nN|d(k�rt|jd(�n8t |jd�|jd�|jd(��|_
|j�|j�|d2}�n*|	d#k�r�|d(k�r�|jd(�n(t!|jd(��|_|j�|j�|d2}�n�|	d$k�rH|d(k�r|jd(�n(t"|jd(��|_|j�|j�|d2}�n�|	d%k�r�|d(k�rh|jd(�n(t#|jd(��|_|j�|j�|d2}�nF|	d&k�r�|dk�r�|||<nF|d(k�r�|jd(�n0t$|jd�|jd(��|_|j�|j�|d2}n�|	d'k�r`|dk�r|||<nF|d(k�r.|jd(�n0t%|jd�|jd(��|_|j�|j�|d2}nz|	d(k�r�|dUk�r�||dD|��<nVdE|k�r�ttjdF��t&|dE|jdG��|d(<|jdEd�|jdGd�|j�|d2}|d2}q�W|j'�dS)VNz
empty rulerrbrk�rulerirjr_r7�addressrrrr,r*r+�to-port�to-addrr)r0r1r3r9rGzbad attribute '%s'r`ra�service�
icmp-block�	icmp-typer-�forward-port�source-portrcrd�accept�drop�reject�markr2�not�NOTzmore than one 'source' elementz#more than one 'destination' elementzFmore than one element. There cannot be both '%s' and '%s' in one rule.zmore than one 'log' elementzmore than one 'audit' elementzOmore than one 'action' element. There cannot be both '%s' and '%s' in one rule.zunknown element %sr<rz0'family' outside of rule. Use 'rule family=...'.z4'priority' outside of rule. Use 'rule priority=...'.z:'%s' outside of any element. Use 'rule <element> %s= ...'.z,'%s' outside of rule. Use 'rule ... %s ...'.r4r5zH'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead.z(invalid 'priority' attribute value '%s'.zdwrong 'protocol' usage. Use either 'rule protocol value=...' or  'rule [forward-]port protocol=...'.zDattribute '%s' outside of any element. Use 'rule <element> %s= ...'.TFzinvalid 'protocol' elementzinvalid 'service' elementzinvalid 'icmp-block' elementzinvalid 'icmp-type' elementzlimit.zlimit.valuezinvalid 'limit' elementzlimit.burst)r_r7rrrrrr,r*r+rsrtr)r0r1r3r9rG)rqr`rar+rur*rvrwr-rxryrcrdrzr{r|r}r2r~rrk)r+rur*rvrwr-rxry)rzr{r|r})r4r5)rrrrr)r~r)rrrr)r~r)r*r+)r*r+rsrt)r*r+)r0r1)r,rG)(rrrrZstripNonPrintableCharactersr_r7r`rarbrcrdrerp�getr>rlrY�
ValueError�INVALID_PRIORITYr�pop�clearrrrrrrrr
r	rrr
rrrrr8)r rgrmZattrsZin_elements�indexrbrirjZ
in_elementZerr_msgr!r!r"rfzs�

""













*




"






















(






 




















zRich_Rule._import_from_stringc	Cs`|jdk	r"|jd kr"ttj|j��|jdkrn|jdk	rB|jjdk	sL|jdk	rVttj��t|j	�t
krnttj��|j|jks�|j|j
kr�ttjd|j|j
f��|j	dko�|jdks�|jdk	o�|jdk�r
|jdkr�ttjd��|jdko�|jdko�|jdk�r
ttjd��t|j	�tt
tgk�rP|jdk�rP|jdk�rP|jdk�rPttjd��|jdk	�rj|jjdk	�r�|jdk�r�ttj��|jjdk	�r�ttjd��|jjdk	�r�ttjd	��tj|j|jj��sjttjt|jj���n�|jjdk	�r,|jjdk	�rttjd
��tj|jj��sjttjt|jj���n>|jjdk	�r^t|jj��sjttjt|jj���nttjd��|jdk	�r|jjdk	�r�|jdk�r�ttj��|jjdk	�r�ttjd	��tj|j|jj��sttjt|jj���n>|jjdk	�rt|jj��sttjt|jj���nttjd��t|j	�t k�rd|j	j!dk�sLt"|j	j!�d
k�r`ttj#t|j	j!����n�t|j	�t$k�r�tj%|j	j&��s�ttj'|j	j&��|j	j(d!k�r`ttj)|j	j(���n�t|j	�t*k�r�tj+|j	j,��s`ttj)|j	j,���nvt|j	�tk�r<|jdk	�rttjd��|jdk	�r`|jjdk	�r`ttjd���n$t|j	�tk�r�|j	j!dk�slt"|j	j!�d
k�r�ttj-t|j	j!���|j�r`ttjd���n�t|j	�t.k�r�|j	j!dk�s�t"|j	j!�d
k�r`ttj-t|j	j!����n�t|j	�t
k�r�tj%|j	j&��sttj'|j	j&��|j	j(d"k�r.ttj)|j	j(��|j	j/dk�rZ|j	j0dk�rZttj'|j	j/��|j	j/dk�r�tj%|j	j/��r�ttj'|j	j/��|j	j0dk�r�tj1|j|j	j0��r�ttj|j	j0��|jdk�r�ttj��|jdk	�r`ttjd��nrt|j	�t2k�r>tj%|j	j&��sttj'|j	j&��|j	j(d#k�r`ttj)|j	j(��n"|j	dk	�r`ttjdt|j	���|jdk	�r�|jj3�r�|jj3d$k�r�ttj4|jj3��|jj5dk	�r�|jj5j6�|jdk	�r�t|j�t7t8t9gk�r�ttj:t|j���|jj5dk	�r�|jj5j6�|jdk	�r\t|j�t8k�r(|jj6|j�nt|j�t;k�rB|jj6�|jj5dk	�r\|jj5j6�dS)%Nr4r5z/'priority' attribute must be between %d and %d.rzno element, no actionz%no element, no source, no destinationzno action, no log, no auditzaddress and maczaddress and ipsetz
mac and ipsetzinvalid sourcezinvalid destinationr<�tcp�udp�sctp�dccpzmasquerade and actionzmasquerade and mac sourcezicmp-block and actionrzforward-port and actionzUnknown element %s�emerg�alert�crit�error�warning�notice�info�debug)r4r5)r�r�r�r�)r�r�r�r�)r�r�r�r�)r�r�r�r�r�r�r�r�)<r7rrZINVALID_FAMILYr`rraZMISSING_FAMILYr3rbr
r_�priority_min�priority_maxr�rcrerrrrdrrrZ
check_addressZINVALID_ADDRrRZ	check_macZINVALID_MACrZ
INVALID_IPSETZINVALID_DESTINATIONrr)r>ZINVALID_SERVICErZ
check_portr*ZINVALID_PORTr+ZINVALID_PROTOCOLrZ
checkProtocolr,ZINVALID_ICMPTYPErr.r/Zcheck_single_addressr	r1ZINVALID_LOG_LEVELr2r8r
rrZINVALID_AUDIT_TYPEr)r r!r!r"r8hs�




 
 



   


zRich_Rule.checkcCs�d}|jr|d|j7}|jr,|d|j7}|jr@|d|j7}|jrT|d|j7}|jrh|d|j7}|jr||d|j7}|jr�|d|j7}|jr�|d|j7}tj	r�tj
|�S|S)Nrqz priority="%d"z family="%s"z %s)r_r7r`rarbrcrdrerZPY2Zu2b)r r$r!r!r"r%s$zRich_Rule.__str__i���)NNr)
r&r'r(r�r�r#rprfr8r%r!r!r!r"rTs
o-Nii�i�Q)�__all__ZfirewallrZfirewall.core.ipsetrZfirewall.core.baserrZfirewall.errorsr�objectrrrrr	rrrrr
rrr
rrrrZrrr!r!r!r"�<module>s@
d__pycache__/modules.cpython-36.pyc000064400000005500151731527050013060 0ustar003

��g��@sBdZdgZddlmZddlmZddlmZGdd�de�Z	dS)zmodules backend�modules�)�runProg)�log)�COMMANDSc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCstd|_td|_dS)NZmodprobeZrmmod)r�
_load_command�_unload_command)�self�r	�/usr/lib/python3.6/modules.py�__init__s
zmodules.__init__cCs
d|jS)Nz%s)�	__class__)rr	r	r
�__repr__$szmodules.__repr__cCs�g}i}y�tdd��p}xh|D]`}|s&P|j�}|j�}|j|d�|ddkrp|djd�dd	�||d<qg||d<qWWdQRXWntk
r�YnX||fS)
z6 get all loaded kernel modules and their dependencies z
/proc/modules�rr��-�,N����)�open�strip�split�append�FileNotFoundError)r�mods�deps�f�lineZsplitsr	r	r
�loaded_modules's 
 zmodules.loaded_modulescCs"tjd|j|j|�t|j|g�S)Nz	%s: %s %s)r�debug2rrr)r�moduler	r	r
�load_module<szmodules.load_modulecCs"tjd|j|j|�t|j|g�S)Nz	%s: %s %s)rrrrr)rrr	r	r
�
unload_module@szmodules.unload_modulecCsT||krdSx0||D]$}|j|||�||kr|j|�qW||krP|j|�dS)z  get all dependants of a module N)�get_depsr)rrr�ret�modr	r	r
r"Dszmodules.get_depscCs�g}|j�\}}|jd||�x*dD]"}||kr$|j|�|jd|�q$Wx^|D]V}|dks�|jd�s�|jd	�s�|jd
�s�|jd�s�|jd�s�|jd
�rP|j|||�qPW|S)z) get all loaded firewall-related modules Znf_conntrack�nf_conntrack_ipv4�nf_conntrack_ipv6r�	ip_tables�
ip6_tables�ebtablesZiptable_Z	ip6table_Znf_Zxt_Zipt_Zip6t_)r%r&r)r'r(r))rr"�remove�insert�
startswith)rrZmods2rZbad_bad_moduler$r	r	r
�get_firewall_modulesOs


zmodules.get_firewall_modulescCs>x8|j�D],}|j|�\}}|dkr
tjd||f�q
WdS)z% unload all firewall-related modules rz Failed to unload module '%s': %sN)r-r!rZdebug1)rrZstatusr#r	r	r
�unload_firewall_modulesdszmodules.unload_firewall_modulesN)�__name__�
__module__�__qualname__rr
rr r!r"r-r.r	r	r	r
rsN)
�__doc__�__all__Zfirewall.core.progrZfirewall.core.loggerrZfirewall.configr�objectrr	r	r	r
�<module>s
__pycache__/fw_transaction.cpython-36.opt-1.pyc000064400000011650151731527050015373 0ustar003

��g��@sJdZdgZddlZddlmZddlmZddlmZGdd�de	�Z
dS)z!Transaction classes for firewalld�FirewallTransaction�N)�log)�errors)�
FirewallErrorc@s�eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd#S)$rcCs(||_i|_g|_g|_g|_g|_dS)N)�fw�rules�	pre_funcs�
post_funcs�
fail_funcs�modules)�selfr�r
�$/usr/lib/python3.6/fw_transaction.py�__init__!szFirewallTransaction.__init__cCs2|jj�|jdd�=|jdd�=|jdd�=dS)N)r�clearrr	r
)rr
r
rr)s
zFirewallTransaction.clearcCs|jj|jg�j|�dS)N)r�
setdefault�name�append)r�backend�ruler
r
r�add_rule/szFirewallTransaction.add_rulecCsx|D]}|j||�qWdS)N)r)rrrrr
r
r�	add_rules2s
zFirewallTransaction.add_rulescCs|j|jko||j|jkS)N)rr)rrrr
r
r�
query_rule6szFirewallTransaction.query_rulecCs2|j|jkr.||j|jkr.|j|jj|�dS)N)rr�remove)rrrr
r
r�remove_rule9szFirewallTransaction.remove_rulecGs|jj||f�dS)N)rr)r�func�argsr
r
r�add_pre=szFirewallTransaction.add_precGs|jj||f�dS)N)r	r)rrrr
r
r�add_post@szFirewallTransaction.add_postcGs|jj||f�dS)N)r
r)rrrr
r
r�add_failCszFirewallTransaction.add_failcCs||jkr|jj|�dS)N)rr)r�moduler
r
r�
add_moduleFs
zFirewallTransaction.add_modulecCs||jkr|jj|�dS)N)rr)rr r
r
r�
remove_moduleJs
z!FirewallTransaction.remove_modulecCsx|D]}|j|�qWdS)N)r!)rrr r
r
r�add_modulesNs
zFirewallTransaction.add_modulescCsx|D]}|j|�qWdS)N)r")rrr r
r
r�remove_modulesRs
z"FirewallTransaction.remove_modulescCs�tjdt|�|df�i}|sjxp|jD]<}x6t|j|�D]$}|j|g�j|jj|�j	|��q<Wq(Wn(x&|jD]}|j|g�j
|j|�qrW||jfS)Nz%s.prepare(%s, %s)z...)r�debug4�typer�reversedrrr�get_backend_by_name�reverse_rule�extendr)r�enabler�backend_namerr
r
r�prepareVszFirewallTransaction.preparecCstjdt|�|f�|j|�\}}|j�d}d}g}xp|D]h}y|jj|||�WnBtk
r�}z&d}|}tjt	j
��tj|�WYdd}~Xq>X|j|�q>W|s�|jj
||�}	|	r�|	\}
}|
r�tj|�|�ri}xH|D]@}g||<x2t||�D]"}||j|jj|�j|���qWq�Wxb|D]Z}y|jj|||�Wn<tk
�r�}ztjt	j
��tj|�WYdd}~XnX�q0Wxh|jD]^\}
}y|
|�WnFtk
�r�}z(tjt	j
��tjd|
||f�WYdd}~XnX�q�Wttj|��|j�dS)Nz%s.execute(%s)F�Tz#Calling fail func %s(%s) failed: %s)rr%r&r-�prerr�	Exception�debug1�	traceback�
format_exc�errorrZhandle_modulesr'r(r)r
rrZCOMMAND_FAILED�post)rr+rrr4ZerrorMsg�doner,�msgZ
module_returnZstatusZ
undo_rulesrrrr
r
r�executefsV



"&zFirewallTransaction.executecCs|tjdt|��xd|jD]Z\}}y||�Wqtk
rr}z(tjtj��tjd|||f�WYdd}~XqXqWdS)Nz%s.pre()z"Calling pre func %s(%s) failed: %s)	rr%r&rr0r1r2r3r4)rrrr7r
r
rr/�szFirewallTransaction.precCs|tjdt|��xd|jD]Z\}}y||�Wqtk
rr}z(tjtj��tjd|||f�WYdd}~XqXqWdS)Nz	%s.post()z#Calling post func %s(%s) failed: %s)	rr%r&r	r0r1r2r3r4)rrrr7r
r
rr5�szFirewallTransaction.postN)�__name__�
__module__�__qualname__rrrrrrrrrr!r"r#r$r-r8r/r5r
r
r
rr s"@)�__doc__�__all__r2Zfirewall.core.loggerrZfirewallrZfirewall.errorsr�objectrr
r
r
r�<module>s__pycache__/fw_transaction.cpython-36.pyc000064400000011650151731527050014434 0ustar003

��g��@sJdZdgZddlZddlmZddlmZddlmZGdd�de	�Z
dS)z!Transaction classes for firewalld�FirewallTransaction�N)�log)�errors)�
FirewallErrorc@s�eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd#S)$rcCs(||_i|_g|_g|_g|_g|_dS)N)�fw�rules�	pre_funcs�
post_funcs�
fail_funcs�modules)�selfr�r
�$/usr/lib/python3.6/fw_transaction.py�__init__!szFirewallTransaction.__init__cCs2|jj�|jdd�=|jdd�=|jdd�=dS)N)r�clearrr	r
)rr
r
rr)s
zFirewallTransaction.clearcCs|jj|jg�j|�dS)N)r�
setdefault�name�append)r�backend�ruler
r
r�add_rule/szFirewallTransaction.add_rulecCsx|D]}|j||�qWdS)N)r)rrrrr
r
r�	add_rules2s
zFirewallTransaction.add_rulescCs|j|jko||j|jkS)N)rr)rrrr
r
r�
query_rule6szFirewallTransaction.query_rulecCs2|j|jkr.||j|jkr.|j|jj|�dS)N)rr�remove)rrrr
r
r�remove_rule9szFirewallTransaction.remove_rulecGs|jj||f�dS)N)rr)r�func�argsr
r
r�add_pre=szFirewallTransaction.add_precGs|jj||f�dS)N)r	r)rrrr
r
r�add_post@szFirewallTransaction.add_postcGs|jj||f�dS)N)r
r)rrrr
r
r�add_failCszFirewallTransaction.add_failcCs||jkr|jj|�dS)N)rr)r�moduler
r
r�
add_moduleFs
zFirewallTransaction.add_modulecCs||jkr|jj|�dS)N)rr)rr r
r
r�
remove_moduleJs
z!FirewallTransaction.remove_modulecCsx|D]}|j|�qWdS)N)r!)rrr r
r
r�add_modulesNs
zFirewallTransaction.add_modulescCsx|D]}|j|�qWdS)N)r")rrr r
r
r�remove_modulesRs
z"FirewallTransaction.remove_modulescCs�tjdt|�|df�i}|sjxp|jD]<}x6t|j|�D]$}|j|g�j|jj|�j	|��q<Wq(Wn(x&|jD]}|j|g�j
|j|�qrW||jfS)Nz%s.prepare(%s, %s)z...)r�debug4�typer�reversedrrr�get_backend_by_name�reverse_rule�extendr)r�enabler�backend_namerr
r
r�prepareVszFirewallTransaction.preparecCstjdt|�|f�|j|�\}}|j�d}d}g}xp|D]h}y|jj|||�WnBtk
r�}z&d}|}tjt	j
��tj|�WYdd}~Xq>X|j|�q>W|s�|jj
||�}	|	r�|	\}
}|
r�tj|�|�ri}xH|D]@}g||<x2t||�D]"}||j|jj|�j|���qWq�Wxb|D]Z}y|jj|||�Wn<tk
�r�}ztjt	j
��tj|�WYdd}~XnX�q0Wxh|jD]^\}
}y|
|�WnFtk
�r�}z(tjt	j
��tjd|
||f�WYdd}~XnX�q�Wttj|��|j�dS)Nz%s.execute(%s)F�Tz#Calling fail func %s(%s) failed: %s)rr%r&r-�prerr�	Exception�debug1�	traceback�
format_exc�errorrZhandle_modulesr'r(r)r
rrZCOMMAND_FAILED�post)rr+rrr4ZerrorMsg�doner,�msgZ
module_returnZstatusZ
undo_rulesrrrr
r
r�executefsV



"&zFirewallTransaction.executecCs|tjdt|��xd|jD]Z\}}y||�Wqtk
rr}z(tjtj��tjd|||f�WYdd}~XqXqWdS)Nz%s.pre()z"Calling pre func %s(%s) failed: %s)	rr%r&rr0r1r2r3r4)rrrr7r
r
rr/�szFirewallTransaction.precCs|tjdt|��xd|jD]Z\}}y||�Wqtk
rr}z(tjtj��tjd|||f�WYdd}~XqXqWdS)Nz	%s.post()z#Calling post func %s(%s) failed: %s)	rr%r&r	r0r1r2r3r4)rrrr7r
r
rr5�szFirewallTransaction.postN)�__name__�
__module__�__qualname__rrrrrrrrrr!r"r#r$r-r8r/r5r
r
r
rr s"@)�__doc__�__all__r2Zfirewall.core.loggerrZfirewallrZfirewall.errorsr�objectrr
r
r
r�<module>s__pycache__/nftables.cpython-36.opt-1.pyc000064400000130376151731527050014157 0ustar003

��g��%@slddlmZddlZddlZddlZddlmZddlmZm	Z	m
Z
mZmZddl
mZmZmZmZmZmZmZddlmZmZmZmZmZmZmZddlmZdZed	d
Z dZ!dZ"id
ddCe"fiddDe"fdde"fd�dde"fdde"fdde"fdde"fd�d�Z#dEdd�Z$e$ddd�e$dd�e$dd�e$dd�e$ddd�e$ddd �e$ddd�e$dd!d"�e$ddd#�e$ddd"�e$dd$d"�e$ddd%�e$dd!d�e$ddd&�e$ddd�e$dd$�e$ddd'�e$ddd(�e$ddd)�e$dd!�e$dd$d"�e$dd*�e$dd+�e$dd,�e$ddd-�e$dd.�e$dd/�e$dd0�e$dd!d'�e$ddd1�e$dd!d)�e$ddd2�e$dd.d"�e$dd.d�d3�"e$d4dd'�e$d4d$d�e$d4dd)�e$d4dd"�e$d4d�e$d4d�e$d4d�e$d4dd-�e$d4d5�e$d4d6�e$d4d7�e$d4d8�e$d4d9�e$d4d:�e$d4dd�e$d4d;�e$d4d$�e$d4dd�e$d4d<�e$d4dd&�e$d4d=�e$d4d>�e$d4d.�e$d4d.d"�e$d4d.d�e$d4d$d"�e$d4d$d)�d?�d@�Z%GdAdB�dBe&�Z'dS)F�)�absolute_importN)�log)�	check_mac�getPortRange�normalizeIP6�check_single_address�
check_address)�
FirewallError�
UNKNOWN_ERROR�INVALID_RULE�INVALID_ICMPTYPE�INVALID_TYPE�
INVALID_ENTRY�INVALID_PORT)�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�Rich_Masquerade�Rich_ForwardPort�Rich_IcmpBlock)�NftablesZ	firewalld�_Zpolicy_dropZpolicy_�
�
PREROUTING�
prerouting��dZpostrouting)r�POSTROUTING�input�forward�output)r�INPUT�FORWARD�OUTPUT)�raw�mangle�nat�filtercCsHdd|dd�id|d�ig}|dk	rD|jdd|dd�id|d�i�|S)N�match�payload�type)�protocol�fieldz==)�left�op�right�code)�append)r,r+r1�	fragments�r4�/usr/lib/python3.6/nftables.py�_icmp_types_fragmentsSsr6�icmpzdestination-unreachable�
z
echo-replyzecho-request���redirect��zparameter-problem�����zrouter-advertisementzrouter-solicitationz
source-quench�z
time-exceededztimestamp-replyztimestamp-request��)"zcommunication-prohibitedzdestination-unreachablez
echo-replyzecho-requestzfragmentation-neededzhost-precedence-violationzhost-prohibitedz
host-redirectzhost-unknownzhost-unreachablez
ip-header-badznetwork-prohibitedznetwork-redirectznetwork-unknownznetwork-unreachablezparameter-problemzport-unreachablezprecedence-cutoffzprotocol-unreachabler;zrequired-option-missingzrouter-advertisementzrouter-solicitationz
source-quenchzsource-route-failedz
time-exceededztimestamp-replyztimestamp-requestztos-host-redirectztos-host-unreachableztos-network-redirectztos-network-unreachablezttl-zero-during-reassemblyzttl-zero-during-transit�icmpv6zmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportznd-neighbor-advertznd-neighbor-solicitzpacket-too-bigznd-redirectznd-router-advertznd-router-solicit)zaddress-unreachablez
bad-headerzbeyond-scopezcommunication-prohibitedzdestination-unreachablez
echo-replyzecho-requestz
failed-policyzmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportzneighbour-advertisementzneighbour-solicitationzno-routezpacket-too-bigzparameter-problemzport-unreachabler;zreject-routezrouter-advertisementzrouter-solicitationz
time-exceededzttl-zero-during-reassemblyzttl-zero-during-transitzunknown-header-typezunknown-option)�ipv4�ipv6c@s`eZdZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Z	dd
�Z
dd�Zd�dd�Zdd�Z
dd�Zdd�Zdd�Zd�dd�Zdd�Zd�d d!�Zd"d#�Zd�d%d&�Zd�d(d)�Zd�d*d+�Zd�d,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Z d>d?�Z!d@dA�Z"dBdC�Z#dDdE�Z$dFdG�Z%dHdI�Z&d�dJdK�Z'dLdM�Z(dNdO�Z)dPdQ�Z*dRdS�Z+d�dTdU�Z,d�dVdW�Z-d�dXdY�Z.dZd[�Z/d�d\d]�Z0d�d^d_�Z1d�d`da�Z2d�dbdc�Z3d�ddde�Z4dfdg�Z5d�dhdi�Z6djdk�Z7d�dldm�Z8dndo�Z9dpdq�Z:drds�Z;dtdu�Z<d�dvdw�Z=d�dxdy�Z>dzd{�Z?d�d|d}�Z@d~d�ZAd�d��ZBd�d��ZCd�d��ZDd�d��ZEd�d��ZFd�d��ZGd�d�d��ZHdS)��nftablesTcCsb||_d|_g|_i|_i|_i|_i|_i|_gggd�|_t	�|_
|j
jd�|j
jd�dS)NT)�inet�ip�ip6)
�_fwZrestore_command_existsZavailable_tables�rule_to_handle�rule_ref_count�rich_rule_priority_counts�policy_priority_counts�zone_source_index_cache�created_tablesrrIZset_echo_outputZset_handle_output)�self�fwr4r4r5�__init__�sznftables.__init__cCs�xdD]}||krPqWd||dkr`||ddd||dddf}||dd=n(d||dkr�d}||dd=ndS||dd	}|r�|dkr�||kr�|||kr�||j|�n�|dk�r�||kr�g||<|�r(|||k�r||j|�||jd
d�d�||j|�}n|jj�r8d
}nt||�}||}||=|d
k�rf||d<n |d8}||d<||ddd<dS)N�add�insert�deletez%%ZONE_SOURCE%%�rule�zone�addressz%%ZONE_INTERFACE%%�familycSs|dS)Nrr4)�xr4r4r5�<lambda>�sz3nftables._run_replace_zone_source.<locals>.<lambda>)�keyrr<�index)rWrXrY)�remover2�sortrarM�_allow_zone_drifting�len)rTrZrR�verbZzone_sourcer]ra�
_verb_snippetr4r4r5�_run_replace_zone_source�sD




z!nftables._run_replace_zone_sourcecCsBd|krdtj|d�iSd|kr4dtj|d�iSttd��dS)NrXrYrWzFailed to reverse rule)�copy�deepcopyr	r
)rT�dictr4r4r5�reverse_rule�s
znftables.reverse_rulec
Cs�xdD]}||krPqW|||dk�r�||d|}||d|=t|�tkr^ttd��||dd||ddf}|dkr�||ks�|||ks�|||dkr�ttd	��|||d
8<n�||kr�i||<|||kr�d|||<d}xVt||j��D]B}||k�r"|dk�r"P||||7}||k�r|dk�rP�qW|||d
7<||}	||=|dk�r�|	|d<n |d
8}|	|d<||ddd<dS)
NrWrXrYrZz%priority must be followed by a numberr]�chainrz*nonexistent or underflow of priority countr<ra)rWrXrY)r+�intr	rr
�sorted�keys)
rTrZZpriority_counts�tokenrf�priorityrmra�prgr4r4r5�_set_rule_replace_priority�sD

 


z#nftables._set_rule_replace_prioritycCsfx`d
D]X}||krd||krtj||d�}xdD]}||kr6||=q6Wtj|dd	�}|SqWdS)NrWrXrYrZra�handle�positionT)Z	sort_keys)rWrXrY)rarurv)rirj�json�dumps)rTrZrf�rule_keyZnon_keyr4r4r5�
_get_rule_keys


znftables._get_rule_keycCsLdddddg}dddg}g}g}tj|j�}tj|j�}tj|j�}	|jj�}
�x�|D�]�}t|�tkrvtt	d|��x|D]}||kr|Pq|W||kr�tt
d|��|j|�}
|
|
k�rDtj
d|j|
|
|
�|dkr�|
|
d	7<qVnX|
|
d	k�r|
|
d	8<qVn6|
|
d	k�r,|
|
d	8<ntt	d
|
|
|
f��n|
�r\|dk�r\d	|
|
<|j|�tj|�}|
�rttd||dd��||dd<|j||d
�|j||d�|j||	�|dk�rdd|ddd|ddd|ddd|j|
d�ii}|j|�qVWdddd	iig|i}tj�dk�rVtjd|jtj|��|jj|�\}}}|dk�r�tdd|tj|�f��||_||_|	|_|
|_d}x�|D]�}|d	7}|j|�}
|
�s̐q�d|k�r�|j|
=|j|
=�q�x"|D]}||d|k�r�P�q�W||d|k�r$�q�|d||dd|j|
<�q�WdS)NrWrXrY�flush�replacez#rule must be a dictionary, rule: %szno valid verb found, rule: %sz%s: prev rule ref cnt %d, %sr<z)rule ref count bug: rule_key '%s', cnt %drZ�exprz%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r]�tablerm)r]r~rmrurIZmetainfoZjson_schema_versionr@z.%s: calling python-nftables with JSON blob: %srz'%s' failed: %s
JSON blob:
%szpython-nftablesru)rirjrPrQrRrOr+rkr	r
rrzrZdebug2�	__class__r2�listr(rtrhrNZgetDebugLogLevelZdebug3rwrxrIZjson_cmd�
ValueError)rT�rules�
log_deniedZ_valid_verbsZ_valid_add_verbsZ_deduplicated_rulesZ_executed_rulesrPrQrRrOrZrfryZ_ruleZ	json_blobZrcr!�errorrar4r4r5�	set_rules+s�







&






znftables.set_rulescCs|j|g|�dS)N�)r�)rTrZr�r4r4r5�set_rule�sznftables.set_ruleNcCs|r
|gStj�S)N)�IPTABLES_TO_NFT_HOOKrp)rTr~r4r4r5�get_available_tables�sznftables.get_available_tablescCsFg}x<dD]4}|jdd||d�ii�|jdd||d�ii�q
W|S)	NrJrKrLrWr~)r]�namerY)rJrKrL)r2)rTr~r�r]r4r4r5�_build_delete_table_rules�s


z"nftables._build_delete_table_rulescCs�i}i}xB|jd�D]4}|j|�}||jkr|j|||<|j|||<qW||_||_i|_i|_i|_x*dD]"}t|j|krp|j|j	t�qpW|j
t�S)NTrJrKrL)rJrKrL)� _build_set_policy_rules_ct_rulesrzrNrOrPrQrR�
TABLE_NAMErSrbr�)rTZsaved_rule_to_handleZsaved_rule_ref_countrZ�
policy_keyr]r4r4r5�build_flush_rules�s 


znftables.build_flush_rulesc
Cslddd�|}g}xTdD]L}|j|ddtd	d
|fddd
diiddddgid�iddigd�ii�qW|S)NrWrY)TFrr r!rZrJz%s_%sr(r)�ctr`�state�in�set�established�related)r.r/r0�accept)r]r~rmr})rr r!)r2�TABLE_NAME_POLICY)rT�enable�add_delr��hookr4r4r5r��s


z)nftables._build_set_policy_rules_ct_rulescCstg}|dkrt|jdddtd�ii�|jdjt�x>dD]6}|jdddtd	d
|fd|dtd
dd�ii�q:W|dk�r�|jdddtd�ii�|jdjt�x>dD]6}|jdddtd	d|fd|dtd
dd�ii�q�W||jd�7}nz|dk�rfx4|jd�D]&}|j|�}||jk�r|j|��qW||jt�7}t|jdk�rp|jdjt�n
t	t
d�|S)NZPANICrWr~rJ)r]r�rr!rmz%s_%sr%r(i,r<�drop)r]r~r�r+r��prio�policy�DROPrr rT�ACCEPTFznot implemented)rr!i���)rr r!)r2r�rS�NFT_HOOK_OFFSETr�rzrNr�rbr	r
)rTr�r�r�rZr�r4r4r5�build_set_policy_rules�sH













znftables.build_set_policy_rulescCs<t�}x,|r|gntj�D]}|jt|j��qWt|�S)N)r��ICMP_TYPES_FRAGMENTSrp�updater�)rT�ipvZ	supportedZ_ipvr4r4r5�supported_icmp_types�sznftables.supported_icmp_typescCs>g}x4dD],}|jdd|td�ii�|j|jt�q
W|S)NrJrKrLrWr~)r]r�)rJrKrL)r2r�rS)rTZdefault_tablesr]r4r4r5�build_default_tabless

znftables.build_default_tables�offcCs�g}x�tdj�D]�}|jdddtd|ddtd|dtd|d	d
�ii�xz|jjrlddd
dgndd
dgD]X}|jdddtd||fd�ii�|jdddtd|ddd||fiigd�ii�qvWqWx�d?D]�}x�tdj�D]�}|jdd|td|ddtd|dtd|d	d
�ii�x~|jj�rJddd
dgndd
dgD]Z}|jdd|td||fd�ii�|jdd|td|ddd||fiigd�ii��qTWq�Wq�WxVtdj�D]F}|jdddtd|ddtd|dtd|d	d
�ii��q�W|jdddtddddddiid d!d"d#gid$�id%digd�ii�|jdddtdddddd&iid d'd$�id%digd�ii�|jdddtdddd(dd)iid*d+d$�id%digd�ii�x~|jj�r�ddd
dgndd
dgD]Z}|jdddtd,d|fd�ii�|jdddtddddd,d|fiigd�ii��q�W|d-k�r�|jdddtddddddiid d!d.gid$�i|j|�d/d0d1iigd�ii�|jdddtddddddiid d!d.gid$�id2digd�ii�|d-k�r$|jdddtdd|j|�d/d0d3iigd�ii�|jdddtddd4d5d6d7�igd�ii�|jdddtdd8ddddiid d!d"d#gid$�id%digd�ii�|jdddtdd8dddd&iid d'd$�id%digd�ii�|jdddtdd8dd(dd)iid*d+d$�id%digd�ii�xbd@D]Z}|jdddtd,d8|fd�ii�|jdddtdd8ddd,d8|fiigd�ii��qWx�dAD]�}xz|jj�r�dd
gnd
gD]^}|jdddtd;d8||fd�ii�|jdddtdd8ddd;d8||fiigd�ii��q�W�qvWxbdBD]Z}|jdddtd,d8|fd�ii�|jdddtdd8ddd,d8|fiigd�ii��qW|d-k�r�|jdddtdd8ddddiid d!d.gid$�i|j|�d/d0d1iigd�ii�|jdddtdd8ddddiid d!d.gid$�id2digd�ii�|d-k�r6|jdddtdd8|j|�d/d0d3iigd�ii�|jdddtdd8d4d5d6d7�igd�ii�|jdddtdd<ddddiid d!d"d#gid$�id%digd�ii�|jdddtd=dd(dd>iid*d+d$�id%digd�ii�xbdCD]Z}|jdddtd,d<|fd�ii�|jdddtdd<ddd,d<|fiigd�ii��q�WxbdDD]Z}|jdddtd,d<|fd�ii�|jdddtdd<ddd,d<|fiigd�ii��qHW|S)ENr&rWrmrJz	mangle_%sr(z%srr<)r]r~r�r+r�r��POLICIES_preZZONES_SOURCEZZONES�
POLICIES_postzmangle_%s_%s)r]r~r�rZ�jump�target)r]r~rmr}rKrLr'znat_%sz	nat_%s_%sz	filter_%sr"r)r�r`r�r�r�r�r�)r.r/r0r�Zstatus�dnat�meta�iifnamez==�lozfilter_%s_%sr�Zinvalidr�prefixzSTATE_INVALID_DROP: r�zFINAL_REJECT: �reject�icmpxzadmin-prohibited)r+r}r#�IN�OUTzfilter_%s_%s_%sr$�
filter_OUTPUT�oifname)rKrL)r�)r�r�)r�)r�)r�)r�rpr2r�rMrd�_pkttype_match_fragment)rTr�Z
default_rulesrmZdispatch_suffixr]�	directionr4r4r5�build_default_ruless�
$

(

&

.
 


&

&











&


.


&










&


&znftables.build_default_rulescCs4|dkrdddgS|dkr dgS|dkr0ddgSgS)	Nr(r"�
FORWARD_IN�FORWARD_OUTr&rr'rr4)rTr~r4r4r5�get_zone_table_chains�s
znftables.get_zone_table_chainsrJc
s��dkr\�dkr\g}
|
j�j�|��||||dd�	�|
j�j�|��||||dd�	�|
S�jjj|���jdkrxdnd��dkr��d	kr�d
nd}�jjj|�t|��g}g}
|r�|jdd
ddiiddt	|�id�i�|�r|
jdd
ddiiddt	|�id�i�ddd�}|�rlxT|D]L}�dk�rT�jj
j|�}||k�rT�||k�rT�q|j�jd|���qW|�r�xT|D]L}�dk�r��jj
j|�}||k�r��||k�r��qx|
j�jd|���qxW��������fdd�}g}
|�rHx�|D]P}|
�rxB|
D]}|
j|||���qWn"�dk�r0|�r0n|
j||d���q�Wn\�dk�rZ|�rZnJ|
�r�xB|
D]}|
j|d|���qfWn"�dk�r�|�r�n|
j|dd��|
S)Nr'rJrK)r]rLr�pre�postrTFr)r�r`r�z==r�)r.r/r0r�)rGrH�saddr�daddrcs�g}|r|j|�|r |j|�|jddd��fii��td���f|d�}|j�j����rrdd|iiSdd|iiSdS)	Nr�r�z%s_%sz%s_%s_POLICIES_%s)r]r~rmr}rWrZrY)r2r�r��_policy_priority_fragment)�ingress_fragment�egress_fragment�expr_fragmentsrZ)�_policyrm�chain_suffixr�r]�p_objrTr~r4r5�_generate_policy_dispatch_rules

zRnftables.build_policy_ingress_egress_rules.<locals>._generate_policy_dispatch_rule)
�extend�!build_policy_ingress_egress_rulesrMr�Z
get_policyrr�policy_base_chain_name�POLICY_CHAIN_PREFIXr2r�r[Zcheck_source�_rule_addr_fragment)rTr�r�r~rmZingress_interfacesZegress_interfacesZingress_sourcesZegress_sourcesr]r��isSNATZingress_fragmentsZegress_fragmentsZ
ipv_to_family�srcr��dstr�r�r�r4)r�rmr�r�r]r�rTr~r5r��sv









z*nftables.build_policy_ingress_egress_rulesFc	
Cs�|dkrT|dkrTg}	|	j|j|||||||d��|	j|j|||||||d��|	S|dkrh|dkrhdnd}
|jjj||t|
d�}d	d
d	d	d
d
d�|}|t|�dd
kr�|dt|�d�d}d}
|dkr�|
dd||fiig}n,ddd|iid|d�i|
dd||fiig}|�rL|�rLd}|td||f|d�}|j|j	��nP|�rnd}|td||f|d�}n.d}|td||f|d�}|�s�|j|j	��|d|iigS)Nr'rJrKrLrTF)r�r�r�)rrr"r�r�r$r<�+�*�gotor�z%s_%sr)r�r`z==)r.r/r0rXz%s_%s_ZONES)r]r~rmr}rWrYrZ)
r��!build_zone_source_interface_rulesrMr�r�r�rer�r��_zone_interface_fragment)rTr�r[r��	interfacer~rmr2r]r�r�r��opt�actionr�rfrZr4r4r5r�Qs\



z*nftables.build_zone_source_interface_rulesc	Csn|dkr�|dkr�g}|jd�r6|j|td�d��}	nd}	td|�sTt|�sT|	dkrp|j|j||||||d��td|�s�t|�s�|	dkr�|j|j||||||d��|S|dkr�|dkr�d	nd
}
|jjj	||t
|
d�}dd
d�|}ddddddd�|}
|jj�rd||f}nd||f}d}|t||j
|
|�|dd||fiigd�}|j|j||��|d|iigS)Nr'rJzipset:rGrKrHrLrTF)r�rXrY)TFr�r�)rrr"r�r�r$z%s_%s_ZONES_SOURCEz%s_%s_ZONESr�r�z%s_%s)r]r~rmr}rZ)�
startswith�_set_get_familyrerrr��build_zone_source_address_rulesrMr�r�r�rdr�r�r��_zone_source_fragment)rTr�r[r�r\r~rmr]r�Zipset_familyr�r�r�r�Zzone_dispatch_chainr�rZr4r4r5r��sB


z(nftables.build_zone_source_address_rulesc
Cs|dkrH|dkrHg}|j|j||||d��|j|j||||d��|Sddd�|}|dkrj|dkrjd	nd
}|jjj||t|d�}	g}|j|d|td
||	fd�ii�x0d!D](}
|j|d|td||	|
fd�ii�q�WxDd"D]<}
|j|d|td
||	fddd||	|
fiigd�ii�q�W|jjj|j	}|jj
�dk�r�|dk�r�|d#k�r�|}|dk�rhd}|j|d|td
||	f|j|jj
��ddd|	|fiigd�ii�|dk�r|d$k�r|d%k�r�|j�}
n|j
�di}
|j|d|td
||	f|
gd�ii�|�s|j�|S)&Nr'rJrKrLrWrY)TFrTF)r�rmz%s_%s)r]r~r�r�r�deny�allowr�z%s_%s_%srZr�r�)r]r~rmr}r�r(�REJECT�
%%REJECT%%r�r�z"filter_%s_%s: "r�)r�rr�r�r�)r�rr�r�r�)r�r�r�)r�r�r�r�)r�r�)r��build_policy_chain_rulesrMr�r�r�r2r�Z	_policiesr��get_log_deniedr��_reject_fragment�lower�reverse)rTr�r�r~rmr]r�r�r�r�r�r�Z
log_suffix�target_fragmentr4r4r5r��sZ





&




 





z!nftables.build_policy_chain_rulescCs<|dkriS|dkr,ddddiid	|d
�iSttd|��dS)
N�all�unicast�	broadcast�	multicastr)r�r`�pkttypez==)r.r/r0zInvalid pkttype "%s")r�r�r�)r	r)rTr�r4r4r5r��s
z nftables._pkttype_match_fragmentcCsdddd�idddd�idddd�idddd�idddd�idddd�idddd�idddd�idddd�idddd�iddd	d�iddd	d�iddd
d�iddd
d�iddd
d�idddd�idddd�iddd
d�iddd
d�idddd�idddd�idddiidddiid�}||S)Nr�r7zhost-prohibited)r+r}znet-prohibitedzadmin-prohibitedrFznet-unreachablezhost-unreachablezport-unreachabler�zprot-unreachablezaddr-unreachablezno-router+z	tcp reset)zicmp-host-prohibitedzhost-prohibzicmp-net-prohibitedz
net-prohibzicmp-admin-prohibitedzadmin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp-net-unreachableznet-unreachzicmp-host-unreachablezhost-unreachzicmp-port-unreachablezicmp6-port-unreachablezport-unreachzicmp-proto-unreachablez
proto-unreachzicmp6-addr-unreachablezaddr-unreachzicmp6-no-routezno-routez	tcp-resetztcp-rstr4)rTZreject_typeZfragsr4r4r5�_reject_types_fragment�s0
znftables._reject_types_fragmentcCsdddd�iS)Nr�r�zadmin-prohibited)r+r}r4)rTr4r4r5r�sznftables._reject_fragmentcCs ddddiiddddgid	�iS)
Nr)r�r`�l4protoz==r�r7rF)r.r/r0r4)rTr4r4r5�_icmp_match_fragment"sznftables._icmp_match_fragmentcCsP|siSddddd�}|j�\}}|||d�}|j�}|dk	rH||d<d|iS)	N�secondZminuteZhourZday)�s�m�h�d)�rateZper�burst�limit)Zvalue_parseZburst_parse)rTr�Zrich_to_nftr�Zdurationr�r�r4r4r5�_rich_rule_limit_fragment'sz"nftables._rich_rule_limit_fragmentcCs�t|j�tttgkrn<|jrHt|j�tttt	gkrRt
tdt|j���n
t
td��|jdkr�t|j�ttgks�t|j�tt	gkr�dSt|j�tgks�t|j�ttgkr�dSn|jdkr�dSdSdS)NzUnknown action %szNo rule action specified.rr�r�r�r�)
r+�elementrrrr�rrrrr	rrr)rT�	rich_ruler4r4r5�_rich_rule_chain_suffix?s 


z nftables._rich_rule_chain_suffixcCs>|jr|jrttd��|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrr�r�)r�auditr	rrr)rTr�r4r4r5� _rich_rule_chain_suffix_from_logUs


z)nftables._rich_rule_chain_suffix_from_logcCsddiS)Nz%%ZONE_INTERFACE%%r4)rTr4r4r5r�`sz!nftables._zone_interface_fragmentcCsNtd|�rt|�}n,td|�r@|jd�}t|d�d|d}d||d�iS)NrH�/rr<z%%ZONE_SOURCE%%)r[r\)rrr�split)rTr[r\Z
addr_splitr4r4r5r�cs



znftables._zone_source_fragmentcCs
d|jiS)Nz%%POLICY_PRIORITY%%)rr)rTr�r4r4r5r�ksz"nftables._policy_priority_fragmentcCs|s|jdkriSd|jiS)Nrz%%RICH_RULE_PRIORITY%%)rr)rTr�r4r4r5�_rich_rule_priority_fragmentnsz%nftables._rich_rule_priority_fragmentcCs�|js
iS|jjj||t�}ddd�|}|j|�}i}	|jjrPd|jj|	d<|jjr|d|jjkrhdn|jj}
d|
|	d<d	td
|||f||j	|jj
�d|	igd�}|j|j|��|d
|iiS)NrWrY)TFz%sr�Zwarning�warn�levelrJz%s_%s_%sr)r]r~rmr}rZ)
rrMr�r�r�r�r�rr�r�r�r�r�)rTr�r�r�r~r�r�r�r�Zlog_optionsrrZr4r4r5�_rich_rule_logss&
znftables._rich_rule_logc
Cs�|js
iS|jjj||t�}ddd�|}|j|�}dtd|||f||j|jj�dddiigd	�}	|	j	|j
|��|d
|	iiS)NrWrY)TFrJz%s_%s_%srrr�)r]r~rmr}rZ)r�rMr�r�r�r�r�r�r�r�r�)
rTr�r�r�r~r�r�r�r�rZr4r4r5�_rich_rule_audit�s
znftables._rich_rule_auditc
Cs�|js
iS|jjj||t�}ddd�|}|j|�}d|||f}	t|j�tkr\ddi}
�nt|j�tkr�|jjr�|j	|jj�}
nddi}
n�t|j�t
kr�ddi}
n�t|j�tk�rHd}|jjj||t�}d|||f}	|jjj
d	�}t|�d
k�r,dddd
iiddddd
ii|d
gi|dgid�i}
ndddd
ii|dd�i}
nttdt|j���dt|	||j|jj�|
gd�}|j|j|��|d|iiS)NrWrY)TFz%s_%s_%sr�r�r�r&r�r<r�r`�mark�^�&r)r`�valuezUnknown action %srJ)r]r~rmr}rZ)r�rMr�r�r�r�r+rrr�rrr�r�rer	rr�r�r�r�r�)
rTr�r�r�r~r�r�r�r�rmZrule_actionrrZr4r4r5�_rich_rule_action�sB


,znftables._rich_rule_actioncCs�|jd�r0|j|td�d�d|kr(dnd|�St|�r>d}n�td|�rNd}nvtd|�r�d}tj|dd�}d	|jj	|j
d
�i}nDtd|�r�d}t|�}n,d}|jd
�}d	t|d�t
|d�d
�i}dd||d�i|r�dnd|d�iSdS)Nzipset:r�TF�etherrGrK)�strictr�)�addrrerHrLr�rr<r)r*)r,r-z!=z==)r.r/r0)r��_set_match_fragmentrerrr�	ipaddressZIPv4NetworkZnetwork_addressZ
compressedZ	prefixlenrr�rn)rTZ
addr_fieldr\�invertr]Znormalized_addressZaddr_lenr4r4r5r��s(
&





znftables._rule_addr_fragmentcCs6|siS|d
krttd|��ddddiid|d	�iS)NrGrHzInvalid familyr)r�r`�nfprotoz==)r.r/r0)rGrH)r	r)rTZrich_familyr4r4r5�_rich_rule_family_fragment�s
z#nftables._rich_rule_family_fragmentcCs8|siS|jr|j}n|jr&d|j}|jd||jd�S)Nzipset:r�)r)r�ipsetr�r)rTZ	rich_destr\r4r4r5�_rich_rule_destination_fragment�s
z(nftables._rich_rule_destination_fragmentcCsZ|siS|jr|j}n2t|d�r.|jr.|j}nt|d�rH|jrHd|j}|jd||jd�S)N�macrzipset:r�)r)r�hasattrrrr�r)rTZrich_sourcer\r4r4r5�_rich_rule_source_fragment�s
z#nftables._rich_rule_source_fragmentcCsPt|�}t|t�r$|dkr$tt��n(t|�dkr8|dSd|d|dgiSdS)Nrr<�range)r�
isinstancernr	rre)rT�portrr4r4r5�_port_fragments
znftables._port_fragmentc	Csbddd�|}d}|jjj||t�}	g}
|r>|
j|j|j��|rT|
j|jd|��|r||
j|j|j	��|
j|j
|j��|
jdd|dd	�id
|j|�d�i�|s�t
|j�tkr�|
jddd
diiddddgid�i�g}|�r0|j|j|||||
��|j|j|||||
��|j|j|||||
��n.|j|ddtd||	f|
ddigd�ii�|S)NrWrY)TFr(r�r)r*�dport)r,r-z==)r.r/r0r�r`r�r�r��new�	untrackedrZrJz%s_%s_allowr�)r]r~rmr})rMr�r�r�r2rr]r�r�destinationr�sourcerr+r�rrrrr�)rTr�r��protorrr�r�r~r�r�r�r4r4r5�build_policy_ports_ruless:


z!nftables.build_policy_ports_rulesc	CsZddd�|}d}|jjj||t�}g}	|r>|	j|j|j��|rT|	j|jd|��|r||	j|j|j	��|	j|j
|j��|	jdddd	iid
|d�i�|s�t|j
�tkr�|	jdddd
iiddddgid�i�g}
|�r(|
j|j|||||	��|
j|j|||||	��|
j|j|||||	��n.|
j|ddtd||f|	ddigd�ii�|
S)NrWrY)TFr(r�r)r�r`r�z==)r.r/r0r�r�r�r�rrrZrJz%s_%s_allowr�)r]r~rmr})rMr�r�r�r2rr]r�rrrrr+r�rrrrr�)rTr�r�r,rr�r�r~r�r�r�r4r4r5�build_policy_protocol_rules2s8

z$nftables.build_policy_protocol_rulesc	Csbddd�|}d}|jjj||t�}	g}
|r>|
j|j|j��|rT|
j|jd|��|r||
j|j|j	��|
j|j
|j��|
jdd|dd	�id
|j|�d�i�|s�t
|j�tkr�|
jddd
diiddddgid�i�g}|�r0|j|j|||||
��|j|j|||||
��|j|j|||||
��n.|j|ddtd||	f|
ddigd�ii�|S)NrWrY)TFr(r�r)r*�sport)r,r-z==)r.r/r0r�r`r�r�r�rrrZrJz%s_%s_allowr�)r]r~rmr})rMr�r�r�r2rr]r�rrrrrr+r�rrrrr�)rTr�r�rrrr�r�r~r�r�r�r4r4r5�build_policy_source_ports_rulesUs:


z(nftables.build_policy_source_ports_rulesc
	Cs�d}|jjj||t�}	ddd�|}
g}|rR|jdddtd||f||d�ii�g}|rl|j|jd	|��|jd
d|dd
�id|j|�d�i�|jdd||fi�|j|
ddtd|	|d�ii�|S)Nr(rWrY)TFz	ct helperrJzhelper-%s-%s)r]r~r�r+r,r�r)r*r)r,r-z==)r.r/r0rZzfilter_%s_allow)r]r~rmr})rMr�r�r�r2r�r�r)
rTr�r�rrrZhelper_nameZmodule_short_namer~r�r�r�r�r4r4r5�build_policy_helper_ports_ruleszs.



z(nftables.build_policy_helper_ports_rulescCs�ddd�|}|jjj||t�}g}	|rv|t|�ddkrT|dt|�d�d}ddd	d
iid|d�id
dig}
n|jd|�d
dig}
dtd||
d�}|	j|d|ii�|	S)NrWrY)TFr<r�r�r)r�r`r�z==)r.r/r0r�r�rJzfilter_%s_allow)r]r~rmr}rZ)rMr�r�r�rer�r�r2)rTr�r[r�r~r�rr�r�r�r}rZr4r4r5�build_zone_forward_rules�s"z!nftables.build_zone_forward_rulesc	Cs�d}|jjj||tdd�}ddd�|}g}|r`|j|j|j��|j|j|j��|j	|�}	nd}	|t
d||	f|d	d
ddiid
dd�iddigd�}
|
j|j|��|d|
iigS)Nr'T)r�rWrY)TFr�z	nat_%s_%sr)r�r`r�z!=r�)r.r/r0Z
masquerade)r]r~rmr}rZ)
rMr�r�r�r2rrrrr�r�r�r�)rTr�r�r]r�r~r�r�r�r�rZr4r4r5�"_build_policy_masquerade_nat_rules�s&
z+nftables._build_policy_masquerade_nat_rulesc
Cs^g}|rD|jr|jdks,|jrDtd|jj�rD|j|j||d|��nV|r�|jrX|jdksl|jr�td|jj�r�|j|j||d|��n|j|j||d|��d}|jjj||t	�}ddd�|}g}|r�|j
|j|j��|j
|j
|j��|j|�}	nd	}	d
td||	f|dd
ddiiddddgid�iddigd�}
|
j|j|��|j
|d|
ii�|S)NrHrLrGrKr(rWrY)TFr�rJzfilter_%s_%sr)r�r`r�r�r�rr)r.r/r0r�)r]r~rmr}rZ)r]rrrr�r&rMr�r�r�r2rrrr�r�r�r�)rTr�r�r�r�r~r�r�r�r�rZr4r4r5�build_policy_masquerade_rules�s8
z&nftables.build_policy_masquerade_rulesc	Cs$d}	|jjj||	t�}
ddd�|}g}|r\|j|j|j��|j|j|j��|j	|�}
nd}
|jdd|dd	�id
|j
|�d�i�|r�td|�r�t|�}|r�|d
kr�|jd||j
|�d�i�q�|jdd|ii�n|jdd|j
|�ii�|t
d|
|
f|d�}|j|j|��|d|iigS)Nr'rWrY)TFr�r)r*r)r,r-z==)r.r/r0rHr�r�)rrrr;rz	nat_%s_%s)r]r~rmr}rZ)rMr�r�r�r2rrrrr�rrrr�r�r�)rTr�r�rr,�toaddr�toportr]r�r~r�r�r�r�rZr4r4r5�$_build_policy_forward_port_nat_rules�s4


z-nftables._build_policy_forward_port_nat_rulesc	
Cs�g}|rF|jr|jdks&|rFtd|�rF|j|j||||||d|��n�|r�|jrZ|jdksh|r�td|�r�|j|j||||||d|��nL|r�td|�r�|j|j||||||d|��n|j|j||||||d|��|S)NrHrLrGrK)r]rr�r*)	rTr�r�rr,r)r(r�r�r4r4r5�build_policy_forward_port_rulessz(nftables.build_policy_forward_port_rulescCs2|t|krt||Sttd||j|f��dS)Nz)ICMP type '%s' not supported by %s for %s)r�r	rr�)rTr�Z	icmp_typer4r4r5�_icmp_types_to_nft_fragments(sz%nftables._icmp_types_to_nft_fragmentscCsBd}|jjj||t�}ddd�|}|r6|jr6|j}n<|jrjg}d|jkrT|jd�d|jkrr|jd�nddg}g}	�x�|D�]�}
|jjj|�r�d||f}ddi}nd	||f}|j�}g}
|r�|
j|j	|j
��|
j|j|j��|
j|j|j
��|
j|j|
|j��|�r�|	j|j|||||
��|	j|j|||||
��|j�rf|	j|j|||||
��nN|j|�}d
td|||f|
|j�gd�}|j|j|��|	j|d
|ii�q~|jj�dk�r|jjj|��r|	j|d
d
t||
|j|jj��ddd||fiigd�ii�|	j|d
d
t||
|gd�ii�q~W|	S)Nr(rWrY)TFrGrHz%s_%s_allowr�z
%s_%s_denyrJz%s_%s_%s)r]r~rmr}rZr�rr�z"%s_%s_ICMP_BLOCK: ")rMr�r�r��ipvsrr2�query_icmp_block_inversionr�rr]rrrr�r,r�rrr�rr�r�r�r�r�r�)rTr�r�Zictr�r~r�r�r-r�r�Zfinal_chainr�r�r�rZr4r4r5�build_policy_icmp_block_rules/sb





"
"
z&nftables.build_policy_icmp_block_rulescCs�d}|jjj||t�}g}ddd�|}|jjj|�r@|j�}nddi}|j|ddtd||fd	|j�|gd
�ii�|jj	�dkr�|jjj|�r�|j|ddtd||fd	|j�|j
|jj	��dd
d||fiigd
�ii�|S)Nr(rWrY)TFr�rZrJz%s_%sr9)r]r~rmrar}r�rr�z%s_%s_ICMP_BLOCK: )rMr�r�r�r.r�r2r�r�r�r�)rTr�r�r~r�r�r�r�r4r4r5�'build_policy_icmp_block_inversion_rulesks,




 z0nftables.build_policy_icmp_block_inversion_rulescCs�g}ddddiiddd�iddd	d
dgdd
�iddd�ig}|dkrV|jdddii�|jddi�|jdddtd|d�ii�|jdddtdddddd�iddddgid�id digd�ii�|S)!Nr)r�r`rz==rH)r.r/r0Zfibr�ZiifrZoif)�flags�resultFr�rr�zrpfilter_DROP: r�rXrZrJZfilter_PREROUTING)r]r~rmr}r*rFr+)r,r-r�znd-router-advertznd-neighbor-solicitr�)r2r�)rTr�r�r�r4r4r5�build_rpfilter_rules�s0

znftables.build_rpfilter_rulesc	Cs�ddddddddd	g	}d
d�|D�}dd
ddd�idd|id�ig}|jjd"krb|jdddii�|j|jd��g}|jdddtdd|d�ii�|jdddtd d!|d�ii�|S)#Nz::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19cSs2g|]*}d|jd�dt|jd�d�d�i�qS)r�r�rr<)rre)r�rn)�.0r^r4r4r5�
<listcomp>�sz5nftables.build_rfc3964_ipv4_rules.<locals>.<listcomp>r)r*rLr�)r,r-z==r�)r.r/r0r�r�rr�zRFC3964_IPv4_REJECT: zaddr-unreachrWrZrJr�r<)r]r~rmrar}Zfilter_FORWARDrB)r�r�)rMZ_log_deniedr2r�r�)rTZ	daddr_setr�r�r4r4r5�build_rfc3964_ipv4_rules�s:

z!nftables.build_rfc3964_ipv4_rulescCs�d}g}|j|j|j��|j|j|j��|j|j|j��g}|j|j|||||��|j|j|||||��|j|j	|||||��|S)Nr()
r2rr]rrrrrrr)rTr�r�r�r~r�r�r4r4r5�*build_policy_rich_source_destination_rules�sz3nftables.build_policy_rich_source_destination_rulescCs|dkrdSdS)NrGrH�ebTF)rGrHr8r4)rTr�r4r4r5�is_ipv_supported�sznftables.is_ipv_supportedc
Cs�ddd�}||||ddg||dd||g||dd||g||dg||||||g||ddg||dd||g||dgdd	�}||kr�||Sttd
|��dS)NZ	ipv4_addrZ	ipv6_addr)rGrHZ
inet_protoZinet_servicerZifnameZ
ether_addr)zhash:ipzhash:ip,portzhash:ip,port,ipzhash:ip,port,netzhash:ip,markzhash:netzhash:net,netz
hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz!ipset type name '%s' is not valid)r	r
)rTr�r+Zipv_addr�typesr4r4r5�_set_type_list�s"

znftables._set_type_listc
Cs�|rd|kr|ddkrd}nd}t||j||�d�}x0|jd�djd�D]}|dkrLdg|d
<PqLW|r�d|kr�|d|d<d|kr�|d|d<g}x0dD](}d|i}	|	j|�|jdd|	ii�q�W|S)Nr]�inet6rHrG)r~r�r+�:r<�,rK�netrZintervalr1ZtimeoutZmaxelem�sizerJrLrWr�)rKr?r)rJrKrL)r�r;r�r�r2)
rTr�r+�optionsr�Zset_dict�tr�r]Z	rule_dictr4r4r5�build_set_create_rules�s*


znftables.build_set_create_rulescCs$|j|||�}|j||jj��dS)N)rCr�rMr�)rTr�r+rAr�r4r4r5�
set_createsznftables.set_createcCs8x2dD]*}dd|t|d�ii}|j||jj��qWdS)NrJrKrLrYr�)r]r~r�)rJrKrL)r�r�rMr�)rTr�r]rZr4r4r5�set_destroys

znftables.set_destroycCs6|jjj|�jjd�djd�}g}x�tt|��D]�}||dkrr|jdddii�|jdd	|rdd
ndd�i�q2||dkr�|jd|j|�|r�dndd�i�q2||dkr�|jdd|r�dndii�q2||dkr�|jdddii�q2t	d||��q2Wdt|�dk�rd|in|d|�r&dndd|d�iS)Nr=r<r>rr�r`r�r*Zthrr")r,r-rKr?rr�r�Zifacer�r�rz-Unsupported ipset type for match fragment: %sr)�concatrz!=z==�@)r.r/r0)rKr?r)
rMr�	get_ipsetr+r�rrer2r�r	)rTr�Z
match_destr�type_formatr3�ir4r4r5r s$ znftables._set_match_fragmentcCsN|jjj|�}|jjd�djd�}|jd�}t|�t|�krHttd��g}�x�tt|��D�]�}||dk�r,y||j	d�}Wn&t
k
r�|jd�||}	Yn,X|j||d|��|||dd�}	y|	j	d�}Wn t
k
�r|j|	�Yn(X|jd|	d|�|	|dd�gi�q\||dk�r d||k�rb|jd||jd�i�n�y||j	d�}WnLt
k
�r�||}
d|jk�r�|jdd
k�r�t
|
�}
|j|
�Yn^X||d|�}
d|jk�r�|jdd
k�r�t
|
�}
|jd|
t|||dd��d�i�q\|j||�q\Wt|�dk�rJd|igS|S)Nr=r<r>z+Number of values does not match ipset type.rZtcp�-rrKr?r�r]r<r�)rrerF)rKr?)rMrrHr+r�rer	rrrar�r2rArrn)rTr��entry�objrIZentry_tokensZfragmentrJraZport_strrr4r4r5�_set_entry_fragment7sL

("znftables._set_entry_fragmentc	Cs>g}|j||�}x(dD] }|jdd|t||d�ii�qW|S)NrJrKrLrWr�)r]r~r��elem)rJrKrL)rNr2r�)rTr�rLr�r�r]r4r4r5�build_set_add_rulesks

znftables.build_set_add_rulescCs"|j||�}|j||jj��dS)N)rPr�rMr�)rTr�rLr�r4r4r5�set_addusznftables.set_addcCsF|j||�}x4dD],}dd|t||d�ii}|j||jj��qWdS)NrJrKrLrYr�)r]r~r�rO)rJrKrL)rNr�r�rMr�)rTr�rLr�r]rZr4r4r5�
set_deleteys
znftables.set_deletecCs4g}x*dD]"}dd|t|d�ii}|j|�q
W|S)NrJrKrLr{r�)r]r~r�)rJrKrL)r�r2)rTr�r�r]rZr4r4r5�build_set_flush_rules�s
znftables.build_set_flush_rulescCs |j|�}|j||jj��dS)N)rSr�rMr�)rTr�r�r4r4r5�	set_flush�s
znftables.set_flushcCsJ|jjj|�}|jdkrd}n(|jrBd|jkrB|jddkrBd}nd}|S)Nzhash:macr	r]r<rLrK)rMrrHr+rA)rTr�rr]r4r4r5r��s
znftables._set_get_familyc	Cs�g}|j|j|||��|j|j|��d}x^|D]D}|j|j||��|d7}|dkr2|j||jj��|j�d}q2W|j||jj��dS)Nrr<i�)r�rCrSrPr�rMr��clear)	rTZset_nameZ	type_nameZentriesZcreate_optionsZ
entry_optionsr��chunkrLr4r4r5�set_restore�s
znftables.set_restore)N)N)r�)rJ)FrJ)rJ)rJ)F)NN)NN)NN)NN)N)N)N)N)N)F)N)N)F)NN)I�__name__�
__module__�__qualname__r�Zpolicies_supportedrVrhrlrtrzr�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�rrrr�rrrrr r!r#r$r%r&r'r*r+r,r/r0r3r6r7r9r;rCrDrErrNrPrQrRrSrTr�rWr4r4r4r5rI�s�/.`

4


R
i
;
-
9
 +


	
$
$
$


'
$

<
#


4
		rIij���i����)N)(Z
__future__rrirwr
Zfirewall.core.loggerrZfirewall.functionsrrrrrZfirewall.errorsr	r
rrr
rrZfirewall.core.richrrrrrrrZnftables.nftablesrr�r�r�r�r�r6r��objectrIr4r4r4r5�<module>s�$$





































__pycache__/watcher.cpython-36.pyc000064400000005256151731527050013055 0ustar003

��g��@s*dgZddlmZmZGdd�de�ZdS)�Watcher�)�Gio�GLibc@sdeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dS)rcCs"||_||_i|_i|_g|_dS)N)�	_callback�_timeout�	_monitors�	_timeouts�_blocked)�self�callbackZtimeout�r�/usr/lib/python3.6/watcher.py�__init__s
zWatcher.__init__cCs:tjj|�}|jtjjd�|j|<|j|jd|j�dS)N�changed)	r�File�new_for_pathZmonitor_directory�FileMonitorFlags�NONEr�connect�_file_changed_cb)r
Z	directory�gfilerrr
�
add_watch_dir"szWatcher.add_watch_dircCs:tjj|�}|jtjjd�|j|<|j|jd|j�dS)Nr)	rrrZmonitor_filerrrrr)r
�filenamerrrr
�add_watch_file(szWatcher.add_watch_filecCs
|jj�S)N)r�keys)r
rrr
�get_watches.szWatcher.get_watchescCs
||jkS)N)r)r
rrrr
�	has_watch1szWatcher.has_watchcCs|j|=dS)N)r)r
rrrr
�remove_watch4szWatcher.remove_watchcCs||jkr|jj|�dS)N)r	�append)r
rrrr
�block_source7s
zWatcher.block_sourcecCs||jkr|jj|�dS)N)r	�remove)r
rrrr
�unblock_source;s
zWatcher.unblock_sourcecCs4x.t|jj��D]}tj|j|�|j|=qWdS)N)�listrrr�
source_remove)r
rrrr
�clear_timeouts?szWatcher.clear_timeoutscCs ||jkr|j|�|j|=dS)N)r	rr)r
rrrr
�_call_callbackDs

zWatcher._call_callbackcCs�|j�}||jkr8||jkr4tj|j|�|j|=dS|tjjksh|tjjksh|tjj	ksh|tjj
kr�||jkr�tj|j|�|j|=tj|j|j
|�|j|<dS)N)Zget_parse_namer	rrr#rZFileMonitorEventZCHANGEDZCREATEDZDELETEDZATTRIBUTE_CHANGEDZtimeout_add_secondsrr%)r
ZmonitorZgio_fileZgio_other_fileZeventrrrr
rIs


zWatcher._file_changed_cbN)�__name__�
__module__�__qualname__rrrrrrrr!r$r%rrrrr
rsN)�__all__Z
gi.repositoryrr�objectrrrrr
�<module>s__pycache__/__init__.cpython-36.opt-1.pyc000064400000000161151731527050014104 0ustar003

��g�@sdS)N�rrr�/usr/lib/python3.6/__init__.py�<module>s__pycache__/fw.cpython-36.opt-1.pyc000064400000066115151731527050012774 0ustar003

��g���@s�dgZddlZddlZddlZddlZddlZddlmZddlm	Z	ddl
mZddl
mZddl
m
Z
ddl
mZdd	l
mZdd
lmZddlmZddlmZdd
lmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl$m%Z%m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/m0Z0ddl1m2Z2m3Z3ddl4m5Z5ddl6m7Z7ddl8m9Z9ddl:m;Z;ddlm<Z<dd l=m>Z>Gd!d�de?�Z@dS)"�Firewall�N)�config)�	functions)�	ipXtables)�ebtables)�nftables)�ipset)�modules)�FirewallIcmpType)�FirewallService)�FirewallZone)�FirewallDirect)�FirewallConfig)�FirewallPolicies)�
FirewallIPSet)�FirewallTransaction)�FirewallHelper)�FirewallPolicy)�nm_get_bus_name�nm_get_interfaces_in_zone)�log)�firewalld_conf)�Direct)�service_reader)�icmptype_reader)�zone_reader�Zone)�ipset_reader)�IPSET_TYPES)�
helper_reader)�
policy_reader)�errors)�
FirewallErrorc@s�eZdZdedd�Zdd�Zdd�Zdd	�Zd
d�Zdfdd
�Zdd�Z	dgdd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zdhd)d*�Zdid+d,�Zd-d.�Zdjd/d0�Zdkd1d2�Zdld3d4�Zd5d6�Zd7d8�Zd9d:�Zd;d<�Zd=d>�Z d?d@�Z!dAdB�Z"dCdD�Z#dEdF�Z$dGdH�Z%dIdJ�Z&dKdL�Z'dMdN�Z(dmdOdP�Z)dQdR�Z*dSdT�Z+dUdV�Z,dWdX�Z-dYdZ�Z.d[d\�Z/d]d^�Z0d_d`�Z1dadb�Z2dcdd�Z3d(S)nrFcCsttj�|_||_|jr>d|_d|_d|_d|_t	|_
d|_nrtj
|�|_d|_g|_tj|�|_d|_g|_tj�|_d|_tj�|_d|_g|_
tj|�|_d|_tj�|_t|�|_t|�|_t|�|_ t!|�|_"t#|�|_t$�|_%t&|�|_t'|�|_(t)|�|_*|j+�dS)NFT),rr�FIREWALLD_CONF�_firewalld_conf�_offline�ip4tables_enabled�ip6tables_enabled�ebtables_enabled�
ipset_enabledr�ipset_supported_types�nftables_enabledr�	ip4tables�ip4tables_backend�ipv4_supported_icmp_types�	ip6tables�ip6tables_backend�ipv6_supported_icmp_typesr�ebtables_backendr�
ipset_backendr�nftables_backendr	�modules_backendr
�icmptyper�servicer�zoner
�directrr�policiesrr�helperr�policy�_Firewall__init_vars)�selfZoffline�r?�/usr/lib/python3.6/fw.py�__init__CsB










zFirewall.__init__cCsDd|j|j|j|j|j|j|j|j|j|j	|j
|j|j|j
|jfS)Nz:%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r))�	__class__r&r'r(�_state�_panic�
_default_zone�_module_refcount�_marks�cleanup_on_exit�cleanup_modules_on_exit�ipv6_rpfilter_enabledr)�_individual_calls�_log_denied)r>r?r?r@�__repr__kszFirewall.__repr__cCsjd|_d|_d|_i|_g|_tj|_tj|_	tj
|_tj|_
tj|_tj|_tj|_tj|_tj|_dS)NZINITF�)rCrDrErFrGrZFALLBACK_CLEANUP_ON_EXITrHZ FALLBACK_CLEANUP_MODULES_ON_EXITrIZFALLBACK_IPV6_RPFILTERrJZFALLBACK_INDIVIDUAL_CALLSrKZFALLBACK_LOG_DENIEDrLZFALLBACK_FIREWALL_BACKEND�_firewall_backendZFALLBACK_FLUSH_ALL_ON_RELOAD�_flush_all_on_reloadZFALLBACK_RFC3964_IPV4�
_rfc3964_ipv4ZFALLBACK_ALLOW_ZONE_DRIFTING�_allow_zone_drifting)r>r?r?r@Z__init_varstszFirewall.__init_varscCs�|jr$d|jj�kr$tjd�d|_|jrHd|jj�krHtjd�d|_|jrld|jj�krltjd�d|_|jr�|jr�|j	r�tj
d�tjd�dS)N�filterziptables is not usable.Fzip6tables is not usable.zebtables is not usable.zNo IPv4 and IPv6 firewall.�)
r&r-�get_available_tablesr�info1r'r0r(r2r+�fatal�sys�exit)r>r?r?r@�
_check_tables�s 



zFirewall._check_tablescCszy|jj�Wn*tk
r8tjd�d|_g|_YnX|jj�|_|jj	�|jj
s||jjrltjd�ntjd�d|_|j
r�|jjd�|_n|jr�|jj�|_ng|_|jj	�|jj
s�|jjr�tjd�ntjd�d|_|j
r�|jjd�|_n|j�r|jj�|_ng|_|jj	�|jj
�sN|jj�r>tjd	�ntjd
�d|_|j�rv|j�rv|jj�rvtjd�dS)Nz4ipset not usable, disabling ipset usage in firewall.FzFiptables-restore is missing, using individual calls for IPv4 firewall.zCiptables-restore and iptables are missing, disabling IPv4 firewall.�ipv4zGip6tables-restore is missing, using individual calls for IPv6 firewall.zEip6tables-restore and ip6tables are missing, disabling IPv6 firewall.�ipv6zHebtables-restore is missing, using individual calls for bridge firewall.zEebtables-restore and ebtables are missing, disabling bridge firewall.zSebtables-restore is not supporting the --noflush option, will therefore not be used)r3Zset_list�
ValueErrorr�warningr)r*Zset_supported_typesr-Zfill_exists�restore_command_existsZcommand_existsr&r+r4Zsupported_icmp_typesr.r0r'r1r2r(rK�restore_noflush_option�debug1)r>r?r?r@�_start_check�sL








zFirewall._start_checkc>Cs�tj}tjdtj�y|jj�Wn8tk
rZ}ztj|�tjd�WYdd}~X�n"X|jj	d�rt|jj	d�}|jj	d�r�|jj	d�}|dk	r�|j
�dBkr�d|_tjd|j�|jj	d	��r|jj	d	�}|dk	r�|j
�dCkr�d|_|dk	�r|j
�dDk�rd|_tjd
|j�|jj	d��rv|jj	d�}|dk	�rv|j
�dEk�rvtjd�y|j
j�Wntk
�rtYnX|jj	d��r�|jj	d�}|dk	�r�|j
�dFk�r�d|_|j
�dGk�r�d|_|j�r�tjd�n
tjd�|jj	d��r"|jj	d�}|dk	�r"|j
�dHk�r"tjd�d|_|jj	d��rt|jj	d�}|dk�sT|j
�dk�r\d|_n|j
�|_tjd|j�|jj	d��r�|jj	d�|_tjd|j�|jj	d��r�|jj	d�}|j
�dIk�r�d|_nd|_tjd|j�|jj	d��r&|jj	d�}|j
�dJk�rd|_nd|_tjd|j�|jj	d��r||jj	d�}|j
�dKk�rVd|_nd|_|j�sntjd�tjd |j�|jjtj|j��|j|j�|j�s�|j�tjd!�y|j
jj�WnZtk
�r }z<|j
j��r�tjd"|j
jj |�ntjd"|j
jj |�WYdd}~XnX|jj!tj|j
��|j"tj#d#�|j"tj$d#�|j"tj%d$�|j"tj&d$�t'|j(j)��d%k�r�tjd&�|j"tj*d'�|j"tj+d'�|j"tj,d(�|j"tj-d(�t'|j.j/��d%k�r�tjd)�|j"tj0d*�|j"tj1d*�t'|j2j3��d%k�r&tj4d+�t5j6d,�|j"tj7d-�|j"tj8d-�d}x.dLD]&}||j2j3�k�rLtj4d1|�d}�qLW|�r�t5j6d,�||j2j3�k�r�d2|j2j3�k�r�d2}nd3|j2j3�k�r�d3}nd.}tjd4||�|}ntjd5|�t9tj:�}	t;j<j=tj:��rRtjd6tj:�y|	j�Wn4tk
�rP}ztjd7tj:|�WYdd}~XnX|j>j?|	�|jj@tj|	��|jA|�|_B|j�r�dS|jC�tjD�d%k�r�tEjE�}
tF|�}|�s�|jG|d8�|�r�|�s�|jH�r�|jIjJ��r�|jKd�|jL�|�r|�rtjd9�|jMjN�|jO|d8�|jKd�|jL�|jH�rX|jIjJ��rXtjd:�|jIjP�tjd;�|jQ|d8�tjd<�|j2jR|d8�|j2jSd|jB|d8�tjd=�|jTjU|d8�|jKd�|jL�|j>jV��rVtjd>�|j>jW|�y|jKd�|jL�WnXtk
�r>}z$t|jXd?|jY�r&|jYnd@��WYdd}~Xntk
�rT�YnX~tjD�d,k�r�tEjE�}
tjZdA|
|
�dS)MNz"Loading firewalld config file '%s'z0Using fallback firewalld configuration settings.�DefaultZoneZ
CleanupOnExit�no�falseFzCleanupOnExit is set to '%s'ZCleanupModulesOnExit�yes�trueTz#CleanupModulesOnExit is set to '%s'ZLockdownzLockdown is enabledZ
IPv6_rpfilterzIPv6 rpfilter is enabledzIPV6 rpfilter is disabledZIndividualCallszIndividualCalls is enabled�	LogDeniedZoffzLogDenied is set to '%s'ZFirewallBackendzFirewallBackend is set to '%s'ZFlushAllOnReloadzFlushAllOnReload is set to '%s'ZRFC3964_IPv4zRFC3964_IPv4 is set to '%s'ZAllowZoneDriftingz�AllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.z AllowZoneDrifting is set to '%s'zLoading lockdown whitelistz*Failed to load lockdown whitelist '%s': %srr6rzNo icmptypes found.r;r7zNo services found.r8zNo zones found.rTr<�block�drop�trustedzZone '%s' is not available.ZpublicZexternalz+Default zone '%s' is not valid. Using '%s'.zUsing default zone '%s'zLoading direct rules file '%s'z)Failed to load direct rules file '%s': %s)�use_transactionzUnloading firewall moduleszApplying ipsetszApplying default rule setzApplying used zoneszApplying used policiesz2Applying direct chains rules and passthrough rulesz
Direct: %srNz%Flushing and applying took %f seconds)rdre)rfrg)rdre)rfrg)rdre)rfrg)rfrg)rdre)rdre)rdre)rirjrk)[rZ
FALLBACK_ZONErrar#r$�read�	Exceptionr^�get�lowerrHrIr:Zenable_lockdownr"rJrKrLrOrPrQrRr%Zset_firewalld_conf�copy�deepcopy�_select_firewall_backendrbZlockdown_whitelistZquery_lockdown�error�filenameZset_policies�_loaderZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPES�lenr6�
get_icmptypesZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESr7�get_servicesZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr8�	get_zonesrWrXrYZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESrZFIREWALLD_DIRECT�os�path�existsr9Zset_permanent_configZ
set_direct�
check_zonerErZZgetDebugLogLevel�timer�flushr)rZ
has_ipsets�execute�clearr5�unload_firewall_modules�apply_default_tablesZapply_ipsets�apply_default_rulesZapply_zones�change_default_zoner<Zapply_policiesZhas_configurationZapply_direct�code�msgZdebug2)r>�reload�complete_reloadZdefault_zoner��valuert�zr8�objZtm1�transaction�eZtm2r?r?r@�_start�st







 




















.zFirewall._startcCsHy|j�Wn&tk
r2d|_|jd��YnXd|_|jd�dS)N�FAILED�ACCEPT�RUNNING)r�rnrC�
set_policy)r>r?r?r@�start�s
zFirewall.startcCshtjj|�sdS|rZ|jtj�rV|dkrVt�}tjj|�|_|j	|j�||_d|_
nd}�x|ttj|��D�]h}|j
d�s�|jtj�rl|dkrltjjd||f�rl|jd||f|dd�qld||f}tjd||��y�|dk�r�t||�}|j|jj�k�r8|jj|j�}tjd	||j|j|j�|jj|j�n|jjtj��rNd|_
y|jj|�Wn<tk
�r�}	ztjd
|jt|	�f�WYdd}	~	XnX|jjtj|���n�|dk�rFt||�}|j|jj�k�r|jj |j�}tjd	||j|j|j�|jj!|j�n|jjtj��r$d|_
|jj"|�|jj"tj|���n.|dk�rnt#|||d�}|�r�dtjj|�tjj|�d
d�f|_|j	|j�tj|�}
|j|j$j%�k�r|j$j&|j�}|j$j'|j�|j(�r�tjd||j||�|j)|�ntjd	||j|j|j�n|jjtj��r,d|_
d|
_
|jj*|
�|�r^tjd||j||�|j)|�n|j$j*|��n|dk�rDt+||�}|j|j,j-�k�r�|j,j.|j�}tjd	||j|j|j�|j,j/|j�n|jjtj��r�d|_
y|j,j0|�Wn<tk
�r,}	ztj1d
|jt|	�f�WYdd}	~	XnX|jj0tj|���n0|dk�r�t2||�}|j|j3j4�k�r�|j3j5|j�}tjd	||j|j|j�|j3j6|j�n|jjtj��r�d|_
|j3j7|�|jj7tj|��n�|dk�rht8||�}|j|j9j:�k�r2|j9j;|j�}tjd	||j|j|j�|j9j<|j�n|jjtj��rHd|_
|j9j=|�|jj>tj|��ntj?d|�Wqltk
�r�}ztj@d|||�WYdd}~XqltAk
�r�tj@d||�tjB�YqlXqlW|�rd|j(�rd|j|j$j%�k�rX|j$j&|j�}tjd||j|j|j�y|j$j'|j�WntAk
�rHYnX|jjC|j�|j$j*|�dS)Nr8Fz.xmlz%s/%sT)�combinezLoading %s file '%s'r6z  Overloads %s '%s' ('%s/%s')z%s: %s, ignoring for run-time.r7)Z
no_check_namer�z  Combining %s '%s' ('%s/%s')rr;r<zUnknown reader type %szFailed to load %s file '%s': %szFailed to load %s file '%s':z0  Overloading and deactivating %s '%s' ('%s/%s')���)Dr{r|�isdir�
startswithrZ
ETC_FIREWALLDr�basename�nameZ
check_name�default�sorted�listdir�endswithrvrrarr6rxZget_icmptyperuZremove_icmptypeZadd_icmptyper"rV�strrqrrrr7ryZget_serviceZremove_serviceZadd_servicerr8rzZget_zoneZremove_zone�combinedr�Zadd_zonerr�
get_ipsets�	get_ipsetZremove_ipset�	add_ipsetr^rr;Zget_helpersZ
get_helperZ
remove_helperZ
add_helperr r<�get_policiesZ
get_policyZ
remove_policyZ
add_policyZadd_policy_objectrWrtrnZ	exceptionZforget_zone)r>r|Zreader_typer�Z
combined_zonerur�r�Zorig_objrtZ
config_objr�r?r?r@rvs


$







$




zFirewall._loadercCsp|jj�|jj�|jj�|jj�|jj�|jj�|jj�|jj�|j	j�|j
j�|j�dS)N)r6�cleanupr7r8rr;rr9r:r<r$r=)r>r?r?r@r��s









zFirewall.cleanupcCsN|jsB|jr(|j�|jj�|jd�|jrBtjd�|jj	�|j
�dS)Nr�z!Unloading firewall kernel modules)r%rHr�rr�rIrrar5r�r�)r>r?r?r@�stop�s



z
Firewall.stopc	Cs�d}d}x�t|�D]�\}}|r0|jj|�\}}n$|j|dkrDd}n|jj|�\}}|dkrn|d7}||7}q|r�|jj|d�|j|d7<q||jkr|j|d8<|j|dkr|j|=qW||fS)NrrNrT)�	enumerater5�load_modulerFZ
unload_module�
setdefault)	r>Z_modules�enableZ
num_failedZ
error_msgs�i�moduleZstatusr�r?r?r@�handle_modules�s(
zFirewall.handle_modulescCs|dkrd|_dS)NrF)r+)r>�backendr?r?r@rs�sz!Firewall._select_firewall_backendcCs4x|j�D]}|j|kr
|Sq
Wttjd|��dS)Nz'%s' backend does not exist)�all_backendsr�r"r!Z
UNKNOWN_ERROR)r>r�r�r?r?r@�get_backend_by_name�s

zFirewall.get_backend_by_namecCs\|jr|jS|dkr |jr |jS|dkr4|jr4|jS|dkrH|jrH|jStt	j
d|��dS)Nr[r\�ebz-'%s' is not a valid backend or is unavailable)r+r4r&r-r'r0r(r2r"r!�INVALID_IPV)r>�ipvr?r?r@�get_backend_by_ipv�szFirewall.get_backend_by_ipvcCsP|dkr|jr|jS|dkr(|jr(|jS|dkr<|jr<|jSttjd|��dS)Nr[r\r�z-'%s' is not a valid backend or is unavailable)	r&r-r'r0r(r2r"r!r�)r>r�r?r?r@�get_direct_backend_by_ipv�sz"Firewall.get_direct_backend_by_ipvcCs<|dkr|jS|dkr|jS|dkr*|jS|dkr8|jSdS)Nr,r/rrF)r&r'r(r+)r>r�r?r?r@�is_backend_enabled�szFirewall.is_backend_enabledcCs8|jr
dS|dkr|jS|dkr&|jS|dkr4|jSdS)NTr[r\r�F)r+r&r'r()r>r�r?r?r@�is_ipv_enabledszFirewall.is_ipv_enabledcCsRg}|jr|j|j�n6|jr*|j|j�|jr<|j|j�|jrN|j|j�|S)N)	r+�appendr4r&r-r'r0r(r2)r>�backendsr?r?r@�enabled_backendsszFirewall.enabled_backendscCsPg}|jr|j|j�|jr(|j|j�|jr:|j|j�|jrL|j|j�|S)N)	r&r�r-r'r0r(r2r+r4)r>r�r?r?r@r�szFirewall.all_backendsNcCsN|dkrt|�}n|}x |j�D]}|j||j��q W|dkrJ|jd�dS)NT)rr��	add_rulesZbuild_default_tablesr�)r>rlr�r�r?r?r@r�$s
zFirewall.apply_default_tablescCs�|dkrt|�}n|}x(|j�D]}|j|j�}|j||�q W|jd�r~|jd�}d|j�kr~|jr~|j	|j�}|j||�|jd�r�|j
r�|j�}|j||�|dkr�|jd�dS)Nr\�rawT)
rr�Zbuild_default_rulesrLr�r�r�rUrJZbuild_rpfilter_rulesrQZbuild_rfc3964_ipv4_rulesr�)r>rlr�r��rulesZipv6_backendr?r?r@r�0s"


zFirewall.apply_default_rulescCs|jr|jj�rdSdS)NTF)r+r9Zhas_runtime_configuration)r>r?r?r@�may_skip_flush_direct_backendsHsz'Firewall.may_skip_flush_direct_backendscCs`|dkrt|�}n|}x2|j�D]&}||j�kr2q |j�}|j||�q W|dkr\|jd�dS)NT)rr�r��build_flush_rulesr�r�)r>rlr�r�r�r?r?r@�flush_direct_backendsNs
zFirewall.flush_direct_backendscCsp|dkrt|�}n|}tjd�|j�s4|j|d�x$|j�D]}|j�}|j||�q>W|dkrl|jd�dS)NzFlushing rule set)rlT)	rrrar�r�r�r�r�r�)r>rlr�r�r�r?r?r@r�]s

zFirewall.flushcCs`|dkrt|�}n|}tjd|�x&|j�D]}|j|�}|j||�q,W|dkr\|jd�dS)NzSetting policy to '%s'T)rrrar�Zbuild_set_policy_rulesr�r�)r>r<rlr�r�r�r?r?r@r�os

zFirewall.set_policycCsB|sdS|j|�}|s&ttjd|��|j|�s4dS|j||j�S)NrNz'%s' is not a valid backend)r�r"r!r�r��set_rulerL)r>�backend_name�ruler�r?r?r@r��s


z
Firewall.rulecCs"ttd|��}|j|�}|s,ttjd|��|j|�s:dS|js\|js\|dkoX|j	j
�rx�t|�D]�\}}y|j||j
�Wqftk
�r}zjtjtj��tj|�xFt|d|��D]2}y|j|j|�|j
�Wq�tk
r�Yq�Xq�W|�WYdd}~XqfXqfWn|j||j
�dS)Nz'%s' is not a valid backendr)�listrSr�r"r!r�r�rKr_r2r`r�r�rLrnrra�	traceback�
format_excrt�reversedZreverse_ruleZ	set_rules)r>r�r�Z_rulesr�r�r�r�r?r?r@r��s.




zFirewall.rulescCs|jrttj��dS)N)rDr"r!Z
PANIC_MODE)r>r?r?r@�check_panic�szFirewall.check_paniccCs"|}||jj�krttj|��|S)N)r<r�r"r!ZINVALID_POLICY)r>r<Z_policyr?r?r@�check_policy�szFirewall.check_policycCs8|}|s|dkr|j�}||jj�kr4ttj|��|S)NrN)�get_default_zoner8rzr"r!ZINVALID_ZONE)r>r8�_zoner?r?r@r~�szFirewall.check_zonecCstj|�sttj|��dS)N)rZcheckInterfacer"r!ZINVALID_INTERFACE)r>�	interfacer?r?r@�check_interface�s
zFirewall.check_interfacecCs|jj|�dS)N)r7�
check_service)r>r7r?r?r@r��szFirewall.check_servicecCstj|�sttj|��dS)N)r�
check_portr"r!ZINVALID_PORT)r>Zportr?r?r@r��s
zFirewall.check_portcCs*|sttj��|dkr&ttjd|��dS)N�tcp�udp�sctp�dccpz''%s' not in {'tcp'|'udp'|'sctp'|'dccp'})r�r�r�r�)r"r!ZMISSING_PROTOCOLZINVALID_PROTOCOL)r>Zprotocolr?r?r@�check_tcpudp�s
zFirewall.check_tcpudpcCstj|�sttj|��dS)N)rZcheckIPr"r!�INVALID_ADDR)r>Zipr?r?r@�check_ip�s
zFirewall.check_ipcCsP|dkr tj|�sLttj|��n,|dkr@tj|�sLttj|��nttjd��dS)Nr[r\z'%s' not in {'ipv4'|'ipv6'})rZcheckIPnMaskr"r!r�Z
checkIP6nMaskr�)r>r��sourcer?r?r@�
check_address�s

zFirewall.check_addresscCs|jj|�dS)N)r6�check_icmptype)r>Zicmpr?r?r@r��szFirewall.check_icmptypecCs>t|t�std|t|�f��t|�dkr:ttjd|��dS)Nz%s is %s, expected intrz#timeout '%d' is not positive number)�
isinstance�int�	TypeError�typer"r!�
INVALID_VALUE)r>Ztimeoutr?r?r@�
check_timeout�s

zFirewall.check_timeoutc Cs`|j}|j}|sNi}x&|jj�D]}|jj|�d||<q W|jj�}|j�}g}x$|jj	�D]}	|j
|jj|	��q^W|s�|jd�|j
�|j�d}
y|jd|d�Wn&tk
r�}z
|}
WYdd}~XnX|�r(xL|D]D}|jj|j�s�x0|jj�D]"}
|
jdk�r�q�|
j|j��q�Wq�W|�s�|j�}||k�r�||k�rRi||<xFt||j��D]2\}}|d�rd||||||<|||=�qdWxb|jj�D]T}||k�r�x.||D]"}|jj|||||d��q�W||=ntjd|��q�Wt|�d	k�r6x(t|j��D]}tjd
|�||=�qW~x�|D]�}|jj|j��r�xx|jD]R}y|jj|j|�Wn6tk
�r�}z|jt j!k�r�|�WYdd}~XnX�qZWn|jj"|�|jj#|j��q>W|jj$|�t%�}|�r,x@|jj�dgD],}x$t&|�D]}|jj|||d��q
W�q�W||_|j�sD|jd
�|
�rVd|_'|
�nd|_'dS)N�
interfacesZDROPT)r�r�r�__default__�senderzNew zone '%s'.rz(Lost zone '%s', zone interfaces dropped.rN)r�r�r�r�)(rDrPr8rz�get_settingsr9Zget_runtime_configr�rr�r�r�r�r�r�r�rnZquery_ipsetr�r�Zset_destroyr��items�change_zone_of_interfacerrVrw�keysZentriesZ	add_entryr"r�r!�ALREADY_ENABLEDr�Zapply_ipsetZ
set_configrrrC)r>r�rDZ	flush_allZ_zone_interfacesr8Z_direct_config�_old_dzZ_ipset_objs�_nameZstart_exceptionr�r�r�Z_new_dz�iface�settingsZinterface_id�entryr�Znm_bus_namer�r?r?r@r��s�









zFirewall.reloadcCs|jS)N)rC)r>r?r?r@�	get_stateaszFirewall.get_statecCsZ|jrttjd��y|jd�Wn.tk
rN}zttj|��WYdd}~XnXd|_dS)Nzpanic mode already enabledZPANICT)rDr"r!r�r�rn�COMMAND_FAILED)r>r�r?r?r@�enable_panic_modefszFirewall.enable_panic_modecCsZ|jsttjd��y|jd�Wn.tk
rN}zttj|��WYdd}~XnXd|_dS)Nzpanic mode is not enabledr�F)rDr"r!ZNOT_ENABLEDr�rnr�)r>r�r?r?r@�disable_panic_modeqszFirewall.disable_panic_modecCs|jS)N)rD)r>r?r?r@�query_panic_mode|szFirewall.query_panic_modecCs|jS)N)rL)r>r?r?r@�get_log_denied�szFirewall.get_log_deniedcCsb|tjkr&ttjd|djtj�f��||j�krR||_|jj	d|�|jj
�nttj|��dS)Nz'%s', choose from '%s'z','rh)rZLOG_DENIED_VALUESr"r!r��joinr�rLr$�set�writeZALREADY_SET)r>r�r?r?r@�set_log_denied�s
zFirewall.set_log_deniedcCs|jS)N)rE)r>r?r?r@r��szFirewall.get_default_zonecCs�|j|�}||jkr�|j}||_|jjd|�|jj�|jj||�|jj|�}x@t|dj	��D]\}}|drd|jj
d|�qdWnttj
|��dS)Nrcr�r�rN)r~rEr$r�r�r8r�r�r�r�r�r"r!ZZONE_ALREADY_SET)r>r8r�r�Z_old_dz_settingsr�r�r?r?r@�set_default_zone�s


zFirewall.set_default_zonecCsH|j�}x:|j�D].\}}|s(t|t�r2|||<q||kr||=qW|S)N)rqr�r��bool)r>Z	permanentZruntimer��keyr�r?r?r@�'combine_runtime_with_permanent_settings�s

z0Firewall.combine_runtime_with_permanent_settingscCsi}i}x�t|j��t|j��BD]�}||kr"t||t�r�t||krN||ng�}tt||�|�||<t|t||�A|@�||<q"t||t�s�t||t�r�||r�||r�d||<q�||r�||r�d||<q"ttjdj	t
||�|���q"W||fS)NTFz Unhandled setting type {} key {})r�r�r�r�r�r�r"r!ZINVALID_SETTING�formatr�)r>Zold_settingsZnew_settingsZadd_settingsZremove_settingsr��oldr?r?r@�get_added_and_removed_settings�s

 z'Firewall.get_added_and_removed_settings)F)FF)F)N)N)N)N)N)F)4�__name__�
__module__�__qualname__rArMr=rZrbr�r�rvr�r�r�rsr�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r~r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r?r?r?r@rBsh
(	;
 








 	
s)A�__all__Zos.pathr{rXrqrr�ZfirewallrrZ
firewall.corerrrrr	Zfirewall.core.fw_icmptyper
Zfirewall.core.fw_servicerZfirewall.core.fw_zonerZfirewall.core.fw_directr
Zfirewall.core.fw_configrZfirewall.core.fw_policiesrZfirewall.core.fw_ipsetrZfirewall.core.fw_transactionrZfirewall.core.fw_helperrZfirewall.core.fw_policyrZfirewall.core.fw_nmrrZfirewall.core.loggerrZfirewall.core.io.firewalld_confrZfirewall.core.io.directrZfirewall.core.io.servicerZfirewall.core.io.icmptyperZfirewall.core.io.zonerrZfirewall.core.io.ipsetrZfirewall.core.ipsetrZfirewall.core.io.helperrZfirewall.core.io.policyr r!Zfirewall.errorsr"�objectrr?r?r?r@�<module>sH__pycache__/fw_service.cpython-36.pyc000064400000003201151731527050013540 0ustar003

��gg�@s2dgZddlmZddlmZGdd�de�ZdS)�FirewallService�)�errors)�
FirewallErrorc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCs||_i|_dS)N)Z_fw�	_services)�self�fw�r� /usr/lib/python3.6/fw_service.py�__init__szFirewallService.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rrrr	�__repr__ szFirewallService.__repr__cCs|jj�dS)N)r�clear)rrrr	�cleanup#szFirewallService.cleanupcCst|jj��S)N)�sortedr�keys)rrrr	�get_services(szFirewallService.get_servicescCs||jkrttj|��dS)N)rrrZINVALID_SERVICE)r�servicerrr	�
check_service+s
zFirewallService.check_servicecCs|j|�|j|S)N)rr)rrrrr	�get_service/s
zFirewallService.get_servicecCs||j|j<dS)N)r�name)r�objrrr	�add_service3szFirewallService.add_servicecCs|j|�|j|=dS)N)rr)rrrrr	�remove_service6s
zFirewallService.remove_serviceN)�__name__�
__module__�__qualname__r
rrrrrrrrrrr	rsN)�__all__ZfirewallrZfirewall.errorsr�objectrrrrr	�<module>s__pycache__/rich.cpython-36.pyc000064400000050640151731527050012342 0ustar003

��g8��@s�dddddddddd	d
ddd
ddddgZddlmZddlmZddlmZddlmZddlm	Z	Gdd�de
�ZGdd�de
�ZGdd�de
�Z
Gdd�de
�ZGdd�de�ZGdd�de
�ZGdd�de
�ZGdd�de
�ZGd d�de
�ZGd!d	�d	e
�ZGd"d
�d
e
�ZGd#d�de
�ZGd$d�de
�ZGd%d
�d
e
�ZGd&d�de�ZGd'd�de
�Zd(d)d/d1d+�ZGd,d�de
�ZGd-d�de
�Zd.S)2�Rich_Source�Rich_Destination�Rich_Service�	Rich_Port�
Rich_Protocol�Rich_Masquerade�Rich_IcmpBlock�
Rich_IcmpType�Rich_SourcePort�Rich_ForwardPort�Rich_Log�
Rich_Audit�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�
Rich_Limit�	Rich_Rule�)�	functions)�check_ipset_name)�REJECT_TYPES)�errors)�
FirewallErrorc@seZdZddd�Zdd�ZdS)rFcCs�||_|jdkrd|_||_|jdks0|jdkr8d|_n|jdk	rN|jj�|_||_|jdkrdd|_||_|jdkr�|jdkr�|jdkr�ttjd��dS)N�zno address, mac and ipset)�addr�mac�upper�ipset�invertrr�INVALID_RULE)�selfrrrr�r!�/usr/lib/python3.6/rich.py�__init__$s


zRich_Source.__init__cCsjd|jrdnd}|jdk	r*|d|jS|jdk	rB|d|jS|jdk	rZ|d|jSttjd��dS)Nz	source%s z NOTrzaddress="%s"zmac="%s"z
ipset="%s"zno address, mac and ipset)rrrrrrr)r �retr!r!r"�__str__5s


zRich_Source.__str__N)F)�__name__�
__module__�__qualname__r#r%r!r!r!r"r#s
c@seZdZddd�Zdd�ZdS)rFcCsV||_|jdkrd|_||_|jdkr,d|_||_|jdkrR|jdkrRttjd��dS)Nrzno address and ipset)rrrrrr)r rrrr!r!r"r#Bs

zRich_Destination.__init__cCsRd|jrdnd}|jdk	r*|d|jS|jdk	rB|d|jSttjd��dS)Nzdestination%s z NOTrzaddress="%s"z
ipset="%s"zno address and ipset)rrrrrr)r r$r!r!r"r%Ns

zRich_Destination.__str__N)F)r&r'r(r#r%r!r!r!r"rAs
c@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)�name)r r)r!r!r"r#YszRich_Service.__init__cCs
d|jS)Nzservice name="%s")r))r r!r!r"r%\szRich_Service.__str__N)r&r'r(r#r%r!r!r!r"rXsc@seZdZdd�Zdd�ZdS)rcCs||_||_dS)N)�port�protocol)r r*r+r!r!r"r#`szRich_Port.__init__cCsd|j|jfS)Nzport port="%s" protocol="%s")r*r+)r r!r!r"r%dszRich_Port.__str__N)r&r'r(r#r%r!r!r!r"r_sc@seZdZdd�ZdS)r	cCsd|j|jfS)Nz#source-port port="%s" protocol="%s")r*r+)r r!r!r"r%hszRich_SourcePort.__str__N)r&r'r(r%r!r!r!r"r	gsc@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)�value)r r,r!r!r"r#mszRich_Protocol.__init__cCs
d|jS)Nzprotocol value="%s")r,)r r!r!r"r%pszRich_Protocol.__str__N)r&r'r(r#r%r!r!r!r"rlsc@seZdZdd�Zdd�ZdS)rcCsdS)Nr!)r r!r!r"r#tszRich_Masquerade.__init__cCsdS)N�
masquerader!)r r!r!r"r%wszRich_Masquerade.__str__N)r&r'r(r#r%r!r!r!r"rssc@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)r))r r)r!r!r"r#{szRich_IcmpBlock.__init__cCs
d|jS)Nzicmp-block name="%s")r))r r!r!r"r%~szRich_IcmpBlock.__str__N)r&r'r(r#r%r!r!r!r"rzsc@seZdZdd�Zdd�ZdS)rcCs
||_dS)N)r))r r)r!r!r"r#�szRich_IcmpType.__init__cCs
d|jS)Nzicmp-type name="%s")r))r r!r!r"r%�szRich_IcmpType.__str__N)r&r'r(r#r%r!r!r!r"r�sc@seZdZdd�Zdd�ZdS)r
cCs<||_||_||_||_|jdkr(d|_|jdkr8d|_dS)Nr)r*r+�to_port�
to_address)r r*r+r.r/r!r!r"r#�s

zRich_ForwardPort.__init__cCs<d|j|j|jdkrd|jnd|jdkr4d|jndfS)Nz(forward-port port="%s" protocol="%s"%s%srz
 to-port="%s"z
 to-addr="%s")r*r+r.r/)r r!r!r"r%�szRich_ForwardPort.__str__N)r&r'r(r#r%r!r!r!r"r
�sc@seZdZddd�Zdd�ZdS)rNcCs||_||_||_dS)N)�prefix�level�limit)r r0r1r2r!r!r"r#�szRich_Log.__init__cCs>d|jrd|jnd|jr$d|jnd|jr6d|jndfS)Nz	log%s%s%sz prefix="%s"rz level="%s"z %s)r0r1r2)r r!r!r"r%�szRich_Log.__str__)NNN)r&r'r(r#r%r!r!r!r"r�s
c@seZdZddd�Zdd�ZdS)rNcCs
||_dS)N)r2)r r2r!r!r"r#�szRich_Audit.__init__cCsd|jrd|jndS)Nzaudit%sz %sr)r2)r r!r!r"r%�szRich_Audit.__str__)N)r&r'r(r#r%r!r!r!r"r�s
c@seZdZddd�Zdd�ZdS)r
NcCs
||_dS)N)r2)r r2r!r!r"r#�szRich_Accept.__init__cCsd|jrd|jndS)Nzaccept%sz %sr)r2)r r!r!r"r%�szRich_Accept.__str__)N)r&r'r(r#r%r!r!r!r"r
�s
c@s&eZdZddd�Zdd�Zdd�ZdS)	rNcCs||_||_dS)N)�typer2)r Z_typer2r!r!r"r#�szRich_Reject.__init__cCs,d|jrd|jnd|jr$d|jndfS)Nz
reject%s%sz
 type="%s"rz %s)r3r2)r r!r!r"r%�szRich_Reject.__str__cCsT|jrP|sttjd��|dkrP|jt|krPdjt|�}ttjd|j|f��dS)Nz9When using reject type you must specify also rule family.�ipv4�ipv6z, z%Wrong reject type %s.
Use one of: %s.)r4r5)r3rrrr�join)r �familyZvalid_typesr!r!r"�check�szRich_Reject.check)NN)r&r'r(r#r%r8r!r!r!r"r�s
c@seZdZdd�ZdS)rcCsd|jrd|jndS)Nzdrop%sz %sr)r2)r r!r!r"r%�szRich_Drop.__str__N)r&r'r(r%r!r!r!r"r�sc@s&eZdZddd�Zdd�Zdd�ZdS)	rNcCs||_||_dS)N)�setr2)r Z_setr2r!r!r"r#�szRich_Mark.__init__cCsd|j|jrd|jndfS)Nz
mark set=%s%sz %sr)r9r2)r r!r!r"r%�szRich_Mark.__str__cCs�|jdk	r|j}nttjd��d|krv|jd�}t|�dkrHttj|��tj|d�shtj|d�r�ttj|��ntj|�s�ttj|��dS)Nzno value set�/�r�)r9rrZINVALID_MARK�split�lenrZcheckUINT32)r �x�splitsr!r!r"r8�s


zRich_Mark.check)N)r&r'r(r#r%r8r!r!r!r"r�s
r<�<�)�s�m�h�dc@s�eZdZddd�Zdd�Zedd��Zejdd��Zed	d
��Zejdd
��Ze	dd
��Z
dd�Ze	dd��Zdd�Z
dd�ZdS)rNcCs||_||_dS)N)r,�burst)r r,rGr!r!r"r#�szRich_Limit.__init__cCs|j�|j�dS)N)�value_parse�burst_parse)r r!r!r"r8�szRich_Limit.checkcCs|jS)N)�_value)r r!r!r"r,�szRich_Limit.valuecCsf|dkrd|_dSy|j|�\}}Wntk
r<|}YnX|�d|��}t|dd�|krb||_dS)Nr:rJ)rJ�_value_parser�getattr)r r,�rate�duration�vr!r!r"r,�s
cCs|jS)N)�_burst)r r!r!r"rGszRich_Limit.burstcCs\|dkrd|_dSy|j|�}Wntk
r8|}Yn
Xt|�}t|dd�|krX||_dS)NrP)rP�_burst_parser�strrL)r rG�br!r!r"rGs
cCs�d}d|kr|jd�}|s(t|�dkr4ttj|��|\}}yt|�}Wnttj|��YnX|dkrv|dd�}|dks�|dkr�ttj|��dt||d
kr�ttjd|f��|dkr�|dkr�ttjd|f��||fS)Nr:r;�second�minute�hour�dayr<rCrDrErFi'rz%s too fastz%s too slow)rTrUrVrW)rCrDrErF)r=r>rr�
INVALID_LIMIT�int�DURATION_TO_MULT)r,r@rMrNr!r!r"rKs&
zRich_Limit._value_parsecCs|j|j�S)N)rKrJ)r r!r!r"rH:szRich_Limit.value_parsec	CsR|dkrdSyt|�}Wnttj|��YnX|dksB|dkrNttj|��|S)Nr<i���)rYrrrX)rGrSr!r!r"rQ=szRich_Limit._burst_parsecCs|j|j�S)N)rQrP)r r!r!r"rIKszRich_Limit.burst_parsecCs,d|j�d�}|jdk	r(|d|j��7}|S)Nz
limit value="�"z burst=)rJrP)r rCr!r!r"r%Ns
zRich_Limit.__str__)N)r&r'r(r#r8�propertyr,�setterrG�staticmethodrKrHrQrIr%r!r!r!r"r�s
c@s>eZdZdZdZddd�Zdd�Zd	d
�Zdd�Zd
d�Z	dS)ri�i�NrcCsV|dk	rt|�|_nd|_||_d|_d|_d|_d|_d|_d|_|rR|j	|�dS)N)
rRr7�priority�source�destination�element�log�audit�action�_import_from_string)r r7�rule_strr_r!r!r"r#XszRich_Rule.__init__cCs�g}x|tj|�D]n}d|krp|jd�}t|�dksF|dsF|drVttjd|��|j|d|dd��q|jd|i�qW|jddi�|S)	z Lexical analysis �=r;rr<zinternal error in _lexer(): %s)�	attr_name�
attr_valuerb�EOL)rZ	splitArgsr=r>rrr�append)r rg�tokens�r�attrr!r!r"�_lexeris
 
zRich_Rule._lexercCs�|sttjd��tj|�}d|_d|_d|_d|_d|_	d|_
d|_d|_|j
|�}|rv|djd�dkrvttjd��i}g}d}�x`||jd�dko�|dgk�s�||jd�}||jd�}||jd�}|�r�|dHk�r�ttjd|���n�|dIk�r�|dk�r|j�rttjd+��n�|dk�r<|j�r<ttjd,��n�|dJk�rf|j	�rfttjd-||j	f��nh|d"k�r�|j
�r�ttjd.��nH|d#k�r�|j�r�ttjd/��n(|dKk�r�|j�r�ttjd0||jf��nttjd1|��t|�dk�r�|t|�d2nd3}	|	d3k�r�|�r`|�r`|d	k�r2ttjd4��n,|dk�rJttjd5��nttjd6||f��n*d|k�r�ttjd7||f��n
|jd��nL|	dk�rD|d	k�r�|dLk�r�ttjd:|��||_n||dk�ryt|�|_Wn&tk
�rttjd;|��YnXn:|�r6|dk�rd<}
nd=||f}
ttj|
��n
|j|��n�|	dk�r�|dMk�rb|||<nV|dNk�rvd>|d
<nBt|jd
�|jd�|jd�|jd
d?��|_|j�|j�|d2}�n|	dk�r,|dOk�r�|||<nN|dPk�r�d>|d
<n:t|jd
�|jd�|jd
d?��|_|j�|j�|d2}�n�|	dk�rd|dk�rTt|�|_	|j�nttjd@���nv|	dk�r�|dk�r�t|�|_	|j�nttjdA���n>|	dk�r�|dQk�r�|||<n0t|jd�|jd��|_	|j�|j�|d2}�n�|	dk�r&|dk�rt|�|_	|j�nttjdB���n�|	dk�r^|dk�rNt|�|_	|j�nttjdC���n||	dk�r�t�|_	|j�|j�|d2}�nN|	d k�r�|dRk�r�|||<n@t|jd�|jd�|jd�|jd��|_	|j�|j�|d2}�n�|	d!k�r@|dSk�r|||<n0t|jd�|jd��|_	|j�|j�|d2}�n�|	d"k�r�|dTk�r^|||<nN|d(k�rt|jd(�n8t |jd�|jd�|jd(��|_
|j�|j�|d2}�n*|	d#k�r�|d(k�r�|jd(�n(t!|jd(��|_|j�|j�|d2}�n�|	d$k�rH|d(k�r|jd(�n(t"|jd(��|_|j�|j�|d2}�n�|	d%k�r�|d(k�rh|jd(�n(t#|jd(��|_|j�|j�|d2}�nF|	d&k�r�|dk�r�|||<nF|d(k�r�|jd(�n0t$|jd�|jd(��|_|j�|j�|d2}n�|	d'k�r`|dk�r|||<nF|d(k�r.|jd(�n0t%|jd�|jd(��|_|j�|j�|d2}nz|	d(k�r�|dUk�r�||dD|��<nVdE|k�r�ttjdF��t&|dE|jdG��|d(<|jdEd�|jdGd�|j�|d2}|d2}q�W|j'�dS)VNz
empty rulerrbrk�rulerirjr_r7�addressrrrr,r*r+�to-port�to-addrr)r0r1r3r9rGzbad attribute '%s'r`ra�service�
icmp-block�	icmp-typer-�forward-port�source-portrcrd�accept�drop�reject�markr2�not�NOTzmore than one 'source' elementz#more than one 'destination' elementzFmore than one element. There cannot be both '%s' and '%s' in one rule.zmore than one 'log' elementzmore than one 'audit' elementzOmore than one 'action' element. There cannot be both '%s' and '%s' in one rule.zunknown element %sr<rz0'family' outside of rule. Use 'rule family=...'.z4'priority' outside of rule. Use 'rule priority=...'.z:'%s' outside of any element. Use 'rule <element> %s= ...'.z,'%s' outside of rule. Use 'rule ... %s ...'.r4r5zH'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead.z(invalid 'priority' attribute value '%s'.zdwrong 'protocol' usage. Use either 'rule protocol value=...' or  'rule [forward-]port protocol=...'.zDattribute '%s' outside of any element. Use 'rule <element> %s= ...'.TFzinvalid 'protocol' elementzinvalid 'service' elementzinvalid 'icmp-block' elementzinvalid 'icmp-type' elementzlimit.zlimit.valuezinvalid 'limit' elementzlimit.burst)r_r7rrrrrr,r*r+rsrtr)r0r1r3r9rG)rqr`rar+rur*rvrwr-rxryrcrdrzr{r|r}r2r~rrk)r+rur*rvrwr-rxry)rzr{r|r})r4r5)rrrrr)r~r)rrrr)r~r)r*r+)r*r+rsrt)r*r+)r0r1)r,rG)(rrrrZstripNonPrintableCharactersr_r7r`rarbrcrdrerp�getr>rlrY�
ValueError�INVALID_PRIORITYr�pop�clearrrrrrrrr
r	rrr
rrrrr8)r rgrmZattrsZin_elements�indexrbrirjZ
in_elementZerr_msgr!r!r"rfzs�

""













*




"






















(






 




















zRich_Rule._import_from_stringc	Cs`|jdk	r"|jd kr"ttj|j��|jdkrn|jdk	rB|jjdk	sL|jdk	rVttj��t|j	�t
krnttj��|j|jks�|j|j
kr�ttjd|j|j
f��|j	dko�|jdks�|jdk	o�|jdk�r
|jdkr�ttjd��|jdko�|jdko�|jdk�r
ttjd��t|j	�tt
tgk�rP|jdk�rP|jdk�rP|jdk�rPttjd��|jdk	�rj|jjdk	�r�|jdk�r�ttj��|jjdk	�r�ttjd��|jjdk	�r�ttjd	��tj|j|jj��sjttjt|jj���n�|jjdk	�r,|jjdk	�rttjd
��tj|jj��sjttjt|jj���n>|jjdk	�r^t|jj��sjttjt|jj���nttjd��|jdk	�r|jjdk	�r�|jdk�r�ttj��|jjdk	�r�ttjd	��tj|j|jj��sttjt|jj���n>|jjdk	�rt|jj��sttjt|jj���nttjd��t|j	�t k�rd|j	j!dk�sLt"|j	j!�d
k�r`ttj#t|j	j!����n�t|j	�t$k�r�tj%|j	j&��s�ttj'|j	j&��|j	j(d!k�r`ttj)|j	j(���n�t|j	�t*k�r�tj+|j	j,��s`ttj)|j	j,���nvt|j	�tk�r<|jdk	�rttjd��|jdk	�r`|jjdk	�r`ttjd���n$t|j	�tk�r�|j	j!dk�slt"|j	j!�d
k�r�ttj-t|j	j!���|j�r`ttjd���n�t|j	�t.k�r�|j	j!dk�s�t"|j	j!�d
k�r`ttj-t|j	j!����n�t|j	�t
k�r�tj%|j	j&��sttj'|j	j&��|j	j(d"k�r.ttj)|j	j(��|j	j/dk�rZ|j	j0dk�rZttj'|j	j/��|j	j/dk�r�tj%|j	j/��r�ttj'|j	j/��|j	j0dk�r�tj1|j|j	j0��r�ttj|j	j0��|jdk�r�ttj��|jdk	�r`ttjd��nrt|j	�t2k�r>tj%|j	j&��sttj'|j	j&��|j	j(d#k�r`ttj)|j	j(��n"|j	dk	�r`ttjdt|j	���|jdk	�r�|jj3�r�|jj3d$k�r�ttj4|jj3��|jj5dk	�r�|jj5j6�|jdk	�r�t|j�t7t8t9gk�r�ttj:t|j���|jj5dk	�r�|jj5j6�|jdk	�r\t|j�t8k�r(|jj6|j�nt|j�t;k�rB|jj6�|jj5dk	�r\|jj5j6�dS)%Nr4r5z/'priority' attribute must be between %d and %d.rzno element, no actionz%no element, no source, no destinationzno action, no log, no auditzaddress and maczaddress and ipsetz
mac and ipsetzinvalid sourcezinvalid destinationr<�tcp�udp�sctp�dccpzmasquerade and actionzmasquerade and mac sourcezicmp-block and actionrzforward-port and actionzUnknown element %s�emerg�alert�crit�error�warning�notice�info�debug)r4r5)r�r�r�r�)r�r�r�r�)r�r�r�r�)r�r�r�r�r�r�r�r�)<r7rrZINVALID_FAMILYr`rraZMISSING_FAMILYr3rbr
r_�priority_min�priority_maxr�rcrerrrrdrrrZ
check_addressZINVALID_ADDRrRZ	check_macZINVALID_MACrZ
INVALID_IPSETZINVALID_DESTINATIONrr)r>ZINVALID_SERVICErZ
check_portr*ZINVALID_PORTr+ZINVALID_PROTOCOLrZ
checkProtocolr,ZINVALID_ICMPTYPErr.r/Zcheck_single_addressr	r1ZINVALID_LOG_LEVELr2r8r
rrZINVALID_AUDIT_TYPEr)r r!r!r"r8hs�




 
 



   


zRich_Rule.checkcCs�d}|jr|d|j7}|jr,|d|j7}|jr@|d|j7}|jrT|d|j7}|jrh|d|j7}|jr||d|j7}|jr�|d|j7}|jr�|d|j7}tj	r�tj
|�S|S)Nrqz priority="%d"z family="%s"z %s)r_r7r`rarbrcrdrerZPY2Zu2b)r r$r!r!r"r%s$zRich_Rule.__str__i���)NNr)
r&r'r(r�r�r#rprfr8r%r!r!r!r"rTs
o-Nii�i�Q)�__all__ZfirewallrZfirewall.core.ipsetrZfirewall.core.baserrZfirewall.errorsr�objectrrrrr	rrrrr
rrr
rrrrZrrr!r!r!r"�<module>s@
d__pycache__/modules.cpython-36.opt-1.pyc000064400000005500151731527050014017 0ustar003

��g��@sBdZdgZddlmZddlmZddlmZGdd�de�Z	dS)zmodules backend�modules�)�runProg)�log)�COMMANDSc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCstd|_td|_dS)NZmodprobeZrmmod)r�
_load_command�_unload_command)�self�r	�/usr/lib/python3.6/modules.py�__init__s
zmodules.__init__cCs
d|jS)Nz%s)�	__class__)rr	r	r
�__repr__$szmodules.__repr__cCs�g}i}y�tdd��p}xh|D]`}|s&P|j�}|j�}|j|d�|ddkrp|djd�dd	�||d<qg||d<qWWdQRXWntk
r�YnX||fS)
z6 get all loaded kernel modules and their dependencies z
/proc/modules�rr��-�,N����)�open�strip�split�append�FileNotFoundError)r�mods�deps�f�lineZsplitsr	r	r
�loaded_modules's 
 zmodules.loaded_modulescCs"tjd|j|j|�t|j|g�S)Nz	%s: %s %s)r�debug2rrr)r�moduler	r	r
�load_module<szmodules.load_modulecCs"tjd|j|j|�t|j|g�S)Nz	%s: %s %s)rrrrr)rrr	r	r
�
unload_module@szmodules.unload_modulecCsT||krdSx0||D]$}|j|||�||kr|j|�qW||krP|j|�dS)z  get all dependants of a module N)�get_depsr)rrr�ret�modr	r	r
r"Dszmodules.get_depscCs�g}|j�\}}|jd||�x*dD]"}||kr$|j|�|jd|�q$Wx^|D]V}|dks�|jd�s�|jd	�s�|jd
�s�|jd�s�|jd�s�|jd
�rP|j|||�qPW|S)z) get all loaded firewall-related modules Znf_conntrack�nf_conntrack_ipv4�nf_conntrack_ipv6r�	ip_tables�
ip6_tables�ebtablesZiptable_Z	ip6table_Znf_Zxt_Zipt_Zip6t_)r%r&r)r'r(r))rr"�remove�insert�
startswith)rrZmods2rZbad_bad_moduler$r	r	r
�get_firewall_modulesOs


zmodules.get_firewall_modulescCs>x8|j�D],}|j|�\}}|dkr
tjd||f�q
WdS)z% unload all firewall-related modules rz Failed to unload module '%s': %sN)r-r!rZdebug1)rrZstatusr#r	r	r
�unload_firewall_modulesdszmodules.unload_firewall_modulesN)�__name__�
__module__�__qualname__rr
rr r!r"r-r.r	r	r	r
rsN)
�__doc__�__all__Zfirewall.core.progrZfirewall.core.loggerrZfirewall.configr�objectrr	r	r	r
�<module>s
__pycache__/fw_policies.cpython-36.opt-1.pyc000064400000004432151731527050014655 0ustar003

��g�
�@sVdgZddlmZddlmZddlmZddlmZddlm	Z	Gdd�de
�ZdS)	�FirewallPolicies�)�config)�log)�LockdownWhitelist)�errors)�
FirewallErrorc@sDeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dS)rcCsd|_ttj�|_dS)NF)�	_lockdownrrZLOCKDOWN_WHITELIST�lockdown_whitelist)�self�r�!/usr/lib/python3.6/fw_policies.py�__init__szFirewallPolicies.__init__cCsd|j|j|jfS)Nz
%s(%r, %r))�	__class__rr	)r
rrr�__repr__#s
zFirewallPolicies.__repr__cCsd|_|jj�dS)NF)rr	�cleanup)r
rrrr'szFirewallPolicies.cleanupcCs�|dkr2tjd|�|jj|�r�tjd�dSn�|dkrdtjd|�|jj|�r�tjd�dSnb|dkr�tjd	|�|jj|�r�tjd
�dSn0|dkr�tjd|�|jj|�r�tjd
�dSdS)N�contextz#Doing access check for context "%s"zcontext matches.TZuidzDoing access check for uid %dzuid matches.�userz Doing access check for user "%s"z
user matches.Zcommandz#Doing access check for command "%s"zcommand matches.F)rZdebug2r	Z
match_contextZdebug3Z	match_uidZ
match_userZ
match_command)r
�key�valuerrr�access_check-s*



zFirewallPolicies.access_checkcCs|jrttjd��d|_dS)Nzenable_lockdown()T)rrrZALREADY_ENABLED)r
rrr�enable_lockdownDsz FirewallPolicies.enable_lockdowncCs|jsttjd��d|_dS)Nzdisable_lockdown()F)rrrZNOT_ENABLED)r
rrr�disable_lockdownIsz!FirewallPolicies.disable_lockdowncCs|jS)N)r)r
rrr�query_lockdownNszFirewallPolicies.query_lockdownN)
�__name__�
__module__�__qualname__r
rrrrrrrrrrrsN)�__all__ZfirewallrZfirewall.core.loggerrZ#firewall.core.io.lockdown_whitelistrrZfirewall.errorsr�objectrrrrr�<module>s__pycache__/fw_zone.cpython-36.opt-1.pyc000064400000077522151731527050014033 0ustar003

��gy��@s�ddlZddlZddlmZmZmZddlmZddlm	Z	ddl
mZddlm
Z
mZmZmZmZmZmZmZmZddlmZmZmZddlmZdd	lmZdd
lmZGdd�de �Z!dS)
�N)�	SHORTCUTS�DEFAULT_ZONE_TARGET�SOURCE_IPSET_TYPES)�FirewallTransaction)�Policy)�log)	�Rich_Service�	Rich_Port�
Rich_Protocol�Rich_SourcePort�Rich_ForwardPort�Rich_IcmpBlock�
Rich_IcmpType�Rich_Masquerade�	Rich_Mark)�checkIPnMask�
checkIP6nMask�	check_mac)�errors)�
FirewallError)�LastUpdatedOrderedDictc@sNeZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zdd
�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zd�dd �Zd!d"�Zd#d$�Zd%d&�Zd�d'd(�Zd)d*�Zd+d,�Zd-d.�Zd�d/d0�Zd�d1d2�Zd3d4�Zd5d6�Zd7d8�Zd9d:�Zd;d<�Z d=d>�Z!d�d@dA�Z"dBdC�Z#d�dDdE�Z$d�dFdG�Z%d�dHdI�Z&dJdK�Z'dLdM�Z(dNdO�Z)d�dQdR�Z*d�dSdT�Z+d�dUdV�Z,dWdX�Z-d�dYdZ�Z.d�d[d\�Z/d]d^�Z0d_d`�Z1dadb�Z2d�dcdd�Z3dedf�Z4dgdh�Z5didj�Z6dkdl�Z7dmdn�Z8dodp�Z9d�dqdr�Z:dsdt�Z;dudv�Z<dwdx�Z=d�dydz�Z>d{d|�Z?d}d~�Z@dd��ZAd�d�d��ZBd�d��ZCd�d��ZDd�d��ZEd�d��ZFd�d�d��ZGd�d��ZHd�d��ZId�d��ZJd�d�d��ZKd�d��ZLd�d��ZMd�d��ZNd�d�d��ZOd�d��ZPd�d��ZQd�d�d��ZRd�d�d��ZSd�d�d��ZTd�d��ZUd�d�d��ZVd�d��ZWd�d��ZXd�d��ZYd�d�d��ZZd�d��Z[d�d��Z\d�d��Z]d�d��Z^d�d��Z_d�d�d��Z`d�d��Zad�d�d„Zbd�dĄZcd�dƄZddS)��FirewallZonercCs||_i|_i|_dS)N)�_fw�_zones�_zone_policies)�self�fw�r�/usr/lib/python3.6/fw_zone.py�__init__&szFirewallZone.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)rrrr�__repr__+szFirewallZone.__repr__cCs|jj�|jj�dS)N)r�clearr)rrrr�cleanup.s
zFirewallZone.cleanupcCs
t|j�S)N)rr)rrrr�new_transaction2szFirewallZone.new_transactioncCsdj||d�S)Nzzone_{fromZone}_{toZone})�fromZone�toZone)�format)rr%r&rrr�policy_name_from_zones5sz#FirewallZone.policy_name_from_zonescCst|jj��S)N)�sortedr�keys)rrrr�	get_zones:szFirewallZone.get_zonescCs8g}x.|j�D]"}|j|�s&|j|�r|j|�qW|S)N)r+�list_interfaces�list_sources�append)rZactive_zones�zonerrr�get_active_zones=s
zFirewallZone.get_active_zonescCs6|j|�}x&|jD]}||j|jdkr|SqWdS)N�
interfaces)�_FirewallZone__interface_idr�settings)r�	interface�interface_idr/rrr�get_zone_of_interfaceDs

z"FirewallZone.get_zone_of_interfacecCs6|j|�}x&|jD]}||j|jdkr|SqWdS)N�sources)�_FirewallZone__source_idrr3)r�source�	source_idr/rrr�get_zone_of_sourceLs

zFirewallZone.get_zone_of_sourcecCs|jj|�}|j|S)N)r�
check_zoner)rr/�zrrr�get_zoneTszFirewallZone.get_zonecCsBt�}|j|_|j||�|_|j|_|j|_|g|_|g|_�x�dD�]�}||jkr~|d	kr~|dkr~t	||t
jt||���qD|d
kr�||jkr�|d
kr�t	||t
jt||���qD||jko�|d
ko�|dk�r�t	||t
jt||���qD|dkrDg|_
xB|j
D]8}|j||�}||j|j|�k�r�|j
jt
j|���q�WqDW|S)N�services�ports�
masquerade�
forward_ports�source_ports�icmp_blocks�rules�	protocols�HOST�ANY)r?r@rArBrCrDrErF)r?r@rCrDrF)rA)rDrB)rE)r�nameZderived_from_zoner(�ZONE_POLICY_PRIORITYZpriority�targetZ
ingress_zonesZegress_zones�setattr�copy�deepcopy�getattrrE�_rich_rule_to_policiesr.)r�z_objr%r&�p_objZsetting�ruleZcurrent_policyrrr�policy_obj_from_zone_objXs6

z%FirewallZone.policy_obj_from_zone_objcCs�dd�d	D�|_||j|j<g|j|j<xX|jdfd|jf|jdfgD]8\}}|j|||�}|jjj|�|j|jj|j�qFW|j	|j�dS)
NcSsi|]}t�|�qSr)r)�.0�xrrr�
<dictcomp>sz)FirewallZone.add_zone.<locals>.<dictcomp>r1r7�icmp_block_inversion�forwardrGrH)r1r7rXrY)
r3rrIrrTr�policyZ
add_policyr.�copy_permanent_to_runtime)r�objr%r&rRrrr�add_zone~s

zFirewallZone.add_zonecCsn|j|}x|jD]}|j||dd�qWx|jD]}|j||dd�q2W|jrZ|j|�|jrj|j|�dS)NF)�allow_apply)	rr1�
add_interfacer7�
add_sourcerY�add_forwardrX�add_icmp_block_inversion)rr/r\�argrrrr[�s

z&FirewallZone.copy_permanent_to_runtimecCs8|j|}|jr|j|�|jj�|j|=|j|=dS)N)r�applied�unapply_zone_settingsr3r"r)rr/r\rrr�remove_zone�s


zFirewallZone.remove_zoneNcCsVxP|j�D]D}|j|}t|j�dks4t|j�dkr
tjd|�|j||d�q
WdS)NrzApplying zone '%s')�use_transaction)r+r�lenr1r7r�debug1�apply_zone_settings)rrgr/rQrrr�apply_zones�s

zFirewallZone.apply_zonescCs|j|}||_dS)N)rrd)rr/rdr\rrr�set_zone_applied�s
zFirewallZone.set_zone_appliedcCs�d|krdS|jd�}t|�dkr&dSd}x tD]}|dt|kr0|}q0W|dk	r�|d|j�krhdSt|�dks�t|�dkr�|ddkr�|d|fSdS)N�_�r���prer�deny�allow�post)rqrrrrsrt)�splitrhrr+)r�chainZsplits�_chainrVrrr�zone_from_chain�s 

zFirewallZone.zone_from_chaincCst|j|�}|dkrdS|\}}|d	kr0|}d}n4|d
krB|}d}n"|dkrTd}|}nttjd|��|j||�|fS)N�
PREROUTING�
FORWARD_INrH�INPUTrG�POSTROUTING�FORWARD_OUTz&chain '%s' can't be mapped to a policy)ryrz)r{)r|r})rxrrZ
INVALID_CHAINr()rrvrVr/rwr%r&rrr�policy_from_chain�s
zFirewallZone.policy_from_chainc	Csj|dkrf|j|�}|dk	rf|j|�\}}|dkr:|j�}n|}|jjj|d|||�|dkrf|jd�dS)N�ipv4�ipv6T)rr�)r~r$rrZZgen_chain_rules�execute)	r�ipv�tablervrgrVrZrw�transactionrrr�create_zone_base_by_chain�s

z&FirewallZone.create_zone_base_by_chaincCstj�||d�}|S)N)Zdate�sender�timeout)�time)rr�r��retrrrZ__gen_settings�szFirewallZone.__gen_settingscCs|j|�jS)N)r>r3)rr/rrr�get_settings�szFirewallZone.get_settingscCs�|j|�}x�|D]z}xt||D]h}|dkr<|j||||�q|dkr`|j|||d|d|�q|dkrlqq|dkrvqtjd|||�qWqW|r�|j|||�dS)Nr1r7rrorXrYz3Zone '%s': Unknown setting '%s:%s', unable to apply)r��
_interface�_sourcerZwarning�_icmp_block_inversion)r�enabler/r�r3�key�argsrrr�_zone_settingss

zFirewallZone._zone_settingscCs�|jj|�}|j|}|jr dSd|_|dkr8|j�}n|}x2|j|D]$}tjd||�|jjj	||d�qHW|j
d||�|dkr�|jd�dS)NTz+Applying policy (%s) derived from zone '%s')rg)rr<rrdr$rrrirZ�apply_policy_settingsr�r�)rr/rg�_zoner\r�rZrrrrjs

z FirewallZone.apply_zone_settingscCs�|jj|�}|j|}|js dS|dkr2|j�}n|}x$|j|D]}|jjj||d�qBW|jd||�|dkr||j	d�dS)N)rgFT)
rr<rrdr$rrZ�unapply_policy_settingsr�r�)rr/rgr�r\r�rZrrrre,s

z"FirewallZone.unapply_zone_settingscCs~|j|�}|j|�}g}x\td�D]P}|j|d|krZ|jtjt||j|d���q"|j||j|d�q"Wt|�S)zH
        :return: exported config updated with runtime settings
        �r)	r>�get_config_with_settings_dict�rangeZIMPORT_EXPORT_STRUCTUREr.rMrNrO�tuple)rr/r\Z	conf_dictZ	conf_list�irrr�get_config_with_settings?s

"z%FirewallZone.get_config_with_settingsc
Cs�|j|�j�}|dtkr"d|d<|j|�|j|�|j|�|j|�|j|�|j|�|j	|�|j
|�|j|�|j|�|j
|�|j|�d�}|jj||�S)zH
        :return: exported config updated with runtime settings
        rK�default)r?r@rDrArBr1r7�	rules_strrFrCrXrY)r>Zexport_config_dictr�
list_services�
list_ports�list_icmp_blocks�query_masquerade�list_forward_portsr,r-�
list_rules�list_protocols�list_source_ports�query_icmp_block_inversion�
query_forwardrZ'combine_runtime_with_permanent_settings)rr/Z	permanentZruntimerrrr�Os z*FirewallZone.get_config_with_settings_dictc
sddlm�d��fdd�	}��fdd�}�j�jf�j�jf�j�jf�j�j	f�j
�jf�j�j
f�j�jf||f�j�jf�j�jf�j�jf�j�jfd�}�j|�}�jj||�\}}	xv|	D]n}
t|	|
t��r$xX|	|
D]:}t|t��r||
d|f|��q�||
d||�q�Wq�||
d|�q�Wx�|D]�}
t||
t��r�x�||
D]l}|
dk�r�||
d|||d�nDt|t��r�||
d|f|�d|d��n||
d||d|d��q\Wn6|
dk�r�||
d||d�n||
d|d|d��q>WdS)Nr)�	Rich_Rulecs�j|�|d�d|d�dS)N)�rule_strr)r�r�)�add_rule)r/r�r�r�)r�rrr�add_rule_wrapperhszDFirewallZone.set_config_with_settings_dict.<locals>.add_rule_wrappercs�j|�|d��dS)N)r�)�remove_rule)r/r�)r�rrr�remove_rule_wrapperjszGFirewallZone.set_config_with_settings_dict.<locals>.remove_rule_wrapper)r?r@rDrArBr1r7r�rFrCrXrYror1r7)r�)r�r�rX)rN)r1r7)rX)�firewall.core.richr��add_service�remove_service�add_port�remove_port�add_icmp_block�remove_icmp_block�add_masquerade�remove_masquerade�add_forward_port�remove_forward_portr_�remove_interfacer`�
remove_source�add_protocol�remove_protocol�add_source_port�remove_source_portrb�remove_icmp_block_inversionra�remove_forwardr�rZget_added_and_removed_settings�
isinstance�listr�)rr/r3r�r�r�Z
setting_to_fnZold_settingsZadd_settingsZremove_settingsr�r�r)r�rr�set_config_with_settings_dictesF













  
z*FirewallZone.set_config_with_settings_dictcCs|jj|�dS)N)r�check_interface)rr4rrrr��szFirewallZone.check_interfacecCs\|jj|�}|j|}|j|�}||jdkrX|jd|}d|krX|ddk	rX|dSdS)Nr1r�)rr<rr2r3)rr/r4r��_objr5r3rrr�interface_get_sender�s

z!FirewallZone.interface_get_sendercCs|j|�|S)N)r�)rr4rrrZ__interface_id�s
zFirewallZone.__interface_idTc
Cs|jj�|jj|�}|j|}|j|�}||jdkrLttjd||f��|j	|�dk	rjttj
d|��tjd||f�|dkr�|j
�}	n|}	|jr�|r�|j||	d�|	j|j|d�|r�|jd|||	�|j||||�|	j|j||�|dk�r|	jd�|S)Nr1z'%s' already bound to '%s'z'%s' already bound to a zonez&Setting zone of interface '%s' to '%s')rgFT)r�check_panicr<rr2r3rr�ZONE_ALREADY_SETr6�
ZONE_CONFLICTrrir$rdrj�add_failrlr��!_FirewallZone__register_interface�#_FirewallZone__unregister_interfacer�)
rr/r4r�rgr^r�r�r5r�rrrr_�s8









zFirewallZone.add_interfacecCs6|jd|�|jd|<|p"|dk|jd|d<dS)Nrr1��__default__)�_FirewallZone__gen_settingsr3)rr�r5r/r�rrrZ__register_interface�sz!FirewallZone.__register_interfacecCsR|jj�|j|�}|jj|�}||kr,|S|dk	r@|j||�|j|||�}|S)N)rr�r6r<r�r_)rr/r4r��	_old_zone�	_new_zoner�rrr�change_zone_of_interface�s

z%FirewallZone.change_zone_of_interfacecCsz|jj�|dkr|j�}n|}|j||�|jd|d|dd�|dk	rd|dkrd|jd|d|dd�|dkrv|jd�dS)NT�+)r.r�F)rr�r$rjr�r�)rZold_zoneZnew_zonergr�rrr�change_default_zone�s

z FirewallZone.change_default_zonec	Cs�|jj�|j|�}|dkr,ttjd|��|dkr8|n
|jj|�}||krbttjd|||f��|dkrt|j�}n|}|j	|}|j
|�}|j|j||�|j
d|||�|dkr�|jd�|S)Nz'%s' is not in any zoner�z"remove_interface(%s, %s): zoi='%s'FT)rr�r6rrZUNKNOWN_INTERFACEr<r�r$rr2�add_postr�r�r�)	rr/r4rgZzoir�r�r�r5rrrr��s(






zFirewallZone.remove_interfacecCs||jdkr|jd|=dS)Nr1)r3)rr�r5rrrZ__unregister_interfacesz#FirewallZone.__unregister_interfacecCs|j|�|j|�dkS)Nr1)r2r�)rr/r4rrr�query_interfaceszFirewallZone.query_interfacecCs|j|�dj�S)Nr1)r�r*)rr/rrrr,"szFirewallZone.list_interfacesFcCsxt|�rdSt|�rdSt|�r$dS|jd�rh|j|dd��|rV|j|dd��|j|dd��Sttj	|��dS)Nrr�r�zipset:�)
rrr�
startswith�_check_ipset_type_for_source�_check_ipset_applied�
_ipset_familyrrZINVALID_ADDR)rr9rdrrr�check_source's
zFirewallZone.check_sourcecCs|j||d�}||fS)N)rd)r�)rr9rdr�rrrZ__source_id6szFirewallZone.__source_idc
Cs|jj�|jj|�}|j|}t|�r0|j�}|j||d�}||jdkr`tt	j
d||f��|j|�dk	r~tt	jd|��|dkr�|j
�}	n|}	|jr�|r�|j||	d�|	j|j|d�|r�|jd||d|d	|	�|j||||�|	j|j||�|dk�r|	jd�|S)
N)rdr7z'%s' already bound to '%s'z'%s' already bound to a zone)rgFTrro)rr�r<rr�upperr8r3rrr�r;r�r$rdrjr�rlr��_FirewallZone__register_source� _FirewallZone__unregister_sourcer�)
rr/r9r�rgr^r�r�r:r�rrrr`:s4





zFirewallZone.add_sourcecCs6|jd|�|jd|<|p"|dk|jd|d<dS)Nrr7r�r�)r�r3)rr�r:r/r�rrrZ__register_sourceaszFirewallZone.__register_sourcecCsb|jj�|j|�}|jj|�}||kr,|St|�r<|j�}|dk	rP|j||�|j|||�}|S)N)rr�r;r<rr�r�r`)rr/r9r�r�r�r�rrr�change_zone_of_sourcegs

z"FirewallZone.change_zone_of_sourcec	Cs�|jj�t|�r|j�}|j|�}|dkr<ttjd|��|dkrH|n
|jj|�}||krrttj	d|||f��|dkr�|j
�}n|}|j|}|j|�}|j
|j||�|jd||d|d|�|dkr�|jd�|S)Nz'%s' is not in any zoner�zremove_source(%s, %s): zos='%s'FrroT)rr�rr�r;rrZUNKNOWN_SOURCEr<r�r$rr8r�r�r�r�)	rr/r9rgZzosr�r�r�r:rrrr�ys,






zFirewallZone.remove_sourcecCs||jdkr|jd|=dS)Nr7)r3)rr�r:rrrZ__unregister_source�sz FirewallZone.__unregister_sourcecCs(t|�r|j�}|j|�|j|�dkS)Nr7)rr�r8r�)rr/r9rrr�query_source�szFirewallZone.query_sourcecCsdd�|j|�dj�D�S)NcSsg|]}|d�qS)ror)rU�krrr�
<listcomp>�sz-FirewallZone.list_sources.<locals>.<listcomp>r7)r�r*)rr/rrrr-�szFirewallZone.list_sourcescs�x��jj�D]�}|jsqxP�j|D]B}x<�jjj|�D]*\}}	|j||||||	|�}
|j||
�q8Wq$W�j|d�}�j	|�dr|d
kr|j
|||d|d�}
|j||
�qWxΈjjj�D]�}|�jjj|�kr�|�jjj
|�kr�q�|�jjj�k�rd�jjj|�j�rd|�r<t�j|��dk�r<�jjj||d�n&�jjjd	||�|j�fd
d�|�q�|r�|j�fdd�|�q�WdS)NrHrYr��*�filter)r4ro)rgFcs |�jjj�ko�jjjd|�S)NT)rrZ�)get_active_policies_not_derived_from_zone�!_ingress_egress_zones_transaction)�p)rrr�<lambda>�sz)FirewallZone._interface.<locals>.<lambda>cs|�jjj�ko�jjj|�S)N)rrZr�r�)r�)rrrr��s)r�r�)r�enabled_backends�policies_supportedrrZ�#_get_table_chains_for_zone_dispatchZ!build_zone_source_interface_rules�	add_rulesr(r��build_zone_forward_rules�"get_policies_not_derived_from_zone�list_ingress_zones�list_egress_zonesr��
get_policyrdrhr,r��_ingress_egress_zonesr�)rr�r/r4r�r.�backendrZr�rvrEr)rrr��s2$zFirewallZone._interfacecCs$|j|�dkrdS|jjj|dd�S)Nzhash:macF)rd)�_ipset_typer�ipsetZ
get_family)rrIrrrr��szFirewallZone._ipset_familycCs|jjj|dd�S)NF)rd)rr�Zget_type)rrIrrrr��szFirewallZone._ipset_typecCsdj|g|jjj|��S)N�,)�joinrr�Z
get_dimension)rrI�flagrrr�_ipset_match_flags�szFirewallZone._ipset_match_flagscCs|jjj|�S)N)rr�Z
check_applied)rrIrrrr��sz!FirewallZone._check_ipset_appliedcCs*|j|�}|tkr&ttjd||f��dS)Nz.ipset '%s' with type '%s' not usable as source)r�rrrZ
INVALID_IPSET)rrIZ_typerrrr��s
z)FirewallZone._check_ipset_type_for_sourcec
s�x�|r�jj|�gn�jj�D]�}|js*qxN�j|D]@}x:�jjj|�D](\}}	|j||||||	�}
|j||
�qJWq6W�j	|d�}�j
|�dr|j|||d|d�}
|j||
�qWxΈjjj�D]�}|�jjj
|�kr�|�jjj|�kr�q�|�jjj�k�rl�jjj|�j�rl|�rDt�j|��dk�rD�jjj||d�n&�jjjd||�|j�fdd	�|�q�|r�|j�fd
d	�|�q�WdS)NrHrYr�)r9ro)rgFcs |�jjj�ko�jjjd|�S)NT)rrZr�r�)r�)rrrr�sz&FirewallZone._source.<locals>.<lambda>cs|�jjj�ko�jjj|�S)N)rrZr�r�)r�)rrrr�
s)r�get_backend_by_ipvr�r�rrZr�Zbuild_zone_source_address_rulesr�r(r�r�r�r�r�r�r�rdrhr-r�r�r�)rr�r/r�r9r�r�rZr�rvrEr)rrr��s2"$zFirewallZone._sourcecCs0|jj|�}|j|d�}|jjj||||�|S)NrG)rr<r(rZr�)rr/�servicer�r��p_namerrrr�
szFirewallZone.add_servicecCs,|jj|�}|j|d�}|jjj||�|S)NrG)rr<r(rZr�)rr/r�r�rrrr�szFirewallZone.remove_servicecCs(|jj|�}|j|d�}|jjj||�S)NrG)rr<r(rZ�
query_service)rr/r�r�rrrr�szFirewallZone.query_servicecCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr�szFirewallZone.list_servicescCs2|jj|�}|j|d�}|jjj|||||�|S)NrG)rr<r(rZr�)rr/�port�protocolr�r�r�rrrr�#szFirewallZone.add_portcCs.|jj|�}|j|d�}|jjj|||�|S)NrG)rr<r(rZr�)rr/r�r�r�rrrr�)szFirewallZone.remove_portcCs*|jj|�}|j|d�}|jjj|||�S)NrG)rr<r(rZ�
query_port)rr/r�r�r�rrrr/szFirewallZone.query_portcCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr�4szFirewallZone.list_portscCs2|jj|�}|j|d�}|jjj|||||�|S)NrG)rr<r(rZr�)rr/�source_portr�r�r�r�rrrr�9szFirewallZone.add_source_portcCs.|jj|�}|j|d�}|jjj|||�|S)NrG)rr<r(rZr�)rr/rr�r�rrrr�?szFirewallZone.remove_source_portcCs*|jj|�}|j|d�}|jjj|||�S)NrG)rr<r(rZ�query_source_port)rr/rr�r�rrrrEszFirewallZone.query_source_portcCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr�JszFirewallZone.list_source_portscCs�|jj|�}t|j�tkr(|j|d�gSt|j�ttt	t
gkrL|j|d�gSt|j�ttgkrv|j|d�|j|d�gSt|j�t
gkr�|j|d�gSt|j�tgkr�|jd|�gS|jdkr�|j|d�gStdt|j���dS)NrHrGz Rich rule type (%s) not handled.)rr<�type�actionrr(�elementrr	r
rr
rrrr)rr/rSrrrrPOs 

z#FirewallZone._rich_rule_to_policiescCs.x(|j||�D]}|jjj||||�qW|S)N)rPrrZr�)rr/rSr�r�r�rrrr�bszFirewallZone.add_rulecCs*x$|j||�D]}|jjj||�qW|S)N)rPrrZr�)rr/rSr�rrrr�gszFirewallZone.remove_rulecCs2d}x(|j||�D]}|o(|jjj||�}qW|S)NT)rPrrZ�
query_rule)rr/rSr�r�rrrrlszFirewallZone.query_rulecCs^|jj|�}t�}xB|j|d�|j|d�|jd|�gD]}|jt|jjj|���q6Wt|�S)NrHrG)rr<�setr(�updaterZr�r�)rr/r�r�rrrr�rs
zFirewallZone.list_rulescCs0|jj|�}|j|d�}|jjj||||�|S)NrG)rr<r(rZr�)rr/r�r�r�r�rrrr�{szFirewallZone.add_protocolcCs,|jj|�}|j|d�}|jjj||�|S)NrG)rr<r(rZr�)rr/r�r�rrrr��szFirewallZone.remove_protocolcCs(|jj|�}|j|d�}|jjj||�S)NrG)rr<r(rZ�query_protocol)rr/r�r�rrrr	�szFirewallZone.query_protocolcCs&|jj|�}|j|d�}|jjj|�S)NrG)rr<r(rZr�)rr/r�rrrr��szFirewallZone.list_protocolscCs.|jj|�}|jd|�}|jjj|||�|S)NrH)rr<r(rZr�)rr/r�r�r�rrrr��szFirewallZone.add_masqueradecCs*|jj|�}|jd|�}|jjj|�|S)NrH)rr<r(rZr�)rr/r�rrrr��szFirewallZone.remove_masqueradecCs&|jj|�}|jd|�}|jjj|�S)NrH)rr<r(rZr�)rr/r�rrrr��szFirewallZone.query_masqueradec	Cs6|jj|�}|j|d�}|jjj|||||||�|S)NrH)rr<r(rZr�)	rr/r�r��toport�toaddrr�r�r�rrrr��s
zFirewallZone.add_forward_portcCs2|jj|�}|j|d�}|jjj|||||�|S)NrH)rr<r(rZr�)rr/r�r�r
rr�rrrr��sz FirewallZone.remove_forward_portcCs.|jj|�}|j|d�}|jjj|||||�S)NrH)rr<r(rZ�query_forward_port)rr/r�r�r
rr�rrrr�szFirewallZone.query_forward_portcCs&|jj|�}|j|d�}|jjj|�S)NrH)rr<r(rZr�)rr/r�rrrr��szFirewallZone.list_forward_portscCsP|jj|�}|j|d�}|jjj||||�|j|d�}|jjj||||�|S)NrGrH)rr<r(rZr�)rr/�icmpr�r�r�rrrr��szFirewallZone.add_icmp_blockcCsH|jj|�}|j|d�}|jjj||�|j|d�}|jjj||�|S)NrGrH)rr<r(rZr�)rr/r
r�rrrr��szFirewallZone.remove_icmp_blockcCsD|jj|�}|j|d�}|j|d�}|jjj||�oB|jjj||�S)NrGrH)rr<r(rZ�query_icmp_block)rr/r
�p_name_host�
p_name_fwdrrrr�s
zFirewallZone.query_icmp_blockcCsH|jj|�}|j|d�}|j|d�}tt|jjj|�|jjj|���S)NrGrH)rr<r(r)rrZr�)rr/rrrrrr��s
zFirewallZone.list_icmp_blockscCsH|jj|�}|j|d�}|jjj||�|j|d�}|jjj||�|S)NrGrH)rr<r(rZrb)rr/r�r�rrrrb�sz%FirewallZone.add_icmp_block_inversioncCsL|jj|�}|j|d�}|jjj|||�|j|d�}|jjj|||�dS)NrGrH)rr<r(rZr�)rr�r/r�r�rrrr��s
z"FirewallZone._icmp_block_inversioncCsD|jj|�}|j|d�}|jjj|�|j|d�}|jjj|�|S)NrGrH)rr<r(rZr�)rr/r�rrrr��sz(FirewallZone.remove_icmp_block_inversioncCs@|jj|�}|j|d�}|j|d�}|jjj|�o>|jjj|�S)NrGrH)rr<r(rZr�)rr/rrrrrr��s
z'FirewallZone.query_icmp_block_inversionc
	Cs�|j|d�}xT|j|jdD]@}x:|jj�D],}|js:q.|j|||d|d�}|j||�q.WqWxj|j|jdD]V\}}	xL|r�|jj|�gn|jj�D],}|js�q�|j|||d|	d�}|j||�q�WqtWdS)NrHr1r�)r4r7)r9)	r(rr3rr�r�r�r�r�)
rr�r/r�r�r4r�rEr�r9rrr�_forward�s"zFirewallZone._forwardcCsdS)NTr)rrrrZ__forward_idszFirewallZone.__forward_idc	Cs�|jj|�}|jj|�|jj�|j|}|j�}||jdkrRttj	d|��|dkrd|j
�}n|}|jr||jd||�|j
||||�|j|j||�|dkr�|jd�|S)NrYzforward already enabled in '%s'T)rr<Z
check_timeoutr�r�_FirewallZone__forward_idr3rrZALREADY_ENABLEDr$rdr�_FirewallZone__register_forwardr��!_FirewallZone__unregister_forwardr�)	rr/r�r�rgr�r��
forward_idr�rrrras$




zFirewallZone.add_forwardcCs|j||�|jd|<dS)NrY)r�r3)rr�rr�r�rrrZ__register_forward.szFirewallZone.__register_forwardcCs�|jj|�}|jj�|j|}|j�}||jdkrFttjd|��|dkrX|j	�}n|}|j
rp|jd||�|j|j
||�|dkr�|jd�|S)NrYzforward not enabled in '%s'FT)rr<r�rrr3rrZNOT_ENABLEDr$rdrr�rr�)rr/rgr�r�rr�rrrr�2s 




zFirewallZone.remove_forwardcCs||jdkr|jd|=dS)NrY)r3)rr�rrrrZ__unregister_forwardKsz!FirewallZone.__unregister_forwardcCs|j�|j|�dkS)NrY)rr�)rr/rrrr�OszFirewallZone.query_forward)N)N)N)N)NNT)N)N)N)F)F)NNT)N)N)F)rN)rN)rN)rN)rN)rN)NNrN)NN)NN)rN)N)rNN)N)e�__name__�
__module__�__qualname__rJrr!r#r$r(r+r0r6r;r>rTr]r[rfrkrlrxr~r�r�r�r�rjrer�r�r�r�r�r2r_r�r�r�r�r�r�r,r�r8r`r�r�r�r�r�r-r�r�r�r�r�r�r�r�r�r�r�r�r�rr�r�r�rr�rPr�r�rr�r�r�r	r�r�r�r�r�r�rr�r�r�rr�rbr�r�r�rrrarr�rr�rrrrr#s�&



8
(





&


,(



	





		
		

r)"r�rMZfirewall.core.baserrrZfirewall.core.fw_transactionrZfirewall.core.io.policyrZfirewall.core.loggerrr�rr	r
rrr
rrrZfirewall.functionsrrrZfirewallrZfirewall.errorsrZfirewall.fw_typesr�objectrrrrr�<module>s,__pycache__/fw_ipset.cpython-36.opt-1.pyc000064400000016503151731527050014174 0ustar003

��g�%�@sfdZdgZddlmZddlmZmZmZm	Z	ddl
mZddlm
Z
ddlmZGdd�de�Zd	S)
z
ipset backend�
FirewallIPSet�)�log)�remove_default_create_options�normalize_ipset_entry�check_entry_overlaps_existing�check_for_overlapping_entries)�IPSet)�errors)�
FirewallErrorc@s�eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	d4dd�Z
dd�Zdd�Zd5dd�Z
dd�Zdd�Zdd�Zd6dd �Zd!d"�Zd#d$�Zd%d&�Zd7d'd(�Zd)d*�Zd+d,�Zd-d.�Zd/d0�Zd1d2�Zd3S)8rcCs||_i|_dS)N)�_fw�_ipsets)�self�fw�r�/usr/lib/python3.6/fw_ipset.py�__init__#szFirewallIPSet.__init__cCsd|j|jfS)Nz%s(%r))�	__class__r)r
rrr�__repr__'szFirewallIPSet.__repr__cCs|jj�dS)N)r�clear)r
rrr�cleanup,szFirewallIPSet.cleanupcCs||j�krttj|��dS)N)�
get_ipsetsr
r	Z
INVALID_IPSET)r
�namerrr�check_ipset/szFirewallIPSet.check_ipsetcCs||j�kS)N)r)r
rrrr�query_ipset3szFirewallIPSet.query_ipsetcCst|jj��S)N)�sortedr�keys)r
rrrr6szFirewallIPSet.get_ipsetscCst|j�dkS)Nr)�lenr)r
rrr�
has_ipsets9szFirewallIPSet.has_ipsetsFcCs&|j|�|j|}|r"|j|�|S)N)rr�check_applied_obj)r
r�applied�objrrr�	get_ipset<s



zFirewallIPSet.get_ipsetcCs4g}|jjr|j|jj�|jjr0|j|jj�|S)N)rZnftables_enabled�appendZnftables_backendZ
ipset_enabledZ
ipset_backend)r
�backendsrrrr#CszFirewallIPSet.backendscCs0|j|jjkr ttjd|j��||j|j<dS)Nz'%s' is not supported by ipset.)�typerZipset_supported_typesr
r	ZINVALID_TYPErr)r
r rrr�	add_ipsetKszFirewallIPSet.add_ipsetcCs�|j|}|jrh|rhy x|j�D]}|j|�q"WWqttk
rd}zttj|��WYdd}~XqtXntj	d|�|j|=dS)Nz,Keeping ipset '%s' because of timeout option)
rrr#�set_destroy�	Exceptionr
r	�COMMAND_FAILEDr�debug1)r
rZkeepr �backend�msgrrr�remove_ipsetQs
 zFirewallIPSet.remove_ipsetc<Cs$|j|}�x|j�D�]}|jdkr�|j�}||kr�d|jksv|jddksv|j||dksvt|j�||dkr�y|j|�Wn.tk
r�}zt	t
j|��WYdd}~XnX|jj
�r�y|j|j|j|j�Wn0tk
�r}zt	t
j|��WYdd}~Xn&Xd|_d|jk�r,|jddk�r,qy|j|j�Wn0tk
�rl}zt	t
j|��WYdd}~XnXx�|jD]J}y|j|j|�Wn0tk
�r�}zt	t
j|��WYdd}~XnX�qvWqy|j|j|j|j|jd�Wn0tk
�r}zt	t
j|��WYdd}~XqXd|_qWdS)N�ipset�timeout�0r�T)rr#rZset_get_active_terse�optionsr$�rm_def_cr_optsr&r'r
r	r(r�_individual_callsZ
set_creater�	set_flush�entries�set_add�set_restore)r
rr r*Zactiver+�entryrrr�apply_ipset]sL


&
zFirewallIPSet.apply_ipsetcCs>x8|j�D],}|j|}d|_tjd|�|j|�q
WdS)NFzApplying ipset '%s')rrrrr)r9)r
rr rrr�apply_ipsets�s

zFirewallIPSet.apply_ipsetscCs�xz|j�D]n}|jdkrq
x\|j�D]P}y|j|�|j|�Wq$tk
rr}z|jtjkrb|�WYdd}~Xq$Xq$Wq
WdS)NZnftables)	r#rr�
check_appliedr&r
�coder	�NOT_APPLIED)r
r*r-r+rrr�flush�s

zFirewallIPSet.flushTcCs|j||d�jS)N)r)r!r$)r
rrrrr�get_type�szFirewallIPSet.get_typecCst|j|dd�jjd��S)NT)r�,)rr!r$�split)r
rrrr�
get_dimension�szFirewallIPSet.get_dimensioncCs|j|�}|j|�dS)N)r!r)r
rr rrrr;�s
zFirewallIPSet.check_appliedcCs|jsttj|j��dS)N)rr
r	r=r)r
r rrrr�szFirewallIPSet.check_applied_objcCs.|j||d�}d|jkr*|jddkr*dSdS)N)rZfamilyZinet6Zipv6Zipv4)r!r1)r
rrr rrr�
get_family�s

zFirewallIPSet.get_familycCs�|j|dd�}t|�}tj||j|j�||jkrFttj	d||f��t
||j�y$x|j�D]}|j|j
|�q^WWn.tk
r�}zttj|��WYdd}~Xn&Xd|jks�|jddkr�|jj|�dS)NT)rz'%s' already is in '%s'r.r/)r!rr�check_entryr1r$r5r
r	ZALREADY_ENABLEDrr#r6rr'r(r")r
rr8r r*r+rrr�	add_entry�s
zFirewallIPSet.add_entrycCs�|j|dd�}t|�}||jkr4ttjd||f��y$x|j�D]}|j|j|�q@WWn.t	k
r�}zttj
|��WYdd}~Xn&Xd|jks�|jddkr�|jj|�dS)NT)rz'%s' not in '%s'r.r/)
r!rr5r
r	ZNOT_ENABLEDr#Z
set_deleterr'r(r1�remove)r
rr8r r*r+rrr�remove_entry�s
zFirewallIPSet.remove_entrycCsD|j|dd�}t|�}d|jkr:|jddkr:ttj|��||jkS)NT)rr.r/)r!rr1r
r	ZIPSET_WITH_TIMEOUTr5)r
rr8r rrr�query_entry�s
zFirewallIPSet.query_entrycCs|j|dd�}|jS)NT)r)r!r5)r
rr rrr�get_entries�szFirewallIPSet.get_entriescCs@|j|dd�}t|�x|D]}tj||j|j�qWd|jksN|jddkrT||_y"x|j�D]}|j|j	�q`WWn.t
k
r�}zttj
|��WYdd}~XnXd|_yXxR|j�D]F}|jjr�x8|jD]}|j|j	|�q�Wq�|j|j	|j|j|jd�q�WWn0t
k
�r4}zttj
|��WYdd}~XnXd|_dS)NT)rr.r/)r!rrrDr1r$r5r#r4rr'r
r	r(rrr3r6r7)r
rr5r r8r*r+rrr�set_entries�s.
zFirewallIPSet.set_entriesN)F)F)T)T)�__name__�
__module__�__qualname__rrrrrrrr!r#r%r,r9r:r>r?rBr;rrCrErGrHrIrJrrrrr"s0

1

		N)�__doc__�__all__Zfirewall.core.loggerrZfirewall.core.ipsetrr2rrrZfirewall.core.io.ipsetrZfirewallr	Zfirewall.errorsr
�objectrrrrr�<module>s__pycache__/ebtables.cpython-36.pyc000064400000016336151731527050013202 0ustar003

��g�$�@s&dgZddlZddlmZddlmZddlmZm	Z	m
Z
ddlmZddl
mZddlmZmZddlZd	gd
ddgd
ddgd�ZiZiZiZx�ej�D]tZgee<e�ee<x\eeD]PZeejde�eejdeef�eejde�eejde�q�Wq�WGdd�de�ZdS)�ebtables�N)�runProg)�log)�tempFile�readfile�	splitArgs)�COMMANDS)�	ipXtables)�
FirewallError�INVALID_IPVZBROUTINGZ
PREROUTINGZPOSTROUTINGZOUTPUTZINPUTZFORWARD)ZbrouteZnat�filterz-N %s_directz-I %s 1 -j %s_directz-I %s_direct 1 -j RETURNz	%s_directc@s�eZdZdZdZdZdd�Zdd�Zdd�Zd	d
�Z	dd�Z
d
d�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd�Zdd�Zd/d d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd0d+d,�Zd-d.�ZdS)1rZebFcCsBt|j|_td|j|_|j�|_|j�|_|j�g|_	dS)Nz
%s-restore)
r�ipv�_command�_restore_command�_detect_restore_noflush_optionZrestore_noflush_option�_detect_concurrent_option�concurrent_option�fill_exists�available_tables)�self�r�/usr/lib/python3.6/ebtables.py�__init__9s

zebtables.__init__cCs$tjj|j�|_tjj|j�|_dS)N)�os�path�existsrZcommand_existsrZrestore_command_exists)rrrrrAszebtables.fill_existscCs(d}t|jddg�}|ddkr$d}|S)N�z--concurrentz-Lr)rr)rr�retrrrrEs
z"ebtables._detect_concurrent_optioncCs.g}y|j|d�Wntk
r(dSXdS)N�offFT)�	set_rules�
ValueError)r�rulesrrrrOsz'ebtables._detect_restore_noflush_optioncCs�g}|jr |j|kr |j|j�|dd�|D�7}tjd|j|jdj|��t|j|�\}}|dkr~td|jdj|�|f��|S)NcSsg|]}d|�qS)z%sr)�.0�itemrrr�
<listcomp>^sz"ebtables.__run.<locals>.<listcomp>z	%s: %s %s� rz'%s %s' failed: %s)	r�appendr�debug2�	__class__r�joinrr )r�argsZ_args�statusrrrrZ__runYszebtables.__runcCs(x"dD]}||krttd|��qWdS)N�
%%REJECT%%�%%ICMP%%�%%LOGTYPE%%z'%s' invalid for ebtables)r,r-r.)r
r)r�rule�strrrr�_rule_validatefs
zebtables._rule_validatecCs|tko|t|kS)N)�BUILT_IN_CHAINS)rr
�table�chainrrr�is_chain_builtinlszebtables.is_chain_builtincCsJg}|r4|jd|d|g�|jd|d|dddg�n|jd|d|g�|S)Nz-tz-Nz-I�1z-jZRETURNz-X)r&)r�addr3r4r!rrr�build_chain_rulespszebtables.build_chain_rulescCs8d|g}|r |d|t|�g7}n|d|g7}||7}|S)Nz-tz-Iz-D)r0)rr7r3r4�indexr*r/rrr�
build_rule{szebtables.build_rulecCs
tj|�S)N)r	Zcommon_reverse_rule)rr*rrr�reverse_rule�szebtables.reverse_rulecCstj|�dS)N)r	Zcommon_check_passthrough)rr*rrr�check_passthrough�szebtables.check_passthroughcCs
tj|�S)N)r	Zcommon_reverse_passthrough)rr*rrr�reverse_passthrough�szebtables.reverse_passthroughc
Cs<t�}d}i}x�|D]�}|dd�}|j|�xTdD]L}y|j|�}	Wntk
rZYq4Xt|�|	dkr4|j|	�|j|	�}q4Wx^tt|��D]N}	xHtjD]>}
|
||	kr�||	j	d�o�||	j
d�r�d||	||	<q�Wq�W|j|g�j|�qWxD|D]<}|j
d|�x&||D]}|j
dj|�d	��qW�qW|j�tj|j�}tjd
|j|jd|j|jf�g}|jd�t|j||jd
�\}
}tj�dk�rt|j�}|dk	�rd}	xH|D]@}tjd|	|fddd�|j
d	��s�tjddd�|	d7}	�q�Wtj|j�|
dk�r8td|jdj|�|f��dS)Nr�-t�--table��"z"%s"z*%s
r%�
z	%s: %s %sz%s: %dz	--noflush)�stdin�z%8d: %sr)�nofmt�nlr)rEz'%s %s' failed: %s)r>r?)rr1r9r �len�pop�range�stringZ
whitespace�
startswith�endswith�
setdefaultr&�writer)�closer�stat�namerr'r(r�st_sizerZgetDebugLogLevelrZdebug3�unlink)rr!�
log_deniedZ	temp_filer3Ztable_rulesZ_ruler/�opt�i�crPr*r+r�lines�linerrrr�sZ




 




zebtables.set_rulescCs|j|�|j|�S)N)r1�_ebtables__run)rr/rTrrr�set_rule�s
zebtables.set_ruleNcCs�g}|r|gntj�}xp|D]h}||jkr6|j|�qy*|jd|dg�|jj|�|j|�Wqtk
r�tjd|�YqXqW|S)Nz-tz-Lz#ebtables table '%s' does not exist.)r2�keysrr&rZr rZdebug1)rr3rZtablesrrr�get_available_tables�s

zebtables.get_available_tablescCsiS)Nr)rr3rrr�get_zone_table_chains�szebtables.get_zone_table_chainscCsFg}x<tj�D]0}||j�kr qxdD]}|jd||g�q&WqW|S)N�-F�-X�-Zz-t)r_r`ra)r2r\r]r&)rr!r3�flagrrr�build_flush_rules�s
zebtables.build_flush_rulescCs^g}|dkrdn|}xDtj�D]8}||j�kr0qx$t|D]}|jd|d||g�q:WqW|S)NZPANICZDROPz-tz-P)r2r\r]r&)rZpolicyr!Z_policyr3r4rrr�build_set_policy_rules�szebtables.build_set_policy_rulescCsgS)Nr)rrrr�build_default_tables�szebtables.build_default_tablesrcCs�g}x�tD]�}||j�krq
t|dd�}|dkrJ|tkrJ|jt|�d|g}x:|D]2}t|�tkrx|j||�qX|j|t|��qXWq
W|S)Nrz-t)�
DEFAULT_RULESr]�	LOG_RULES�extend�type�listr&r)rrTZ
default_rulesr3Z_default_rules�prefixr/rrr�build_default_rules�s

zebtables.build_default_rulescCs
||jkS)N)r
)rr
rrr�is_ipv_supportedszebtables.is_ipv_supported)N)r)�__name__�
__module__�__qualname__r
rQZpolicies_supportedrrrrrZr1r5r8r:r;r<r=rr[r]r^rcrdrerlrmrrrrr4s0


	@


)�__all__Zos.pathrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsrrrZfirewall.configrZ
firewall.corer	Zfirewall.errorsr
rrJr2rfrgZ
OUR_CHAINSr\r3�setr4r&r7�objectrrrrr�<module>s.
__pycache__/prog.cpython-36.pyc000064400000001266151731527060012365 0ustar003

��g��@sddlZdgZddd�ZdS)�N�runProgc
Cs�|dkrg}|g|}d}|r@t|d��}|j�j�}WdQRXddi}y tj|tjtjtjd|d�}Wntk
r|d
SX|j|�\}}	|j	dd	�}|j
|fS)N�rZLANG�CT)�stdin�stderr�stdoutZ	close_fds�env��zutf-8�replace)r	r
)�open�read�encode�
subprocess�Popen�PIPEZSTDOUT�OSErrorZcommunicate�decode�
returncode)
�prog�argvr�argsZinput_stringZhandlerZprocess�outputZ
err_output�r�/usr/lib/python3.6/prog.pyrs$

)NN)r�__all__rrrrr�<module>s__pycache__/base.cpython-36.pyc000064400000002172151731527060012325 0ustar003

��g6�@s�dZdZdZd0ZdddedgZddddgZd	d
ddd
dd�Zddddddddddddddddgd d!d"d#d$d%d&ddg	d'�Zd(d)d*d+d,d-d.gZd/S)1zBase firewall settingsz{chain}_{zone}ZCONTINUE�ZACCEPTz
%%REJECT%%ZDROP�defaultZREJECTZPREZPOST�INZFWDIZFWDOZOUT)Z
PREROUTINGZPOSTROUTINGZINPUTZ
FORWARD_INZFORWARD_OUTZOUTPUTzicmp-host-prohibitedzhost-prohibzicmp-net-unreachableznet-unreachzicmp-host-unreachablezhost-unreachzicmp-port-unreachablezport-unreachzicmp-proto-unreachablez
proto-unreachzicmp-net-prohibitedz
net-prohibz	tcp-resetztcp-rstzicmp-admin-prohibitedzadmin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp6-no-routezno-routezicmp6-addr-unreachablezaddr-unreachzicmp6-port-unreachable)Zipv4Zipv6zhash:ipzhash:ip,portzhash:ip,markzhash:netz
hash:net,portzhash:net,ifacezhash:macN���)	�__doc__ZDEFAULT_ZONE_TARGETZDEFAULT_POLICY_TARGETZDEFAULT_POLICY_PRIORITYZZONE_TARGETSZPOLICY_TARGETSZ	SHORTCUTSZREJECT_TYPESZSOURCE_IPSET_TYPES�rr�/usr/lib/python3.6/base.py�<module>s.__pycache__/watcher.cpython-36.opt-1.pyc000064400000005256151731527060014015 0ustar003

��g��@s*dgZddlmZmZGdd�de�ZdS)�Watcher�)�Gio�GLibc@sdeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dS)rcCs"||_||_i|_i|_g|_dS)N)�	_callback�_timeout�	_monitors�	_timeouts�_blocked)�self�callbackZtimeout�r�/usr/lib/python3.6/watcher.py�__init__s
zWatcher.__init__cCs:tjj|�}|jtjjd�|j|<|j|jd|j�dS)N�changed)	r�File�new_for_pathZmonitor_directory�FileMonitorFlags�NONEr�connect�_file_changed_cb)r
Z	directory�gfilerrr
�
add_watch_dir"szWatcher.add_watch_dircCs:tjj|�}|jtjjd�|j|<|j|jd|j�dS)Nr)	rrrZmonitor_filerrrrr)r
�filenamerrrr
�add_watch_file(szWatcher.add_watch_filecCs
|jj�S)N)r�keys)r
rrr
�get_watches.szWatcher.get_watchescCs
||jkS)N)r)r
rrrr
�	has_watch1szWatcher.has_watchcCs|j|=dS)N)r)r
rrrr
�remove_watch4szWatcher.remove_watchcCs||jkr|jj|�dS)N)r	�append)r
rrrr
�block_source7s
zWatcher.block_sourcecCs||jkr|jj|�dS)N)r	�remove)r
rrrr
�unblock_source;s
zWatcher.unblock_sourcecCs4x.t|jj��D]}tj|j|�|j|=qWdS)N)�listrrr�
source_remove)r
rrrr
�clear_timeouts?szWatcher.clear_timeoutscCs ||jkr|j|�|j|=dS)N)r	rr)r
rrrr
�_call_callbackDs

zWatcher._call_callbackcCs�|j�}||jkr8||jkr4tj|j|�|j|=dS|tjjksh|tjjksh|tjj	ksh|tjj
kr�||jkr�tj|j|�|j|=tj|j|j
|�|j|<dS)N)Zget_parse_namer	rrr#rZFileMonitorEventZCHANGEDZCREATEDZDELETEDZATTRIBUTE_CHANGEDZtimeout_add_secondsrr%)r
ZmonitorZgio_fileZgio_other_fileZeventrrrr
rIs


zWatcher._file_changed_cbN)�__name__�
__module__�__qualname__rrrrrrrr!r$r%rrrrr
rsN)�__all__Z
gi.repositoryrr�objectrrrrr
�<module>s__pycache__/base.cpython-36.opt-1.pyc000064400000002172151731527060013264 0ustar003

��g6�@s�dZdZdZd0ZdddedgZddddgZd	d
ddd
dd�Zddddddddddddddddgd d!d"d#d$d%d&ddg	d'�Zd(d)d*d+d,d-d.gZd/S)1zBase firewall settingsz{chain}_{zone}ZCONTINUE�ZACCEPTz
%%REJECT%%ZDROP�defaultZREJECTZPREZPOST�INZFWDIZFWDOZOUT)Z
PREROUTINGZPOSTROUTINGZINPUTZ
FORWARD_INZFORWARD_OUTZOUTPUTzicmp-host-prohibitedzhost-prohibzicmp-net-unreachableznet-unreachzicmp-host-unreachablezhost-unreachzicmp-port-unreachablezport-unreachzicmp-proto-unreachablez
proto-unreachzicmp-net-prohibitedz
net-prohibz	tcp-resetztcp-rstzicmp-admin-prohibitedzadmin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp6-no-routezno-routezicmp6-addr-unreachablezaddr-unreachzicmp6-port-unreachable)Zipv4Zipv6zhash:ipzhash:ip,portzhash:ip,markzhash:netz
hash:net,portzhash:net,ifacezhash:macN���)	�__doc__ZDEFAULT_ZONE_TARGETZDEFAULT_POLICY_TARGETZDEFAULT_POLICY_PRIORITYZZONE_TARGETSZPOLICY_TARGETSZ	SHORTCUTSZREJECT_TYPESZSOURCE_IPSET_TYPES�rr�/usr/lib/python3.6/base.py�<module>s.icmp.py000064400000006035151731527060006061 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2017 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "ICMP_TYPES", "ICMPV6_TYPES",
            "check_icmp_type", "check_icmpv6_type" ]

ICMP_TYPES = {
     "echo-reply": "0/0",
     "pong": "0/0",
     "network-unreachable": "3/0",
     "host-unreachable": "3/1",
     "protocol-unreachable": "3/2",
     "port-unreachable": "3/3",
     "fragmentation-needed": "3/4",
     "source-route-failed": "3/5",
     "network-unknown": "3/6",
     "host-unknown": "3/7",
     "network-prohibited": "3/9",
     "host-prohibited": "3/10",
     "TOS-network-unreachable": "3/11",
     "TOS-host-unreachable": "3/12",
     "communication-prohibited": "3/13",
     "host-precedence-violation": "3/14",
     "precedence-cutoff": "3/15",
     "source-quench": "4/0",
     "network-redirect": "5/0",
     "host-redirect": "5/1",
     "TOS-network-redirect": "5/2",
     "TOS-host-redirect": "5/3",
     "echo-request": "8/0",
     "ping": "8/0",
     "router-advertisement": "9/0",
     "router-solicitation": "10/0",
     "ttl-zero-during-transit": "11/0",
     "ttl-zero-during-reassembly": "11/1",
     "ip-header-bad": "12/0",
     "required-option-missing": "12/1",
     "timestamp-request": "13/0",
     "timestamp-reply": "14/0",
     "address-mask-request": "17/0",
     "address-mask-reply": "18/0",
}

ICMPV6_TYPES = {
    "no-route": "1/0",
    "communication-prohibited": "1/1",
    "address-unreachable": "1/3",
    "port-unreachable": "1/4",
    "packet-too-big": "2/0",
    "ttl-zero-during-transit": "3/0",
    "ttl-zero-during-reassembly": "3/1",
    "bad-header": "4/0",
    "unknown-header-type": "4/1",
    "unknown-option": "4/2",
    "echo-request": "128/0",
    "ping": "128/0",
    "echo-reply": "129/0",
    "pong": "129/0",
    "router-solicitation": "133/0",
    "router-advertisement": "134/0",
    "neighbour-solicitation": "135/0",
    "neigbour-solicitation": "135/0",
    "neighbour-advertisement": "136/0",
    "neigbour-advertisement": "136/0",
    "redirect": "137/0",
}

def check_icmp_name(_name):
    if _name in ICMP_TYPES:
        return True
    return False

def check_icmp_type(_type):
    if _type in ICMP_TYPES.values():
        return True
    return False

def check_icmpv6_name(_name):
    if _name in ICMP_TYPES:
        return True
    return False

def check_icmpv6_type(_type):
    if _type in ICMPV6_TYPES.values():
        return True
    return False
fw_policies.py000064400000005363151731527070007440 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "FirewallPolicies" ]

from firewall import config
from firewall.core.logger import log
from firewall.core.io.lockdown_whitelist import LockdownWhitelist
from firewall import errors
from firewall.errors import FirewallError

class FirewallPolicies(object):
    def __init__(self):
        self._lockdown = False
        self.lockdown_whitelist = LockdownWhitelist(config.LOCKDOWN_WHITELIST)

    def __repr__(self):
        return '%s(%r, %r)' % (self.__class__, self._lockdown,
                                           self.lockdown_whitelist)

    def cleanup(self):
        self._lockdown = False
        self.lockdown_whitelist.cleanup()

    # lockdown

    def access_check(self, key, value):
        if key == "context":
            log.debug2('Doing access check for context "%s"' % value)
            if self.lockdown_whitelist.match_context(value):
                log.debug3('context matches.')
                return True
        elif key == "uid":
            log.debug2('Doing access check for uid %d' % value)
            if self.lockdown_whitelist.match_uid(value):
                log.debug3('uid matches.')
                return True
        elif key == "user":
            log.debug2('Doing access check for user "%s"' % value)
            if self.lockdown_whitelist.match_user(value):
                log.debug3('user matches.')
                return True
        elif key == "command":
            log.debug2('Doing access check for command "%s"' % value)
            if self.lockdown_whitelist.match_command(value):
                log.debug3('command matches.')
                return True
        return False

    def enable_lockdown(self):
        if self._lockdown:
            raise FirewallError(errors.ALREADY_ENABLED, "enable_lockdown()")
        self._lockdown = True

    def disable_lockdown(self):
        if not self._lockdown:
            raise FirewallError(errors.NOT_ENABLED, "disable_lockdown()")
        self._lockdown = False

    def query_lockdown(self):
        return self._lockdown

modules.py000064400000007356151731527070006611 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""modules backend"""

__all__ = [ "modules" ]

from firewall.core.prog import runProg
from firewall.core.logger import log
from firewall.config import COMMANDS

class modules(object):
    def __init__(self):
        self._load_command = COMMANDS["modprobe"]
        # Use rmmod instead of modprobe -r (RHBZ#1031102)
        self._unload_command = COMMANDS["rmmod"]

    def __repr__(self):
        return '%s' % (self.__class__)

    def loaded_modules(self):
        """ get all loaded kernel modules and their dependencies """
        mods = [ ]
        deps = { }
        try:
            with open("/proc/modules", "r") as f:
                for line in f:
                    if not line:
                        break
                    line = line.strip()
                    splits = line.split()
                    mods.append(splits[0])
                    if splits[3] != "-":
                        deps[splits[0]] = splits[3].split(",")[:-1]
                    else:
                        deps[splits[0]] = [ ]
        except FileNotFoundError:
            pass

        return mods, deps # [loaded modules], {module:[dependants]}

    def load_module(self, module):
        log.debug2("%s: %s %s", self.__class__, self._load_command, module)
        return runProg(self._load_command, [ module ])

    def unload_module(self, module):
        log.debug2("%s: %s %s", self.__class__, self._unload_command, module)
        return runProg(self._unload_command, [ module ])

    def get_deps(self, module, deps, ret):
        """ get all dependants of a module """
        if module not in deps:
            return
        for mod in deps[module]:
            self.get_deps(mod, deps, ret)
            if mod not in ret:
                ret.append(mod)
        if module not in ret:
            ret.append(module)

    def get_firewall_modules(self):
        """ get all loaded firewall-related modules """
        mods = [ ]
        (mods2, deps) = self.loaded_modules()

        self.get_deps("nf_conntrack", deps, mods)
        # these modules don't have dependants listed in /proc/modules
        for bad_bad_module in ["nf_conntrack_ipv4", "nf_conntrack_ipv6"]:
            if bad_bad_module in mods:
                # move them to end of list, so we'll remove them later
                mods.remove(bad_bad_module)
                mods.insert(-1, bad_bad_module)

        for mod in mods2:
            if mod in [ "ip_tables", "ip6_tables", "ebtables" ] or \
               mod.startswith("iptable_") or mod.startswith("ip6table_") or \
               mod.startswith("nf_") or mod.startswith("xt_") or \
               mod.startswith("ipt_") or mod.startswith("ip6t_") :
                self.get_deps(mod, deps, mods)
        return mods

    def unload_firewall_modules(self):
        """ unload all firewall-related modules """
        for module in self.get_firewall_modules():
            (status, ret) = self.unload_module(module)
            if status != 0:
                log.debug1("Failed to unload module '%s': %s" %(module, ret))
io/__pycache__/helper.cpython-36.pyc000064400000013451151731527070013304 0ustar003

��g� �@s�dddgZddljZddlZddlZddlZddlmZddlm	Z	ddl
mZmZm
Z
mZmZmZddlmZdd	lmZdd
lmZGdd�de�ZGdd
�d
e
�Zdd�Zddd�ZdS)�Helper�
helper_reader�
helper_writer�N)�config)�
u2b_if_py2)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp)�log)�errors)�
FirewallErrorcs�eZdZddddddd gffZdZd	d
gZdddgd�Zd
ddgddgd�Z�fdd�Zdd�Z	dd�Z
dd�Zdd�Z�Z
S)!r�version��short�description�family�module�portsz(sssssa(ss))�-�.N)rr�helper�name�port�protocol)rrcs6tt|�j�d|_d|_d|_d|_d|_g|_dS)Nr)	�superr�__init__rrrrrr)�self)�	__class__��/usr/lib/python3.6/helper.pyr;szHelper.__init__cCs.d|_d|_d|_d|_d|_|jdd�=dS)Nr)rrrrrr)rr!r!r"�cleanupDszHelper.cleanupcCsRt|j�|_t|j�|_t|j�|_t|j�|_t|j�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSs g|]\}}t|�t|�f�qSr!)r)�.0ZpoZprr!r!r"�
<listcomp>Usz)Helper.encode_strings.<locals>.<listcomp>N)rrrrrrr)rr!r!r"�encode_stringsLszHelper.encode_stringscCs(ddg}||kr$ttjd||f��dS)NZipv4Zipv6z'%s' not in '%s')rrZINVALID_IPV)rZipvZipvsr!r!r"�	check_ipvWszHelper.check_ipvcCsz|dkr0xl|D]}t|d�t|d�qWnF|dkrv|jd�sRttjd|��t|jdd��dkrvttjd|��dS)	Nrr�r�
nf_conntrack_z('%s' does not start with 'nf_conntrack_'rzModule name '%s' too short)rr�
startswithrr�INVALID_MODULE�len�replace)rr�itemZ
all_configrr!r!r"�
_check_config]s


zHelper._check_config)rr)rr)rr)rr)rr)rr)�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr#r&r'r/�
__classcell__r!r!)r r"r&s$
	c@seZdZdd�ZdS)�helper_ContentHandlercCs>tj|||�|jj||�|dkr�d|kr8|d|j_d|kr\|jj|d�|d|j_d|kr�|djd�s�tt	j
d|d��t|djdd��dkr�tt	j
d	|d��|d|j_
nz|d
kr�np|dkr�nf|dk�r:t|d�t|d
�|d|d
f}||jjk�r$|jjj|�ntjd|d|d
�dS)Nrrrrr)z('%s' does not start with 'nf_conntrack_'rr(zModule name '%s' too shortrrrrz#Port '%s/%s' already set, ignoring.)r	�startElementr.Zparser_check_element_attrsrr'rr*rrr+r,r-rrrr�appendr
Zwarning)rr�attrs�entryr!r!r"r5ns>
z"helper_ContentHandler.startElementN)r0r1r2r5r!r!r!r"r4msr4c	Cst�}|jd�s ttjd|��|dd	�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~t�r|j�|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid helper file: %s���)r�endswithrrZINVALID_NAMErZ
check_name�filename�pathr*r�
ETC_FIREWALLDZbuiltin�defaultr4�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_HELPERZgetExceptionrr&)	r=r>r�handler�parserr�f�source�msgr!r!r"r�s8




(c
CsP|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j|d	<|j�r|jd
k�r|j|d<|j�r<|jd
k�r<|j|d<|jd
|�|jd�|j�r�|jd
k�r�|jd�|jdi�|j|j�|jd�|jd�|j�r�|jd
k�r�|jd�|jdi�|j|j�|jd�|jd�x>|jD]4}	|jd�|jd|	d|	dd��|jd��q�W|jd
�|jd�|j�|j�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrrrr�
z  rrrrr()rr) r>r=r�os�exists�shutilZcopy2�	Exceptionr
�error�dirnamer*rr?�mkdir�iorBr
Z
startDocumentrrrr5ZignorableWhitespacerZ
charactersZ
endElementrrZ
simpleElementZendDocument�close)
rr>�_pathrrH�dirpathrFrDr7rr!r!r"r�s\ 












)N)�__all__Zxml.saxrArLrSrNZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr	r
rrZfirewall.core.loggerr
rZfirewall.errorsrrr4rrr!r!r!r"�<module>s

 G#io/__pycache__/helper.cpython-36.opt-1.pyc000064400000013451151731527070014243 0ustar003

��g� �@s�dddgZddljZddlZddlZddlZddlmZddlm	Z	ddl
mZmZm
Z
mZmZmZddlmZdd	lmZdd
lmZGdd�de�ZGdd
�d
e
�Zdd�Zddd�ZdS)�Helper�
helper_reader�
helper_writer�N)�config)�
u2b_if_py2)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp)�log)�errors)�
FirewallErrorcs�eZdZddddddd gffZdZd	d
gZdddgd�Zd
ddgddgd�Z�fdd�Zdd�Z	dd�Z
dd�Zdd�Z�Z
S)!r�version��short�description�family�module�portsz(sssssa(ss))�-�.N)rr�helper�name�port�protocol)rrcs6tt|�j�d|_d|_d|_d|_d|_g|_dS)Nr)	�superr�__init__rrrrrr)�self)�	__class__��/usr/lib/python3.6/helper.pyr;szHelper.__init__cCs.d|_d|_d|_d|_d|_|jdd�=dS)Nr)rrrrrr)rr!r!r"�cleanupDszHelper.cleanupcCsRt|j�|_t|j�|_t|j�|_t|j�|_t|j�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSs g|]\}}t|�t|�f�qSr!)r)�.0ZpoZprr!r!r"�
<listcomp>Usz)Helper.encode_strings.<locals>.<listcomp>N)rrrrrrr)rr!r!r"�encode_stringsLszHelper.encode_stringscCs(ddg}||kr$ttjd||f��dS)NZipv4Zipv6z'%s' not in '%s')rrZINVALID_IPV)rZipvZipvsr!r!r"�	check_ipvWszHelper.check_ipvcCsz|dkr0xl|D]}t|d�t|d�qWnF|dkrv|jd�sRttjd|��t|jdd��dkrvttjd|��dS)	Nrr�r�
nf_conntrack_z('%s' does not start with 'nf_conntrack_'rzModule name '%s' too short)rr�
startswithrr�INVALID_MODULE�len�replace)rr�itemZ
all_configrr!r!r"�
_check_config]s


zHelper._check_config)rr)rr)rr)rr)rr)rr)�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr#r&r'r/�
__classcell__r!r!)r r"r&s$
	c@seZdZdd�ZdS)�helper_ContentHandlercCs>tj|||�|jj||�|dkr�d|kr8|d|j_d|kr\|jj|d�|d|j_d|kr�|djd�s�tt	j
d|d��t|djdd��dkr�tt	j
d	|d��|d|j_
nz|d
kr�np|dkr�nf|dk�r:t|d�t|d
�|d|d
f}||jjk�r$|jjj|�ntjd|d|d
�dS)Nrrrrr)z('%s' does not start with 'nf_conntrack_'rr(zModule name '%s' too shortrrrrz#Port '%s/%s' already set, ignoring.)r	�startElementr.Zparser_check_element_attrsrr'rr*rrr+r,r-rrrr�appendr
Zwarning)rr�attrs�entryr!r!r"r5ns>
z"helper_ContentHandler.startElementN)r0r1r2r5r!r!r!r"r4msr4c	Cst�}|jd�s ttjd|��|dd	�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~t�r|j�|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid helper file: %s���)r�endswithrrZINVALID_NAMErZ
check_name�filename�pathr*r�
ETC_FIREWALLDZbuiltin�defaultr4�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_HELPERZgetExceptionrr&)	r=r>r�handler�parserr�f�source�msgr!r!r"r�s8




(c
CsP|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j|d	<|j�r|jd
k�r|j|d<|j�r<|jd
k�r<|j|d<|jd
|�|jd�|j�r�|jd
k�r�|jd�|jdi�|j|j�|jd�|jd�|j�r�|jd
k�r�|jd�|jdi�|j|j�|jd�|jd�x>|jD]4}	|jd�|jd|	d|	dd��|jd��q�W|jd
�|jd�|j�|j�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrrrr�
z  rrrrr()rr) r>r=r�os�exists�shutilZcopy2�	Exceptionr
�error�dirnamer*rr?�mkdir�iorBr
Z
startDocumentrrrr5ZignorableWhitespacerZ
charactersZ
endElementrrZ
simpleElementZendDocument�close)
rr>�_pathrrH�dirpathrFrDr7rr!r!r"r�s\ 












)N)�__all__Zxml.saxrArLrSrNZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr	r
rrZfirewall.core.loggerr
rZfirewall.errorsrrr4rrr!r!r!r"�<module>s

 G#io/__pycache__/zone.cpython-36.opt-1.pyc000064400000031307151731527070013737 0ustar003

��g�M�@sdddgZddljZddlZddlZddlZddlmZddlm	Z	m
Z
mZmZm
Z
mZmZddlmZmZddlmZmZmZmZdd	lmZmZmZmZdd
lmZddlm Z ddlm!Z!dd
l"m#Z#Gdd�de�Z$Gdd�de�Z%ddd�Z&ddd�Z'dS)�Zone�zone_reader�zone_writer�N)�config)�checkIPnMask�
checkIP6nMask�checkInterface�uniqify�max_zone_name_len�
u2b_if_py2�	check_mac)�DEFAULT_ZONE_TARGET�ZONE_TARGETS)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�common_startElement�common_endElement�common_check_config�
common_writer)�rich)�log)�errors)�
FirewallErrorcsfeZdZdZd@dAdBdCdDd	dgfd
dEgfddgfdFd
dGgfddgfddgfddgfddgfddHgfdIdJfZdddgZddddgddgdgdgdddgdgddddgddgddddddgdgdd�Zddddgd gd!d"gd#d$gd%d&d'd#d(gd%d'd(gd)d*gd+gd,gd-�	Zed.d/��Z	�fd0d1�Z
d2d3�Zd4d5�Z�fd6d7�Z
�fd8d9�Zd:d;�Z�fd<d=�Zd>d?�Z�ZS)Krz Zone class �version��short�description�UNUSEDF�target�services�ports�icmp_blocks�
masquerade�
forward_ports�
interfaces�sources�	rules_str�	protocols�source_ports�icmp_block_inversion�forward�_�-�/N�name�port�protocol�value�set)rr�zone�servicer1z
icmp-blockz	icmp-typer,zforward-port�	interface�rule�source�destinationr2zsource-portrZauditZaccept�rejectZdropZmark�limitzicmp-block-inversion�	immutableZenabledzto-portzto-addr�familyZpriority�address�mac�invert�ipset�prefix�level�typeZburst)	r5r$zforward-portr8r9r:rr;r<cCs8x&ttj�D]\}\}}||kr|SqWttjd��dS)Nz
index_of())�	enumerater�IMPORT_EXPORT_STRUCTURErrZ
UNKNOWN_ERROR)�element�iZelZdummy�rJ�/usr/lib/python3.6/zone.py�index_ofdsz
Zone.index_ofcs�tt|�j�d|_d|_d|_d|_t|_g|_	g|_
g|_g|_d|_
d|_g|_g|_g|_g|_d|_g|_g|_d|_d|_d|_dS)NrF)�superr�__init__rrrrr
r r!r"r)r#r,r$r%r*r&r'�	fw_config�rulesr(r+�combined�applied)�self)�	__class__rJrKrNks,z
Zone.__init__cCs�d|_d|_d|_d|_t|_|jdd�=|jdd�=|jdd�=|j	dd�=d|_
d|_|jdd�=|j
dd�=|jdd�=|jdd�=d|_|jdd�=|jdd�=d|_d|_d|_dS)NrF)rrrrr
r r!r"r)r#r,r$r%r*r&r'rOrPr(r+rQrR)rSrJrJrK�cleanup�s*zZone.cleanupcCs�t|j�|_t|j�|_t|j�|_t|j�|_dd�|jD�|_dd�|jD�|_dd�|jD�|_dd�|jD�|_dd�|j	D�|_	dd�|j
D�|_
dd�|jD�|_d	d�|jD�|_d
d�|j
D�|_
dd�|jD�|_dS)
z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsg|]}t|��qSrJ)r)�.0�srJrJrK�
<listcomp>�sz'Zone.encode_strings.<locals>.<listcomp>cSs g|]\}}t|�t|�f�qSrJ)r)rV�po�prrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrZrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrIrJrJrKrX�scSs0g|](\}}}}t|�t|�t|�t|�f�qSrJ)r)rVZp1Zp2Zp3Zp4rJrJrKrX�scSs g|]\}}t|�t|�f�qSrJ)r)rVrYrZrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrIrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrWrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrWrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrWrJrJrKrX�sN)rrrrr r!r"r)r#r%r*r&r'rPr()rSrJrJrK�encode_strings�szZone.encode_stringscsN|dkr8dd�|D�|_tt|�j|dd�|jD��ntt|�j||�dS)Nr(cSsg|]}tj|d��qS))Zrule_str)rZ	Rich_Rule)rVrWrJrJrKrX�sz$Zone.__setattr__.<locals>.<listcomp>cSsg|]}t|��qSrJ)�str)rVrWrJrJrKrX�s)rPrMr�__setattr__)rSr0r3)rTrJrKr]�s zZone.__setattr__cstt|�j�}|d=|S)Nr)rMr�export_config_dict)rSZconf)rTrJrKr^�szZone.export_config_dictcCsLt||||�|dkr.|tkr*ttj|���n|dkr�xl|D]d}t|�sTttj|��|jr<xD|jj�D]6}||j	krvqf||jj
|�jkrfttjdj||���qfWq<Wn�|dk�rHx�|D]�}t
|�r�t|�r�t|�r�|jd�r�ttj|��|jr�xL|jj�D]>}||j	k�r�q||jj
|�jk�rttjdj||����qWq�WdS)Nr r&z)interface '{}' already bound to zone '{}'r'zipset:z&source '{}' already bound to zone '{}')rrrr�INVALID_TARGETrZINVALID_INTERFACErOZ	get_zonesr0Zget_zoner&�formatrrr�
startswith�INVALID_ADDRr')rSr�itemZ
all_configr7r5r9rJrJrK�
_check_config�s6



zZone._check_configcs�tt|�j|�|jd�r,ttjd|��n�|jd�rHttjd|��n�|jd�dkrhttjd|��nnd|kr�|d|j	d��}n|}t
|�t�kr�ttjd|t
|�t�|jf��|j
r�||j
j�kr�ttjd��dS)Nr/z'%s' can't start with '/'z'%s' can't end with '/'�zmore than one '/' in '%s'z'Zone of '%s' has %d chars, max is %d %sz+Zones can't have the same name as a policy.)rMr�
check_namerarr�INVALID_NAME�endswith�count�find�lenr
rQrOZget_policy_objectsZ
NAME_CONFLICT)rSr0Zchecked_name)rTrJrKrf�s,

zZone.check_namec
Cs�d|_d|_d|_d|_d|_x$|jD]}||jkr&|jj|�q&Wx$|jD]}||jkrL|jj|�qLWx$|jD]}||jkrr|jj|�qrWx$|j	D]}||j	kr�|j	j|�q�Wx$|j
D]}||j
kr�|j
j|�q�Wx$|jD]}||jkr�|jj|�q�W|j�rd|_|j
�rd|_
x(|jD]}||jk�r&|jj|��q&Wx(|jD]}||jk�rP|jj|��qPWx,|jD]"}	|jj|	�|jjt|	���qzW|j�r�d|_dS)NTr)rQ�filenamerrrr&�appendr'r!r"r)r#r,r$r%r*rPr(r\r+)
rSr5r7r9r6r1�protoZicmpr,r8rJrJrK�combine�sL





zZone.combine)rr)rr)rr)rF)r r)rr)r$F)rrrr)rr)r+F)r,F)�__name__�
__module__�__qualname__�__doc__rGZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRS�staticmethodrLrNrUr[r]r^rdrfro�
__classcell__rJrJ)rTrKr(sx


c@s$eZdZdd�Zdd�Zdd�ZdS)�zone_ContentHandlercCs"tj||�d|_d|_d|_dS)NF)rrN�_rule�_rule_errorZ	_limit_ok)rSrcrJrJrKrN szzone_ContentHandler.__init__c	Cs�tj|||�|jrdS|jj||�t|||�r6dS|dkr�d|krVtjd|d�d|krj|d|j_d|kr�tjd|d�d|kr�|d}|t	kr�t
tj|��|dkr�|t
kr�||j_�n�|d	kr�|jjr�tjd
�nd|j_�n�|dk�rh|j�rtjd
�d|_dSd|k�r.tjd�d|_dS|d|jjk�rT|jjj|d�ntjd|d��n8|dk�rf|j�r |jj�r�tjdt|j��d|_dSd}d|k�r�|dj�d$k�r�d}d}}}d|k�r�|d}d|k�r�|d}d|k�r|d}tj||||d�|j_dSd|k�rBd|k�rBtjd�dSd|k�rdd|k�rdtjd�dSd|k�r~tjd|d�d|k�r�tjd�dSd|k�r�t|d��r�t|d��r�t|d��r�t
tj|d��d|k�r$d|d}||jjk�r|jjj|�ntjd |d�d|k�r�|d}||jjk�rT|jjj|�ntjd |d�n:|d!k�r�|jj�r�tjd"�nd|j_ntjd#|�dSdS)%Nr5r0z'Ignoring deprecated attribute name='%s'rr=z,Ignoring deprecated attribute immutable='%s'r rr,zForward already set, ignoring.Tr7z$Invalid rule: interface use in rule.z Invalid interface: Name missing.z%Interface '%s' already set, ignoring.r9z:Invalid rule: More than one source in rule '%s', ignoring.FrA�yes�truer?r@rB)rAz$Invalid source: No address no ipset.z"Invalid source: Address and ipset.r>z)Ignoring deprecated attribute family='%s'z+Invalid source: Invertion not allowed here.zipset:%sz"Source '%s' already set, ignoring.zicmp-block-inversionz+Icmp-Block-Inversion already set, ignoring.zUnknown XML element '%s')ryrz)r�startElementrxrcZparser_check_element_attrsrrZwarningrrrrr_r
r r,rwr&rmr9r\�lowerrZRich_Sourcerrrrbr'r+)	rSr0�attrsr rAZaddrr@rB�entryrJrJrKr{&s�

























z zone_ContentHandler.startElementcCstj||�t||�dS)N)r�
endElementr)rSr0rJrJrKr�szzone_ContentHandler.endElementN)rprqrrrNr{rrJrJrJrKrvsprvFc
Cst�}|jd�s ttjd|��|dd	�|_|s>|j|j�||_||_|j	t
j�rZdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}	zttjd|	j���WYdd}	~	XnXWdQRX~~t�r|j�|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid zone file: %s���)rrhrrrgr0rfrl�pathrar�
ETC_FIREWALLDZbuiltin�defaultrv�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_ZONEZgetExceptionrr[)
rlr�Z
no_check_namer5�handler�parserr0�fr9�msgrJrJrKr�s:




(cCs\|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|jtk�r*|j|d<|jd|�|jd
�t||�x8t|j�D]*}	|jd�|jdd|	i�|jd
��qVWx\t|j�D]N}
|jd�d|
k�r�|jdd|
dd�i�n|jdd|
i�|jd
��q�W|j�r
|jd�|jdi�|jd
�|j�r2|jd�|jdi�|jd
�|jd�|jd
�|j �|j!�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrr r5�
z  r7r0zipset:r9rB�r?zicmp-block-inversionr,)"r�rlr0�os�exists�shutilZcopy2�	Exceptionr�error�dirnamerarr��mkdir�ior�rZ
startDocumentrr r
r{ZignorableWhitespacerr	r&Z
simpleElementr'r+r,rZendDocument�close)r5r��_pathr0r��dirpathr�r�r}r7r9rJrJrKr�s` 












)F)N)(�__all__Zxml.saxr�r�r�r�ZfirewallrZfirewall.functionsrrrr	r
rrZfirewall.core.baser
rZfirewall.core.io.io_objectrrrrZfirewall.core.io.policyrrrrZ
firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrrvrrrJrJrJrK�<module>s$

$x|
io/__pycache__/lockdown_whitelist.cpython-36.opt-1.pyc000064400000022550151731527070016700 0ustar003

��g�1�@s�ddljZddlZddlZddlZddlmZddlmZm	Z	m
Z
mZddlm
Z
ddlmZmZmZmZmZmZddlmZddlmZGdd	�d	e
�ZGd
d�de	�ZdS)�N)�config)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�log)�uniqify�	checkUser�checkUid�checkCommand�checkContext�
u2b_if_py2)�errors)�
FirewallErrorc@seZdZdd�Zdd�ZdS)�!lockdown_whitelist_ContentHandlercCstj||�d|_dS)NF)r�__init__�	whitelist)�self�item�r�(/usr/lib/python3.6/lockdown_whitelist.pyr%sz*lockdown_whitelist_ContentHandler.__init__cCsVtj|||�|jj||�|dkr@|jr6ttjd��d|_�n|dkrr|js\tj	d�dS|d}|jj
|�n�|dkr�|js�tj	d�dSd	|kr�yt|d	�}Wn&tk
r�tj	d
|d	�dSX|jj
|�nd|kr�|jj|d�n\|dk�r@|j�stj	d�dSd
|k�r.tj	d�dS|jj|d
�ntj	d|�dSdS)NrzMore than one whitelist.T�commandz)Parse Error: command outside of whitelist�name�userz&Parse Error: user outside of whitelist�idz"Parse Error: %s is not a valid uid�selinuxz)Parse Error: selinux outside of whitelist�contextzParse Error: no contextzUnknown XML element %s)r�startElementrZparser_check_element_attrsrrrZPARSE_ERRORr�error�add_command�int�
ValueError�add_uid�add_user�add_context)rrZattrsr�uidrrrr)sJ






z.lockdown_whitelist_ContentHandler.startElementN)�__name__�
__module__�__qualname__rrrrrrr$srcs4eZdZdZddgfddgfddgfddgffZdZd	gZd
dgd
dgd
�ZdddgiZ�fdd�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Zd>d?�Z d@dA�Z!dBdC�Z"�Z#S)D�LockdownWhitelistz LockdownWhitelist class �commands��contexts�users�uidsrz
(asasasai)�_Nrr)rrrrrrcs6tt|�j�||_d|_g|_g|_g|_g|_dS)N)	�superr)r�filename�parserr*r,r-r.)rr1)�	__class__rrrnszLockdownWhitelist.__init__cCs�|d
kr.x�|D]}|j||dd�|�qWnv|dkrLt|�s�ttj|��nX|dkrjt|�s�ttj|��n:|dkr�t|�s�ttj|��n|d	kr�t	|�s�ttj
|��dS)Nr*r,r-r.�rrrr%)r*r,r-r.���)�
_check_configrrr�INVALID_COMMANDr�INVALID_CONTEXTr	�INVALID_USERr
�INVALID_UID)rrrZ
all_config�xrrrr6ys
zLockdownWhitelist._check_configcCs4|jdd�=|jdd�=|jdd�=|jdd�=dS)N)r*r,r-r.)rrrr�cleanup�szLockdownWhitelist.cleanupcCs:dd�|jD�|_dd�|jD�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsg|]}t|��qSr)r
)�.0r;rrr�
<listcomp>�sz4LockdownWhitelist.encode_strings.<locals>.<listcomp>cSsg|]}t|��qSr)r
)r=r;rrrr>�scSsg|]}t|��qSr)r
)r=r;rrrr>�sN)r*r,r-)rrrr�encode_strings�sz LockdownWhitelist.encode_stringscCs@t|�sttj|��||jkr,|jj|�nttjd|��dS)Nz!Command "%s" already in whitelist)rrrr7r*�append�ALREADY_ENABLED)rrrrrr�s
zLockdownWhitelist.add_commandcCs,||jkr|jj|�nttjd|��dS)NzCommand "%s" not in whitelist.)r*�removerr�NOT_ENABLED)rrrrr�remove_command�s
z LockdownWhitelist.remove_commandcCs
||jkS)N)r*)rrrrr�has_command�szLockdownWhitelist.has_commandcCsBx<|jD]2}|jd�r.|j|dd��r:dSq||krdSqWdS)N�*r4TFr5)r*�endswith�
startswith)rrZ_commandrrr�
match_command�s
zLockdownWhitelist.match_commandcCs|jS)N)r*)rrrr�get_commands�szLockdownWhitelist.get_commandscCsDt|�sttjt|���||jkr0|jj|�nttjd|��dS)NzUid "%s" already in whitelist)r
rrr:�strr.r@rA)rr%rrrr"�s
zLockdownWhitelist.add_uidcCs,||jkr|jj|�nttjd|��dS)NzUid "%s" not in whitelist.)r.rBrrrC)rr%rrr�
remove_uid�s
zLockdownWhitelist.remove_uidcCs
||jkS)N)r.)rr%rrr�has_uid�szLockdownWhitelist.has_uidcCs
||jkS)N)r.)rr%rrr�	match_uid�szLockdownWhitelist.match_uidcCs|jS)N)r.)rrrr�get_uids�szLockdownWhitelist.get_uidscCs@t|�sttj|��||jkr,|jj|�nttjd|��dS)NzUser "%s" already in whitelist)r	rrr9r-r@rA)rrrrrr#�s
zLockdownWhitelist.add_usercCs,||jkr|jj|�nttjd|��dS)NzUser "%s" not in whitelist.)r-rBrrrC)rrrrr�remove_user�s
zLockdownWhitelist.remove_usercCs
||jkS)N)r-)rrrrr�has_user�szLockdownWhitelist.has_usercCs
||jkS)N)r-)rrrrr�
match_user�szLockdownWhitelist.match_usercCs|jS)N)r-)rrrr�	get_users�szLockdownWhitelist.get_userscCs@t|�sttj|��||jkr,|jj|�nttjd|��dS)Nz!Context "%s" already in whitelist)rrrr8r,r@rA)rrrrrr$"s
zLockdownWhitelist.add_contextcCs,||jkr|jj|�nttjd|��dS)NzContext "%s" not in whitelist.)r,rBrrrC)rrrrr�remove_context,s
z LockdownWhitelist.remove_contextcCs
||jkS)N)r,)rrrrr�has_context3szLockdownWhitelist.has_contextcCs
||jkS)N)r,)rrrrr�
match_context6szLockdownWhitelist.match_contextcCs|jS)N)r,)rrrr�get_contexts9szLockdownWhitelist.get_contextscCs�|j�|jjd�s&ttjd|j��t|�}tj�}|j	|�y|j
|j�Wn8tjk
r�}zttjd|j
���WYdd}~XnX~~tr�|j�dS)Nz.xmlz'%s' is missing .xml suffixzNot a valid file: %s)r<r1rGrrZINVALID_NAMEr�saxZmake_parserZsetContentHandler�parseZSAXParseExceptionZINVALID_TYPEZgetExceptionrr?)r�handlerr2�msgrrr�read>s"
zLockdownWhitelist.readcCs�tjj|j�r\ytj|jd|j�Wn4tk
rZ}ztd|j|f��WYdd}~XnXtjjtj	�sxtj
tj	d�tj|jddd�}t
|�}|j�|jdi�|jd�x6t|j�D](}|jd	�|jd
d|i�|jd�q�Wx:t|j�D],}|jd	�|jdd
t|�i�|jd�q�Wx8t|j�D]*}|jd	�|jdd|i�|jd��q0Wx8t|j�D]*}|jd	�|jdd|i�|jd��qjW|jd�|jd�|j�|j�~dS)Nz%s.oldzBackup of '%s' failed: %si�ZwtzUTF-8)�mode�encodingr�
z  rrrrrr)�os�path�existsr1�shutilZcopy2�	Exception�IOErrorrZ
ETC_FIREWALLD�mkdir�io�openrZ
startDocumentrZignorableWhitespacerr*Z
simpleElementr.rKr-r,Z
endElementZendDocument�close)rr[�frZrr%rrrrr�writeQsB$






zLockdownWhitelist.write)$r&r'r(�__doc__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr6r<r?rrDrErIrJr"rLrMrNrOr#rPrQrRrSr$rTrUrVrWr\rk�
__classcell__rr)r3rr)WsL

	


1
r))Zxml.saxrXr`rgrcZfirewallrZfirewall.core.io.io_objectrrrrZfirewall.core.loggerrZfirewall.functionsrr	r
rrr
rZfirewall.errorsrrr)rrrr�<module>s
 3io/__pycache__/policy.cpython-36.opt-1.pyc000064400000051212151731527070014260 0ustar003

��gϢ�@s dddgZddljZddlZddlZddlZddlmZddlm	Z	m
Z
ddlmZmZm
Z
ddlmZmZmZdd	lmZmZmZmZmZmZdd
lmZddlmZddlmZdd
lmZdd�Z dd�Z!dd�Z"dd�Z#dd�Z$Gdd�de�Z%Gdd�de�Z&ddd�Z'ddd�Z(dS) �Policy�
policy_reader�
policy_writer�N)�config)�checkIP�checkIP6)�uniqify�max_policy_name_len�portStr)�DEFAULT_POLICY_TARGET�POLICY_TARGETS�DEFAULT_POLICY_PRIORITY)�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp�check_protocol)�rich)�log)�errors)�
FirewallErrorc	Cs�|dkr�n�|dkr�n�|dkr�|jr`|jjrJtjdt|j��d|_dStj|d�|j_dS|d|jj	kr�|jj	j
|d�ntjd|d��n|dk�rN|jr�|jjr�tjdt|j��d|_dStj|d|d	�|j_dSt|d�t
|d	�t|dd
�|d	f}||jjk�r4|jjj
|�ntjd|d|d	��nN|d	k�r�|j�r�|jj�r�tjdt|j��d|_dStj|d�|j_nBt|d�|d|jjk�r�|jjj
|d�ntjd
|d��n�|dk�rh|j�r.|jj�rtjdt|j��d|_dStj|d�|j_dS|d|jjk�rT|jjj
|d�ntjd|d��n4|dk�r�|j�r�|jj�r�tjdt|j��d|_dStj|d�|j_dStjd|d��n�|dk�r2|j�r|jj�rtjdt|j��d|_dStj�|j_n|jj�r&tjd�nd|j_�nj|dk�r�d}d|k�rR|d}d}d|k�rh|d}|j�r�|jj�r�tjdt|j��d|_dStj|d|d	||�|j_dSt|d�t
|d	�|�r�t|�|�r
t|��r
t|��r
ttjd|��t|dd
�|d	t|d
�t|�f}||jjk�rL|jjj
|�n6tjd|d|d	|�rld|nd|�r|d|nd��n|dk�r@|j�r�|jj�r�tjdt|j��d|_dStj|d|d	�|j_dSt|d�t
|d	�t|dd
�|d	f}||jj k�r&|jj j
|�ntjd|d|d	��n\|dk�r�|j�sftjd�d|_dS|jj!�r�tjd t|j��dSd!}d}d"|k�r�|d"}d}d#|k�r�|d#}d$|k�r�|d$j"�dLk�r�d}tj#|||�|j_!�n�|dMk�r�|j�stjd+�d|_dS|jj$�r0tjd,�d|_dS|d'k�rHtj%�|j_$nh|d(k�rxd}	d-|k�rh|d-}	tj&|	�|j_$n8|d)k�r�tj'�|j_$n |d*k�r�|d.}
tj(|
�|j_$|jj$|_)�n�|d/k�r^|j�s�tjd0�dS|jj�r�tjd1�dSd}d2|k�r*|d2}|dNk�r*tjd;�d|_dSd<|k�r<|d<nd}tj*||�|j_|jj|_)�n>|d=k�r�|j�s~tjd>�dS|jj+�r�tjd?t|j��d|_dStj,�|j_+|jj+|_)n�|d@k�r,d}
dA}dB|k�r|dB}
|
dOk�rtjdE|dB�d|_dSdF|k�rt-|dF�}tj.|
|dG�|_np|dHk�r�|j)�sRtjdI�d|_dS|j)j/�rxtjdJt|j��d|_dS|d}tj0||j1dK��|j)_/nd!SdS)PN�short�description�servicez;Invalid rule: More than one element in rule '%s', ignoring.T�namez#Service '%s' already set, ignoring.�port�protocol�-z#Port '%s/%s' already set, ignoring.�valuez$Protocol '%s' already set, ignoring.z
icmp-blockz&icmp-block '%s' already set, ignoring.z	icmp-typez-Invalid rule: icmp-block '%s' outside of rule�
masqueradez!Masquerade already set, ignoring.zforward-port�zto-portzto-addrz#to-addr '%s' is not a valid addressz-Forward port %s/%s%s%s already set, ignoring.z >%sz @%szsource-portz*Source port '%s/%s' already set, ignoring.�destinationz)Invalid rule: Destination outside of rulez?Invalid rule: More than one destination in rule '%s', ignoring.F�address�ipset�invert�yes�true�accept�reject�drop�markz$Invalid rule: Action outside of rulez"Invalid rule: More than one action�type�setrz!Invalid rule: Log outside of rulezInvalid rule: More than one log�level�emerg�alert�crit�error�warning�notice�info�debugzInvalid rule: Invalid log level�prefix�auditz#Invalid rule: Audit outside of rulez9Invalid rule: More than one audit in rule '%s', ignoring.�ruler�family�ipv4�ipv6z&Invalid rule: Rule family "%s" invalid�priority)r:r=�limitz4Invalid rule: Limit outside of action, log and auditz9Invalid rule: More than one limit in rule '%s', ignoring.�burst)r&r')r(r)r*r+)r/r0r1r2r3r4r5r6)r;r<)2�_rule�elementrr3�str�_rule_errorr�Rich_Service�item�services�append�	Rich_Portrrr
�ports�
Rich_Protocolr�	protocols�Rich_IcmpBlock�icmp_blocks�
Rich_IcmpType�Rich_Masquerader �Rich_ForwardPortrrrr�INVALID_ADDR�
forward_ports�Rich_SourcePort�source_portsr"�lowerZRich_Destination�action�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�	_limit_okZRich_Logr8Z
Rich_Audit�int�	Rich_Ruler>Z
Rich_Limit�get)�objr�attrs�entry�to_portZto_addrr%r#r$Z_typeZ_setr.r7r:r=r�rc�/usr/lib/python3.6/policy.py�common_startElements�


















































recCs�|dkr�|js�y|jj�Wn6tk
rR}ztjd|t|j��WYdd}~XnLXt|j�|jjkr�|jj	j
|j�|jjj
t|j��ntjdt|j��d|_d|_n|dkr�d|_dS)Nr9z%s: %sz Rule '%s' already set, ignoring.Fr(r)r*r+rr8)r(r)r*r+rr8)rCr@Zcheck�	Exceptionrr3rBrE�	rules_str�rulesrGr[)r_r�ercrcrd�common_endElements&rjcCs�t|t�rdnd}|dkrT|jrT|jj�}x$|D]}||kr0ttjd|��q0W�n�|dkr�x$|D]}t|d�t|d�qbW�nb|dkr�x|D]}t	|�q�W�n@|d	kr�|jr�|jj
�}	x$|D]}
|
|	kr�ttjd
|
��q�W�n�|dk�r�x�|D]�}t|d�t|d�|d�r>|d
�r>ttjd|��|d�rTt|d�|d
r�t
|d
�r�t|d
�r�ttjd|d
��q�W�nT|dk�r�x&|D]}t|d�t|d��q�W�n|dk�r�x|D�]}tj|d�}
|j�r�|
j�r�t|
jtj��st|
jtj��r�|jj
�}	|
jj|	k�rLttjd
|
jj��nH|
j�r�|jj|
jj�}|j�r�|
j|jk�r�ttjd|
j|
jjf��nL|j�r�t|
jtj��r�|jj�}|
jj|k�r�ttjdj||j|
jj����q�WdS)NrZZonerFz '%s' not among existing servicesrIr�rKrMz"'%s' not among existing icmp typesrR��z$'%s' is missing to-port AND to-addr z#to-addr '%s' is not a valid addressrTrg�
rich_rules)�rule_strz3rich rule family '%s' conflicts with icmp type '%s'z){} '{}': '{}' not among existing services)rgrn)�
isinstancer�	fw_configZget_servicesrrZINVALID_SERVICErrrZ
get_icmptypesZINVALID_ICMPTYPE�INVALID_FORWARDrrrQrr]rArLrNrr:Zget_icmptyper"rD�format)r_rrE�
all_configZobj_typeZexisting_servicesrr�protoZexisting_icmptypesZicmptype�fwd_portr9Zobj_richZictrcrcrd�common_check_config2s�












 

rwcCs0d|ji}|j}|dk	r ||d<|jd|�dS)Nrr?r>)rr?�
simpleElement)�handlerr>�dr?rcrcrd�_handler_add_rich_limitxs

r{cCs�|jrF|jdkrF|jd�|jdi�|j|j�|jd�|jd�|jr�|jdkr�|jd�|jdi�|j|j�|jd�|jd�x6t|j�D](}|jd�|jdd|i�|jd�q�Wx@t|j	�D]2}|jd�|jd|d	|d
d��|jd�q�Wx8t|j
�D]*}|jd�|jdd
|i�|jd��qWx8t|j�D]*}|jd�|jdd|i�|jd��qLW|j�r�|jd�|jdi�|jd�x�t|j
�D]�}|jd�|d	|d
d�}|d�r�|ddk�r�|d|d<|d�r|ddk�r|d|d<|jd|�|jd��q�WxBt|j�D]4}|jd�|jd|d	|d
d��|jd��q>W�xT|jD�]H}i}|j�r�|j|d<|jd	k�r�t|j�|d<|jd�|jd|�|jd�|j�rVi}|jj�r�|jj|d<|jj�r|jj|d<|jj�r$|jj|d<|jj�r6d|d<|jd�|jd|�|jd�|j�r�i}|jj�rx|jj|d<|jj�r�|jj|d<|jj�r�d|d<|jd�|jd |�|jd�|j�rxd}	i}t|j�tjk�r�d}	|jj|d<�nbt|j�tjk�r(d}	|jj|d<|jj |d<�n0t|j�tj!k�rNd}	|jj"|d
<�n
t|j�tj#k�rfd}	n�t|j�tj$k�r�d}	|jj|d<n�t|j�tj%k�r�d!}	|jj|d<n�t|j�tj&k�rd}	|jj|d<|jj |d<|jj'dk�r�|jj'|d<|jj(dk�rX|jj(|d<nFt|j�tj)k�rBd}	|jj|d<|jj |d<nt*t+j,d"t|j���|jd�|j|	|�|jd�|j-�ri}|j-j.�r�|j-j.|d#<|j-j/�r�|j-j/|d$<|j-j0�r�|jd�|jd%|�|jd&�t1||j-j0�|jd'�|jd%�n|jd�|jd%|�|jd�|j2�r�i}|j2j0�rx|jd�|jd(i�|jd&�t1||j2j0�|jd'�|jd(�n|jd�|jd(|�|jd�|j3�r�d}
i}t|j3�tj4k�r�d)}
n|t|j3�tj5k�r�d*}
|j3j�r<|j3j|d+<nNt|j3�tj6k�rd,}
n6t|j3�tj7k�r*d-}
|j3j8|d.<nt-j9d/t|j3��|j3j0�r�|jd�|j|
|�|jd&�t1||j3j0�|jd'�|j|
�n|jd�|j|
|�|jd�|jd�|jd�|jd��q�WdS)0Nr!z  r�
rrrrrrk)rrrrz
icmp-blockr rlzto-portrmzto-addrzforward-portzsource-portr:r=r9r#�macr$�Truer%z    �sourcer"z	icmp-typez"Unknown element '%s' in obj_writerr7r.rz
      z
    r8r(r)r,r*r+r-zUnknown action '%s'):r�ignorableWhitespace�startElementZ
characters�
endElementrrrFrxrIrKrMr rRrTrhr:r=rBr�addrr}r$r%r"rAr,rrDrrHrrrJrrOrLrNrPrb�
to_addressrSrrZINVALID_OBJECTrr7r.r>r{r8rVrWrXrYrZr-r3)r_ryrrrZicmpZforwardr`r9rArVrcrcrd�
common_writer�s\




















































r�csPeZdZd7ZdZeZdgZd8d9d:d;d	dgfd
d<gfddgfd=dd>gfddgfddgfdd?gfd@ddgfddgffZdddgZ	dddgdgddgdgdgdddgddddgddgddddddgdgdgdgd�Z
ddgdd gd!dgd"d#d$d!d%gd"d$d%gd&d'gd(gd)gd*�Z�fd+d,�Zd-d.�Z
�fd/d0�Z�fd1d2�Zd3d4�Z�fd5d6�Z�ZS)Ari�i�r�versionr!rr�targetrFrIrMr FrRrnrKrTr=�
ingress_zones�egress_zones�_r�/Nrrrrr-)rr�policyrrz
icmp-blockz	icmp-typer zforward-portr9rr"rzsource-portrr8r(r)r*r+r>zingress-zonezegress-zonezto-portzto-addrr:r#r}r%r$r7r.r,r?)r�zforward-portr9rr"rr)r>cs�tt|�j�d|_d|_d|_t|_g|_g|_	g|_
g|_d|_g|_
g|_d|_g|_g|_d|_|j|_d|_g|_g|_dS)Nr!F)�superr�__init__r�rrrr�rFrIrKrMr rRrTrqrhrg�applied�priority_defaultr=Zderived_from_zoner�r�)�self)�	__class__rcrdr��s(zPolicy.__init__cCs�d|_d|_d|_t|_|jdd�=|jdd�=|jdd�=|jdd�=d|_	|j
dd�=|jdd�=d|_|j
dd�=|jdd�=d|_|j|_|jdd�=|jdd�=dS)Nr!F)r�rrrr�rFrIrKrMr rRrTrqrhrgr�r�r=r�r�)r�rcrcrd�cleanup�s$zPolicy.cleanupcs"|dkr|jSttt|�|�SdS)Nrn)rg�getattrr�r)r�r)r�rcrd�__getattr__�szPolicy.__getattr__csB|dkr,dd�|D�|_dd�|jD�|_ntt|�j||�dS)NrncSsg|]}tj|d��qS))ro)rr])�.0�srcrcrd�
<listcomp>�sz&Policy.__setattr__.<locals>.<listcomp>cSsg|]}t|��qSrc)rB)r�r�rcrcrdr��s)rhrgr�r�__setattr__)r�rr)r�rcrdr��szPolicy.__setattr__c
Cst||||�|dkr2|tkr.ttjd|���n�|dkrz||jksX||jksX||jkrvttjd||j|j|jf���n�|dk�rhddg}|j	r�||j	j
�7}x�|D]�}||kr�ttjd	|��|dkr�tddg�t|�@�s�|dk�rt|�t|g��rttjd
|��|dkr�|dk�r8d|k�r8d|dk�sT|dkr�d|kr�d|dkr�ttjd��q�W�n�|dk�r|�rd|k�r�d|dk�r�ttjd
��nxd|k�rd|dk�r�ttjd��xR|dD]F}|dk�rސq�|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�n�|dk�r4�x�|D�]}tj|d�}|j�r�t|jtj��r�d|k�r|d|dk�r|ttjd
��nxd|k�r,d|dk�r�ttjd��xR|dD]F}|dk�r��q�|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�q,|j�r�t|jtj��r�d|k�r,d|dk�r@|jj�r�ttjd��nt|d�r,|jj�s`ttjd��d|dk�r,x�|dD]8}|j	j
|�}|j	�rxd|j	j|�k�rxttjd���qxWnv|j�r,t|jtj��r,d|k�r,xR|dD]F}|dk�r�q�|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�q,Wn�|dk�rx�|D]�}	d|k�rnd|dk�rnttjd��n�d|k�rDd|dk�r�|	d�rttjd��nt|d�rD|	d�s�ttjd��d|dk�rDxD|dD]8}|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�qDWdS)Nr�z'%s' is invalid targetr=zQ%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %sr�r��ANY�HOSTz'%s' not among existing zonesz>'%s' may only contain one of: many regular zones, ANY, or HOSTzF'HOST' can only appear in either ingress or egress zones, but not bothr z.'masquerade' is invalid for egress zone 'HOST'z/'masquerade' is invalid for ingress zone 'HOST'Z
interfaceszR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesrn)rozAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesrRz1'forward-port' is invalid for ingress zone 'HOST'rm)r�r�)r�r�)r�r�)r�r�)rwrrr�INVALID_TARGET�priority_reserved�priority_max�priority_minZINVALID_PRIORITYrq�	get_zonesZINVALID_ZONEr-Zget_zoneZget_zone_config_dictrr]rArprOrPr�rrrVrZ)
r�rrErtZexisting_zones�zoneZz_objr9r_rvrcrcrd�
_check_config�s�






"
















zPolicy._check_configcs�tt|�j|�|jd�r,ttjd|��n�|jd�rHttjd|��n�|jd�dkrhttjd|��njd|kr�|d|j	d��}n|}t
|�t�kr�ttjd|t
|�t�f��|jr�||jj
�kr�ttjd��dS)Nr�z'%s' can't start with '/'z'%s' can't end with '/'rkzmore than one '/' in '%s'z&Policy of '%s' has %d chars, max is %dz,Policies can't have the same name as a zone.)r�r�
check_name�
startswithrr�INVALID_NAME�endswith�count�find�lenr	rqr�Z
NAME_CONFLICT)r�rZchecked_name)r�rcrdr�,s*

zPolicy.check_namei���)r�r!)rr!)rr!)r�r!)r!r!)r F)r!r!r!r!)r!r!)r=r)�__name__�
__module__�__qualname__r�r�r
r�r�ZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr�r�r�r�r�r��
__classcell__rcrc)r�rdrZsr


^c@s$eZdZdd�Zdd�Zdd�ZdS)�policy_ContentHandlercCs"tj||�d|_d|_d|_dS)NF)rr�r@rCr[)r�rErcrcrdr�Hszpolicy_ContentHandler.__init__cCstj|||�|jrdS|jj||�t|||�r6dS|dkr�d|krR|d|j_d|krjt|d�|j_d|kr�|d}|t	kr�t
tj|��|r�||j_
�n^|dkr�|d|jjkr�|jjj|d�ntjd|d��n|dk�r |d|jjk�r|jjj|d�ntjd	|d�n�|d
k�r�|j�sFtjd�d|_dS|jj�rltjd
t|j��d|_dSd}d|k�r�|dj�dk�r�d}d}}}d|k�r�|d}d|k�r�|d}d|k�r�|d}tj||||d�|j_dStjd|�dSdS)Nr�r�r=r�zingress-zonerz(Ingress zone '%s' already set, ignoring.zegress-zonez'Egress zone '%s' already set, ignoring.rz$Invalid rule: Source outside of ruleTz:Invalid rule: More than one source in rule '%s', ignoring.Fr%r&r'r#r}r$)r%zUnknown XML element '%s')r&r')rr�rCrEZparser_check_element_attrsrer�r\r=rrrr�r�r�rGrr3r�r@rrBrUrZRich_Source)r�rr`r�r%r�r}r$rcrcrdr�Nsf








z"policy_ContentHandler.startElementcCstj||�t||�dS)N)rr�rj)r�rrcrcrdr��sz policy_ContentHandler.endElementN)r�r�r�r�r�r�rcrcrcrdr�Gs@r�Fc
Cst�}|jd�s ttjd|��|dd	�|_|s>|j|j�||_||_|j	t
j�rZdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}	zttjd|	j���WYdd}	~	XnXWdQRX~~|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid policy file: %s���)rr�rrr�rr��filename�pathr�r�
ETC_FIREWALLDZbuiltin�defaultr��saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_POLICYZgetException)
r�r�Z
no_check_namer�ry�parserr�fr�msgrcrcrdr�s6




(c
Cs�|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|j|jk�r0t|j�|d<|j|d<|jd
|�|jd�t||�x8t|j�D]*}	|jd�|jdd|	i�|jd��qfWx8t|j�D]*}	|jd�|jdd|	i�|jd��q�W|jd
�|jd�|j �|j!�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingr!r�r=r�r�r|z  zingress-zonerzegress-zone)"r�r�r�os�exists�shutilZcopy2rfrr2�dirnamer�rr��mkdir�ior�rZ
startDocumentr�r=r�rBr�r�r�r�rr�rxr�r�ZendDocument�close)
r�r��_pathrr��dirpathr�ryr`r�rcrcrdr�sN 







)F)N))�__all__Zxml.saxr�r�r�r�ZfirewallrZfirewall.functionsrrrr	r
Zfirewall.core.baserrr
Zfirewall.core.io.io_objectrrrrrrZ
firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrerjrwr{r�rr�rrrcrcrcrd�<module>s4

 F[nL
io/__pycache__/zone.cpython-36.pyc000064400000031307151731527070013000 0ustar003

��g�M�@sdddgZddljZddlZddlZddlZddlmZddlm	Z	m
Z
mZmZm
Z
mZmZddlmZmZddlmZmZmZmZdd	lmZmZmZmZdd
lmZddlm Z ddlm!Z!dd
l"m#Z#Gdd�de�Z$Gdd�de�Z%ddd�Z&ddd�Z'dS)�Zone�zone_reader�zone_writer�N)�config)�checkIPnMask�
checkIP6nMask�checkInterface�uniqify�max_zone_name_len�
u2b_if_py2�	check_mac)�DEFAULT_ZONE_TARGET�ZONE_TARGETS)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�common_startElement�common_endElement�common_check_config�
common_writer)�rich)�log)�errors)�
FirewallErrorcsfeZdZdZd@dAdBdCdDd	dgfd
dEgfddgfdFd
dGgfddgfddgfddgfddgfddHgfdIdJfZdddgZddddgddgdgdgdddgdgddddgddgddddddgdgdd�Zddddgd gd!d"gd#d$gd%d&d'd#d(gd%d'd(gd)d*gd+gd,gd-�	Zed.d/��Z	�fd0d1�Z
d2d3�Zd4d5�Z�fd6d7�Z
�fd8d9�Zd:d;�Z�fd<d=�Zd>d?�Z�ZS)Krz Zone class �version��short�description�UNUSEDF�target�services�ports�icmp_blocks�
masquerade�
forward_ports�
interfaces�sources�	rules_str�	protocols�source_ports�icmp_block_inversion�forward�_�-�/N�name�port�protocol�value�set)rr�zone�servicer1z
icmp-blockz	icmp-typer,zforward-port�	interface�rule�source�destinationr2zsource-portrZauditZaccept�rejectZdropZmark�limitzicmp-block-inversion�	immutableZenabledzto-portzto-addr�familyZpriority�address�mac�invert�ipset�prefix�level�typeZburst)	r5r$zforward-portr8r9r:rr;r<cCs8x&ttj�D]\}\}}||kr|SqWttjd��dS)Nz
index_of())�	enumerater�IMPORT_EXPORT_STRUCTURErrZ
UNKNOWN_ERROR)�element�iZelZdummy�rJ�/usr/lib/python3.6/zone.py�index_ofdsz
Zone.index_ofcs�tt|�j�d|_d|_d|_d|_t|_g|_	g|_
g|_g|_d|_
d|_g|_g|_g|_g|_d|_g|_g|_d|_d|_d|_dS)NrF)�superr�__init__rrrrr
r r!r"r)r#r,r$r%r*r&r'�	fw_config�rulesr(r+�combined�applied)�self)�	__class__rJrKrNks,z
Zone.__init__cCs�d|_d|_d|_d|_t|_|jdd�=|jdd�=|jdd�=|j	dd�=d|_
d|_|jdd�=|j
dd�=|jdd�=|jdd�=d|_|jdd�=|jdd�=d|_d|_d|_dS)NrF)rrrrr
r r!r"r)r#r,r$r%r*r&r'rOrPr(r+rQrR)rSrJrJrK�cleanup�s*zZone.cleanupcCs�t|j�|_t|j�|_t|j�|_t|j�|_dd�|jD�|_dd�|jD�|_dd�|jD�|_dd�|jD�|_dd�|j	D�|_	dd�|j
D�|_
dd�|jD�|_d	d�|jD�|_d
d�|j
D�|_
dd�|jD�|_dS)
z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsg|]}t|��qSrJ)r)�.0�srJrJrK�
<listcomp>�sz'Zone.encode_strings.<locals>.<listcomp>cSs g|]\}}t|�t|�f�qSrJ)r)rV�po�prrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrZrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrIrJrJrKrX�scSs0g|](\}}}}t|�t|�t|�t|�f�qSrJ)r)rVZp1Zp2Zp3Zp4rJrJrKrX�scSs g|]\}}t|�t|�f�qSrJ)r)rVrYrZrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrIrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrWrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrWrJrJrKrX�scSsg|]}t|��qSrJ)r)rVrWrJrJrKrX�sN)rrrrr r!r"r)r#r%r*r&r'rPr()rSrJrJrK�encode_strings�szZone.encode_stringscsN|dkr8dd�|D�|_tt|�j|dd�|jD��ntt|�j||�dS)Nr(cSsg|]}tj|d��qS))Zrule_str)rZ	Rich_Rule)rVrWrJrJrKrX�sz$Zone.__setattr__.<locals>.<listcomp>cSsg|]}t|��qSrJ)�str)rVrWrJrJrKrX�s)rPrMr�__setattr__)rSr0r3)rTrJrKr]�s zZone.__setattr__cstt|�j�}|d=|S)Nr)rMr�export_config_dict)rSZconf)rTrJrKr^�szZone.export_config_dictcCsLt||||�|dkr.|tkr*ttj|���n|dkr�xl|D]d}t|�sTttj|��|jr<xD|jj�D]6}||j	krvqf||jj
|�jkrfttjdj||���qfWq<Wn�|dk�rHx�|D]�}t
|�r�t|�r�t|�r�|jd�r�ttj|��|jr�xL|jj�D]>}||j	k�r�q||jj
|�jk�rttjdj||����qWq�WdS)Nr r&z)interface '{}' already bound to zone '{}'r'zipset:z&source '{}' already bound to zone '{}')rrrr�INVALID_TARGETrZINVALID_INTERFACErOZ	get_zonesr0Zget_zoner&�formatrrr�
startswith�INVALID_ADDRr')rSr�itemZ
all_configr7r5r9rJrJrK�
_check_config�s6



zZone._check_configcs�tt|�j|�|jd�r,ttjd|��n�|jd�rHttjd|��n�|jd�dkrhttjd|��nnd|kr�|d|j	d��}n|}t
|�t�kr�ttjd|t
|�t�|jf��|j
r�||j
j�kr�ttjd��dS)Nr/z'%s' can't start with '/'z'%s' can't end with '/'�zmore than one '/' in '%s'z'Zone of '%s' has %d chars, max is %d %sz+Zones can't have the same name as a policy.)rMr�
check_namerarr�INVALID_NAME�endswith�count�find�lenr
rQrOZget_policy_objectsZ
NAME_CONFLICT)rSr0Zchecked_name)rTrJrKrf�s,

zZone.check_namec
Cs�d|_d|_d|_d|_d|_x$|jD]}||jkr&|jj|�q&Wx$|jD]}||jkrL|jj|�qLWx$|jD]}||jkrr|jj|�qrWx$|j	D]}||j	kr�|j	j|�q�Wx$|j
D]}||j
kr�|j
j|�q�Wx$|jD]}||jkr�|jj|�q�W|j�rd|_|j
�rd|_
x(|jD]}||jk�r&|jj|��q&Wx(|jD]}||jk�rP|jj|��qPWx,|jD]"}	|jj|	�|jjt|	���qzW|j�r�d|_dS)NTr)rQ�filenamerrrr&�appendr'r!r"r)r#r,r$r%r*rPr(r\r+)
rSr5r7r9r6r1�protoZicmpr,r8rJrJrK�combine�sL





zZone.combine)rr)rr)rr)rF)r r)rr)r$F)rrrr)rr)r+F)r,F)�__name__�
__module__�__qualname__�__doc__rGZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRS�staticmethodrLrNrUr[r]r^rdrfro�
__classcell__rJrJ)rTrKr(sx


c@s$eZdZdd�Zdd�Zdd�ZdS)�zone_ContentHandlercCs"tj||�d|_d|_d|_dS)NF)rrN�_rule�_rule_errorZ	_limit_ok)rSrcrJrJrKrN szzone_ContentHandler.__init__c	Cs�tj|||�|jrdS|jj||�t|||�r6dS|dkr�d|krVtjd|d�d|krj|d|j_d|kr�tjd|d�d|kr�|d}|t	kr�t
tj|��|dkr�|t
kr�||j_�n�|d	kr�|jjr�tjd
�nd|j_�n�|dk�rh|j�rtjd
�d|_dSd|k�r.tjd�d|_dS|d|jjk�rT|jjj|d�ntjd|d��n8|dk�rf|j�r |jj�r�tjdt|j��d|_dSd}d|k�r�|dj�d$k�r�d}d}}}d|k�r�|d}d|k�r�|d}d|k�r|d}tj||||d�|j_dSd|k�rBd|k�rBtjd�dSd|k�rdd|k�rdtjd�dSd|k�r~tjd|d�d|k�r�tjd�dSd|k�r�t|d��r�t|d��r�t|d��r�t
tj|d��d|k�r$d|d}||jjk�r|jjj|�ntjd |d�d|k�r�|d}||jjk�rT|jjj|�ntjd |d�n:|d!k�r�|jj�r�tjd"�nd|j_ntjd#|�dSdS)%Nr5r0z'Ignoring deprecated attribute name='%s'rr=z,Ignoring deprecated attribute immutable='%s'r rr,zForward already set, ignoring.Tr7z$Invalid rule: interface use in rule.z Invalid interface: Name missing.z%Interface '%s' already set, ignoring.r9z:Invalid rule: More than one source in rule '%s', ignoring.FrA�yes�truer?r@rB)rAz$Invalid source: No address no ipset.z"Invalid source: Address and ipset.r>z)Ignoring deprecated attribute family='%s'z+Invalid source: Invertion not allowed here.zipset:%sz"Source '%s' already set, ignoring.zicmp-block-inversionz+Icmp-Block-Inversion already set, ignoring.zUnknown XML element '%s')ryrz)r�startElementrxrcZparser_check_element_attrsrrZwarningrrrrr_r
r r,rwr&rmr9r\�lowerrZRich_Sourcerrrrbr'r+)	rSr0�attrsr rAZaddrr@rB�entryrJrJrKr{&s�

























z zone_ContentHandler.startElementcCstj||�t||�dS)N)r�
endElementr)rSr0rJrJrKr�szzone_ContentHandler.endElementN)rprqrrrNr{rrJrJrJrKrvsprvFc
Cst�}|jd�s ttjd|��|dd	�|_|s>|j|j�||_||_|j	t
j�rZdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}	zttjd|	j���WYdd}	~	XnXWdQRX~~t�r|j�|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid zone file: %s���)rrhrrrgr0rfrl�pathrar�
ETC_FIREWALLDZbuiltin�defaultrv�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_ZONEZgetExceptionrr[)
rlr�Z
no_check_namer5�handler�parserr0�fr9�msgrJrJrKr�s:




(cCs\|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|jtk�r*|j|d<|jd|�|jd
�t||�x8t|j�D]*}	|jd�|jdd|	i�|jd
��qVWx\t|j�D]N}
|jd�d|
k�r�|jdd|
dd�i�n|jdd|
i�|jd
��q�W|j�r
|jd�|jdi�|jd
�|j�r2|jd�|jdi�|jd
�|jd�|jd
�|j �|j!�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrr r5�
z  r7r0zipset:r9rB�r?zicmp-block-inversionr,)"r�rlr0�os�exists�shutilZcopy2�	Exceptionr�error�dirnamerarr��mkdir�ior�rZ
startDocumentrr r
r{ZignorableWhitespacerr	r&Z
simpleElementr'r+r,rZendDocument�close)r5r��_pathr0r��dirpathr�r�r}r7r9rJrJrKr�s` 












)F)N)(�__all__Zxml.saxr�r�r�r�ZfirewallrZfirewall.functionsrrrr	r
rrZfirewall.core.baser
rZfirewall.core.io.io_objectrrrrZfirewall.core.io.policyrrrrZ
firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrrvrrrJrJrJrK�<module>s$

$x|
io/__pycache__/ipset.cpython-36.pyc000064400000025614151731527070013155 0ustar003

��g�R�@sdZdddgZddljZddlZddlZddlZddlmZddl	m
Z
mZmZm
Z
mZmZmZmZmZddlmZmZmZmZdd	lmZmZdd
lmZmZmZmZddl m!Z!ddlm"Z"dd
l#m$Z$Gdd�de�Z%Gdd�de�Z&dd�Z'ddd�Z(dS)z$ipset io XML handler, reader, writer�IPSet�ipset_reader�ipset_writer�N)�config)	�checkIP�checkIP6�checkIPnMask�
checkIP6nMask�
u2b_if_py2�	check_mac�
check_port�checkInterface�
checkProtocol)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�IPSET_TYPES�IPSET_CREATE_OPTIONS)�check_icmp_name�check_icmp_type�check_icmpv6_name�check_icmpv6_type)�log)�errors)�
FirewallErrorcs�eZdZddd d!dddifddgffZdZd	d
ddgZd
d
dgdgd
d�Zdgdgd�Z�fdd�Zdd�Z	dd�Z
edd��Zdd�Z
�fdd�Z�ZS)"r�version��short�description�type�options�entriesz
(ssssa{ss}as)�_�-�:�.N�name)rr�ipset�option�entry�value)r(r)cs<tt|�j�d|_d|_d|_d|_g|_i|_d|_	dS)NrF)
�superr�__init__rrrr r"r!�applied)�self)�	__class__��/usr/lib/python3.6/ipset.pyr-CszIPSet.__init__cCs8d|_d|_d|_d|_|jdd�=|jj�d|_dS)NrF)rrrr r"r!�clearr.)r/r1r1r2�cleanupMs
z
IPSet.cleanupcCs\t|j�|_t|j�|_t|j�|_t|j�|_dd�|jj�D�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsi|]\}}t|�t|��qSr1)r
)�.0�k�vr1r1r2�
<dictcomp>^sz(IPSet.encode_strings.<locals>.<dictcomp>cSsg|]}t|��qSr1)r
)r5�er1r1r2�
<listcomp>`sz(IPSet.encode_strings.<locals>.<listcomp>N)r
rrrr r!�itemsr")r/r1r1r2�encode_stringsVszIPSet.encode_stringsc
Csd}d|kr|ddkrd}|jd�s6ttjd|��|dd�jd�}|jd�}t|�t|�ksnt|�d	kr�ttjd
||f���xztt|��D�]h}||}||}|dk�r�d|ko�|dk�rh|d	kr�ttjd
|||f��|jd�}	t|	�dk�rttjd||||f��x�|	D]J}
|dk�r2t|
��sH|dk�rt	|
��rttjd|
|||f���qWnh|dk�r�|dk�r�ttjd||||f��|dk�r�t
}nt}nt	}||��s�ttjd||||f��q�|dk�r@d|k�r�|jd�}	t|	�dk�rttjd||||f��|dk�r0t|	d��sJ|dk�rft	|	d��rfttjd|	d|||f��|dk�r�t
|	d	��s�|dk�r>t|	d	��r>ttjd|	d	|||f��n�|jd��r�|dk�o�|dk�o�|dk�s�ttjd||||f��|dk�rt
|��s&|dk�r�t|��r�ttjd||||f��q�|dk�rvt
|��s`|dk�r�ttjd||f��q�|dk�r�d|k�r�|jd�}	t|	�dk�r�ttjd|��|	ddk�r|dk�r�ttjd||f��t|	d	��r�t|	d	��r�ttjd|	d	|f��n�|	dd1k�r~|dk�rDttjd||f��t|	d	��r�t|	d	��r�ttjd!|	d	|f��n^|	dd2k�r�t|	d��r�ttjd&|	d|f��n&t|	d	��s�ttjd'|	d	|f��nt|��s�ttjd(||f��q�|d)k�r�|jd*��rPyt|d+�}Wn*tk
�rLttjd,||f��YnXn8yt|�}Wn*tk
�r�ttjd,||f��YnX|dk�s�|d-k�r�ttjd,||f��q�|d.k�r�t|��s�t|�d/k�r�ttjd0||f��q�ttjd|��q�WdS)3NZipv4�family�inet6Zipv6zhash:zipset type '%s' not usable��,�z)entry '%s' does not match ipset type '%s'Zipr$z invalid address '%s' in '%s'[%d]�z.invalid address range '%s' in '%s' for %s (%s)z(invalid address '%s' in '%s' for %s (%s)z0.0.0.0rZnetz/0zhash:net,ifaceZmacz00:00:00:00:00:00z invalid mac address '%s' in '%s'Zportr%zinvalid port '%s'Zicmpz(invalid protocol for family '%s' in '%s'zinvalid icmp type '%s' in '%s'�icmpv6�	ipv6-icmpz invalid icmpv6 type '%s' in '%s'�tcp�sctp�udp�udplitezinvalid protocol '%s' in '%s'zinvalid port '%s'in '%s'zinvalid port '%s' in '%s'ZmarkZ0x�zinvalid mark '%s' in '%s'l��Ziface�zinvalid interface '%s' in '%s')rCrD)rErFrGrH)�
startswithrr�
INVALID_IPSET�split�lenZ
INVALID_ENTRY�rangerrrr	�endswithrrrrrrr�int�
ValueErrorr
)
r*r!Z
ipset_typer=�flagsr;�i�flag�itemZsplitsZ_splitZip_checkZint_valr1r1r2�check_entrybs@























zIPSet.check_entrycCs�|dkr |tkr ttjd|��|dkr�x�|j�D]�}|tkrNttjd|��|dkr�yt||�}Wn,tk
r�ttj	d|||f��YnX|d	kr�ttj	d
|||f��q2|dkr2||dkr2ttj
||��q2WdS)Nr z'%s' is not valid ipset typer!zipset invalid option '%s'�timeout�hashsize�maxelemz)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer=�inetr>)rXrYrZ)r[r>)rrr�INVALID_TYPE�keysrrLrQrR�
INVALID_VALUE�INVALID_FAMILY)r/rrVZ
all_config�key�	int_valuer1r1r2�
_check_configs2

zIPSet._check_configcsrd|dkr6|dddkr6t|d�dkr6ttj��x&|dD]}tj||d|d�q@Wtt|�j|�dS)NrX��0r?r�)rNrrZIPSET_WITH_TIMEOUTrrWr,�
import_config)r/rr*)r0r1r2rf3s
zIPSet.import_config)rr)rr)rr)r r)�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr-r4r<�staticmethodrWrbrf�
__classcell__r1r1)r0r2r,s,


	7c@seZdZdd�Zdd�ZdS)�ipset_ContentHandlerc
Cs�tj|||�|jj||�|dkrpd|krX|dtkrLttjd|d��|d|j_d|krl|d|j_	�nz|dkr|�nn|dkr��nb|dk�r�d}d	|kr�|d	}|d
dkr�ttj
d|d
��|jjdko�|d
dk�r�ttj
d|d
|jjf��|d
dk�r&|�r&ttj
d|d
��|d
dk�r�yt|�}Wn.tk
�rnttj
d|d
|f��YnX|dk�r�ttj
d|d
|f��|d
dk�r�|dk�r�ttj|��|d
|jjk�r�||jj|d
<ntjd|d
�dS)Nr(r z%srrrr)rr+r'r=rXrYrZzUnknown option '%s'zhash:macz%Unsupported option '%s' for type '%s'z&Missing mandatory value of option '%s'z)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer[r>z Option %s already set, ignoring.)r=rXrYrZ)r=)r=rXrYrZ)rXrYrZ)r[r>)r�startElementrVZparser_check_element_attrsrrrr\r rZINVALID_OPTIONrQrRr^r_r!r�warning)r/r'�attrsr+rar1r1r2rm>sd

z!ipset_ContentHandler.startElementcCs(tj||�|dkr$|jjj|j�dS)Nr*)r�
endElementrVr"�appendZ_element)r/r'r1r1r2rpuszipset_ContentHandler.endElementN)rgrhrirmrpr1r1r1r2rl=s7rlc%Cst�}|jd�s ttjd|��|dd�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~d	|jk�rF|jd	d
k�rFt|j�dk�rFtjd|j�|jdd�=d}	t�}
x�|	t|j�k�r|j|	|
k�r�tjd
|j|	�|jj|	�nry|j |j|	|j|j!�Wn<tk
�r�}ztjd|�|jj|	�WYdd}~XnX|
j"|j|	�|	d7}	�qRW~
t#�r|j$�|S)Nz.xmlz'%s' is missing .xml suffixrcFTz%s/%s�rbznot a valid ipset file: %srXrdrz6ipset '%s': timeout option is set, entries are ignoredzEntry %s already set, ignoring.z
%s, ignoring.rA���)%rrPrrZINVALID_NAMEr'Z
check_name�filename�pathrKr�
ETC_FIREWALLDZbuiltin�defaultrl�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionrLZgetExceptionr!rNr"rrn�set�poprWr �addrr<)rtrur(�handler�parserr'�f�source�msgrTZentries_setr9r1r1r2rzs^




(cCs�|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�d	|ji}|j�r|jd
k�r|j|d<|jd|�|jd
�|j�rz|jd
k�rz|jd�|jdi�|j|j�|jd�|jd
�|j�r�|jd
k�r�|jd�|jdi�|j|j�|jd�|jd
�xZ|jj�D]L\}	}
|jd�|
d
k�r|jd|	|
d��n|jdd|	i�|jd
��q�WxD|jD]:}|jd�|jdi�|j|�|jd�|jd
��q(W|jd�|jd
�|j�|j �~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingr rrr(�
z  rrr))r'r+r'r*)!rurtr'�os�exists�shutilZcopy2�	Exceptionr�error�dirnamerKrrv�mkdir�ioryrZ
startDocumentr rrmZignorableWhitespacerZ
charactersrprr!r;Z
simpleElementr"ZendDocument�close)r(ru�_pathr'r��dirpathr�r~ror`r+r*r1r1r2r�sf 















)N))�__doc__�__all__Zxml.saxrxr�r�r�ZfirewallrZfirewall.functionsrrrr	r
rrr
rZfirewall.core.io.io_objectrrrrZfirewall.core.ipsetrrZfirewall.core.icmprrrrZfirewall.core.loggerrrZfirewall.errorsrrrlrrr1r1r1r2�<module>s&

,=5io/__pycache__/ifcfg.cpython-36.pyc000064400000007721151731527100013100 0ustar003

��g��@s^dZdgZddlZddlZddlZddlZddlmZddl	m
Z
mZmZGdd�de
�ZdS)zifcfg file parser�ifcfg�N)�log)�b2u�u2b�PY2c@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCsi|_g|_||_|j�dS)N)�_config�_deleted�filename�clear)�selfr	�r�/usr/lib/python3.6/ifcfg.py�__init__#szifcfg.__init__cCsi|_g|_dS)N)rr)rrrr
r
)szifcfg.clearcCs|jj�dS)N)rr
)rrrr
�cleanup-sz
ifcfg.cleanupcCs|jj|j��S)N)r�get�strip)r�keyrrr
r0sz	ifcfg.getcCs8t|j��}t|j��|j|<||jkr4|jj|�dS)N)rrrr�remove)rr�valueZ_keyrrr
�set3s
z	ifcfg.setcCsHd}x2|jj�D]$\}}|r$|d7}|d||f7}qWtrDt|�S|S)N��
z%s=%s)r�itemsrr)r�srrrrr
�__str__9sz
ifcfg.__str__cCsB|j�yt|jd�}Wn4tk
rL}ztjd|j|��WYdd}~XnXx�|D]�}|s^P|j�}t|�dksT|ddkr�qTdd�|jd	d�D�}t|�d
kr�qTt|d�d
kr�|dj	d�r�|dj
d�r�|ddd�|d<|ddkr�qTn,|jj|d�dk	�r tj
d
|j|j��qT|d|j|d<qTW|j�dS)N�rzFailed to load '%s': %s�r�#�;cSsg|]}|j��qSr)r)�.0�xrrr
�
<listcomp>Qszifcfg.read.<locals>.<listcomp>�=��"rz%%s: Duplicate option definition: '%s')rr���)r
�openr	�	Exceptionr�errorr�len�split�
startswith�endswithrrZwarning�close)r�f�msg�lineZpairrrr
�readBs2
z
ifcfg.readc:Cs�t|j�dkrdSg}y.tjddtjj|j�tjj|j�dd�}Wn2t	k
rv}zt
jd|��WYdd}~XnXd}d}ytj
|jddd	�}WnNt	k
r�}z0tjj|j�r�t
jd
|j|f��nd}WYdd}~X�ndX�x^|D�]T}|s�P|jd�}t|�dk�r(|�sD|jd�d}q�|d
dk�rPd}|j|�|jd�q�|jdd�}t|�dk�r~d}|j|d�q�|d
j�}	|dj�}
t|
�dk�r�|
jd��r�|
jd��r�|
dd�}
|	|k�r@|	|jk�r|j|	|
k�rd}|jd|	|j|	f�d}n$|	|jk�r"d}nd}|j|d�|j|	�q�d}q�Wt|j�d
k�r�xF|jj�D]8\}	}
|	|k�rz�qd|�s�d}|jd|	|
f�d}�qdW|�r�|j�|j�|�s�tj|j�dStjj|j��r8ytj|jd|j�WnBt	k
�r6}z$tj|j�td|j|f��WYdd}~XnXytj|j|j�WnBt	k
�r�}z$tj|j�td|j|f��WYdd}~XnXtj|jd�dS)NrZwtz%s.F)�mode�prefix�dir�deletez!Failed to open temporary file: %sZrtzUTF-8)r2�encodingzFailed to open '%s': %srTrrr"r#r$z%s=%s
z%s.bakzBackup of '%s' failed: %szFailed to create '%s': %si�r%)r)r�tempfileZNamedTemporaryFile�os�path�basenamer	�dirnamer'rr(�ior&�existsr�writer*r+r,r�appendrr-r�name�shutilZcopy2�IOErrorZmove�chmod)r�doneZ	temp_filer/Zmodified�emptyr.r0�prrrrr
r>_s�





$$zifcfg.writeN)�__name__�
__module__�__qualname__rr
rrrrr1r>rrrr
r"s	)�__doc__�__all__Zos.pathr8r<r7rAZfirewall.core.loggerrZfirewall.functionsrrr�objectrrrrr
�<module>sio/__pycache__/service.cpython-36.pyc000064400000020377151731527100013464 0ustar003

��g�2�@s�dddgZddljZddlZddlZddlZddlmZddlm	Z	ddl
mZmZm
Z
mZmZmZmZmZddlmZdd	lmZdd
lmZGdd�de�ZGdd
�d
e
�Zdd�Zddd�ZdS)�Service�service_reader�service_writer�N)�config)�
u2b_if_py2)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp�check_protocol�
check_address)�log)�errors)�
FirewallErrorcs�eZdZd d!d"dd#gfddgfdddifddgfd	d$gfd
dgfddgff
Zdd
gZdddd�Zddgddgdgdgddgddgdgdgd�Z�fdd�Zdd�Zdd�Z	dd�Z
�ZS)%r�version��short�description�ports�modules�destination�	protocols�source_ports�includes�helpers�_�-N)rr�service�name�port�protocol�value�ipv4�ipv6r)rr!r"�modulerzsource-port�include�helpercsNtt|�j�d|_d|_d|_g|_g|_g|_i|_	g|_
g|_g|_dS)Nr)
�superr�__init__rrrrrrrrrr)�self)�	__class__��/usr/lib/python3.6/service.pyr*DszService.__init__cCshd|_d|_d|_|jdd�=|jdd�=|jdd�=|jj�|jdd�=|j	dd�=|j
dd�=dS)Nr)rrrrrrr�clearrrr)r+r-r-r.�cleanupQs
zService.cleanupcCs�t|j�|_t|j�|_t|j�|_dd�|jD�|_dd�|jD�|_dd�|jj�D�|_dd�|jD�|_dd�|j	D�|_	dd�|j
D�|_
d	d�|jD�|_d
S)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSs g|]\}}t|�t|�f�qSr-)r)�.0�po�prr-r-r.�
<listcomp>dsz*Service.encode_strings.<locals>.<listcomp>cSsg|]}t|��qSr-)r)r1�mr-r-r.r4escSsi|]\}}t|�t|��qSr-)r)r1�k�vr-r-r.�
<dictcomp>fsz*Service.encode_strings.<locals>.<dictcomp>cSsg|]}t|��qSr-)r)r1r3r-r-r.r4gscSs g|]\}}t|�t|�f�qSr-)r)r1r2r3r-r-r.r4hscSsg|]}t|��qSr-)r)r1�sr-r-r.r4jscSsg|]}t|��qSr-)r)r1r9r-r-r.r4ksN)rrrrrrr�itemsrrrr)r+r-r-r.�encode_strings]szService.encode_stringscCs:|dkrJx>|D]6}|ddkr8t|d�t|d�qt|d�qWn�|dkrjx�|D]}t|�qXWn�|dkr�x�|D]}t|d�t|d�qxWn�|dkr�x�|D]*}|dkr�ttjd
|��t|||�q�Wn^|dk�r6xR|D]J}|jd��r|jdd�}d
|k�r|jd
d�}t	|�dkr�ttj
|��q�WdS)Nrrr�rrrr$r%z'%s' not in {'ipv4'|'ipv6'}r�
nf_conntrack_rr�)r$r%)rrr
rrZINVALID_DESTINATIONr�
startswith�replace�lenZINVALID_MODULE)r+r�itemZ
all_configr!�protorr&r-r-r.�
_check_configms8






zService._check_config)rr)rr)rr)rr)rr)�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr*r0r;rD�
__classcell__r-r-)r,r.r&s4


c@seZdZdd�ZdS)�service_ContentHandlercCs0tj|||�|jj||�|dkrTd|kr<tjd|d�d|krP|d|j_�n�|dkr`�n�|dkrl�n�|dk�r$|ddkr�t|d�t|d	�|d|d	f}||jj	kr�|jj	j
|�ntjd
|d|d	�nBt|d	�|d	|jjk�r|jjj
|d	�ntjd|d	��n|d	k�rtt|d�|d|jjk�r`|jjj
|d�ntjd|d��n�|d
k�r�t|d�t|d	�|d|d	f}||jj
k�r�|jj
j
|�ntjd|d|d	��nN|dk�r>xRdD]J}||k�r�t|||�||jjk�r&tjd|�n|||jj|<�q�Wn�|dk�r�|d}|jd��r~|jdd�}d|k�r~|jdd�}||jjk�r�|jjj
|�ntjd|�n�|dk�r�|d|jjk�r�|jjj
|d�ntjd|d�n@|dk�r,|d|jjk�r|jjj
|d�ntjd|d�dS)Nrr z'Ignoring deprecated attribute name='%s'rrrr!rr"z#Port '%s/%s' already set, ignoring.z$Protocol '%s' already set, ignoring.r#zsource-portz)SourcePort '%s/%s' already set, ignoring.rr$r%z2Destination address for '%s' already set, ignoringr&r=rrz"Module '%s' already set, ignoring.r'z#Include '%s' already set, ignoring.r(z"Helper '%s' already set, ignoring.)r$r%)r	�startElementrBZparser_check_element_attrsrZwarningrrrr�appendr
rrrrr?r@rrr)r+r �attrs�entry�xr&r-r-r.rJ�s�










z#service_ContentHandler.startElementN)rErFrGrJr-r-r-r.rI�srIc	Cst�}|jd�s ttjd|��|dd	�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~t�r|j�|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid service file: %s���)r�endswithrrZINVALID_NAMEr Z
check_name�filename�pathr?r�
ETC_FIREWALLDZbuiltin�defaultrI�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_SERVICEZgetExceptionrr;)	rSrTr�handler�parserr �f�source�msgr-r-r.r�s8




(cCsr|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|jd|�|jd�|j�rt|jd	k�rt|jd
�|jdi�|j|j�|jd�|jd�|j�r�|jd	k�r�|jd
�|jdi�|j|j�|jd�|jd�x>|jD]4}	|jd
�|jd|	d|	dd��|jd��q�Wx4|jD]*}
|jd
�|jdd|
i�|jd��qWx>|jD]4}	|jd
�|jd|	d|	dd��|jd��q<Wx4|jD]*}|jd
�|jdd|i�|jd��q|Wt|j �dk�r�|jd
�|jd|j �|jd�x4|j!D]*}|jd
�|jdd|i�|jd��q�Wx4|j"D]*}
|jd
�|jdd|
i�|jd��qW|jd�|jd�|j#�|j$�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrr�
z  rrr!rr<)r!r"r"r#zsource-portr&r rr'r()%rTrSr �os�exists�shutilZcopy2�	Exceptionr�error�dirnamer?rrU�mkdir�iorXr
Z
startDocumentrrJZignorableWhitespacerZ
charactersZ
endElementrrZ
simpleElementrrrrArrrZendDocument�close)rrT�_pathr r^�dirpathr\rZrLr!r"r&r'r(r-r-r.rs� 

















)N)�__all__Zxml.saxrWrbrirdZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr	r
rrr
rZfirewall.core.loggerrrZfirewall.errorsrrrIrrr-r-r-r.�<module>s

(mQio/__pycache__/firewalld_conf.cpython-36.pyc000064400000016616151731527100015003 0ustar003

��g�5�
@s~ddlZddlZddlZddlZddlmZddlmZddl	m
Z
mZmZddddd	d
ddd
ddddg
Z
Gdd�de�ZdS)�N)�config)�log)�b2u�u2b�PY2�DefaultZone�MinimalMark�
CleanupOnExit�CleanupModulesOnExit�Lockdown�
IPv6_rpfilter�IndividualCalls�	LogDenied�AutomaticHelpers�FirewallBackend�FlushAllOnReload�RFC3964_IPv4�AllowZoneDriftingc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)�firewalld_confcCsi|_g|_||_|j�dS)N)�_config�_deleted�filename�clear)�selfr�r�$/usr/lib/python3.6/firewalld_conf.py�__init__&szfirewalld_conf.__init__cCsi|_g|_dS)N)rr)rrrrr,szfirewalld_conf.clearcCs|jj�g|_dS)N)rrr)rrrr�cleanup0s
zfirewalld_conf.cleanupcCs|jj|j��S)N)r�get�strip)r�keyrrrr4szfirewalld_conf.getcCs8t|j��}t|j��|j|<||jkr4|jj|�dS)N)rrrr�remove)rr �valueZ_keyrrr�set7s
zfirewalld_conf.setcCsHd}x2|jj�D]$\}}|r$|d7}|d||f7}qWtrDt|�S|S)N��
z%s=%s)r�itemsrr)r�sr r"rrr�__str__=szfirewalld_conf.__str__cCs�|j�yt|jd�}W�n8tk
�rR}�ztjd|j|�|jdtj�|jdt	tj
��|jdtjrpdnd�|jdtjr�dnd�|jd	tj
r�dnd�|jd
tjr�dnd�|jdtjr�dnd�|jdtj�|jd
tj�|jdtj�|jdtj�r
dnd�|jdtj�r"dnd�|jdtj�r:dnd��WYdd}~XnX�x�|D]�}|�shP|j�}t|�dk�s\|dd.k�r��q\dd�|jd�D�}t|�dk�r�tjd|j���q\nr|dtk�r�tjd|j���q\nN|ddk�rtjd|j���q\n*|jj|d�dk	�r:tjd|j���q\|d|j|d<�q\W|j�|jd��s�tjdtj�|jdt	tj��|jd�}yt|�WnPttfk
�r�|dk	�r�tj d |�r�|ndtj
�|jdt	tj
��YnX|jd�}|�s|j!�d/k�rJ|dk	�r2tj d#|�r(|ndtj�|jdtj�rDdnd�|jd�}|�sj|j!�d0k�r�|dk	�r�tj d$|�r�|ndtj�|jdtj�r�dnd�|jd	�}|�s�|j!�d1k�r|dk	�r�tj d%|�r�|ndtj
�|jd	tj
�r�dnd�|jd
�}|�s"|j!�d2k�r^|dk	�rFtj d&|�r<|ndtj�|jd
tj�rXdnd�|jd�}|�s~|j!�d3k�r�|dk	�r�tj d'|�r�|ndtj�|jdtj�r�dnd�|jd�}|�s�|tj"k�r|dk	�r�tj d(|tj�|jdt	tj��|jd
�}|�s&|j!�tj#k�r\|dk	�rJtj d)|�r@|ndtj�|jd
t	tj��|jd�}|�s~|j!�tj$k�r�|dk	�r�tj d*|�r�|ndtj�|jdt	tj��|jd�}|�s�|j!�d4k�r
|dk	�r�tj d+|�r�|ndtj�|jdt	tj��|jd�}|�s*|j!�d5k�r`|dk	�rNtj d,|�rD|ndtj�|jdt	tj��|jd�}|�s�|j!�d6k�r�|dk	�r�tj d-|�r�|ndtj�|jdt	tj��dS)7N�rzFailed to load '%s': %srrr	�yes�nor
rrr
rrrrrr�r�#�;cSsg|]}|j��qSr)r)�.0�xrrr�
<listcomp>bsz'firewalld_conf.read.<locals>.<listcomp>�=�zInvalid option definition: '%s'zInvalid option: '%s'r$zMissing value: '%s'z!Duplicate option definition: '%s'z0DefaultZone is not set, using default value '%s'z7MinimalMark '%s' is not valid, using default value '%d'�false�truez7CleanupOnExit '%s' is not valid, using default value %sz>CleanupModulesOnExit '%s' is not valid, using default value %sz2Lockdown '%s' is not valid, using default value %sz7IPv6_rpfilter '%s' is not valid, using default value %sz9IndividualCalls '%s' is not valid, using default value %sz3LogDenied '%s' is invalid, using default value '%s'z:AutomaticHelpers '%s' is not valid, using default value %sz9FirewallBackend '%s' is not valid, using default value %sz:FlushAllOnReload '%s' is not valid, using default value %sz6RFC3964_IPv4 '%s' is not valid, using default value %sz;AllowZoneDrifting '%s' is not valid, using default value %s)r-r.)r+r4r*r5)r+r4r*r5)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)%r�openr�	Exceptionr�errorr#rZ
FALLBACK_ZONE�strZFALLBACK_MINIMAL_MARKZFALLBACK_CLEANUP_ON_EXITZ FALLBACK_CLEANUP_MODULES_ON_EXITZFALLBACK_LOCKDOWNZFALLBACK_IPV6_RPFILTERZFALLBACK_INDIVIDUAL_CALLSZFALLBACK_LOG_DENIEDZFALLBACK_AUTOMATIC_HELPERSZFALLBACK_FIREWALL_BACKENDZFALLBACK_FLUSH_ALL_ON_RELOADZFALLBACK_RFC3964_IPV4ZFALLBACK_ALLOW_ZONE_DRIFTINGr�len�split�
valid_keysrr�close�int�
ValueError�	TypeErrorZwarning�lowerZLOG_DENIED_VALUESZAUTOMATIC_HELPERS_VALUESZFIREWALL_BACKEND_VALUES)r�f�msg�lineZpairr"rrr�readFs
























zfirewalld_conf.readc:Cs�t|j�dkrdSg}tjjtj�s2tjtjd�y.tj	ddtjj
|j�tjj|j�dd�}Wn2t
k
r�}ztjd|��WYdd}~XnXd}d}ytj|jdd	d
�}WnPt
k
�r}z0tjj|j�r�tjd|j|f��nd}WYdd}~X�n6X�x0|D�]&}|�sP|jd�}t|�dk�rH|�s2|jd�d
}n�|ddk�rpd}|j|�|jd�n�|jd�}t|�dk�r�d}|j|d��q|dj�}	|dj�}
|	|k�r.|	|jk�r�|j|	|
k�r�d}|jd|	|j|	f�d
}n$|	|jk�rd
}nd}|j|d�|j|	�nd
}�qWt|j�dk�r�x^|jj�D]P\}	}
|	|k�rj�qT|	dk�rx�qT|�s�|jd�d
}|jd|	|
f�d
}�qTW|�r�|j�|j�|�s�tj|j�dStjj|j��r@ytj|jd|j�WnBt
k
�r>}z$tj|j�td|j|f��WYdd}~XnXytj|j|j�WnBt
k
�r�}z$tj|j�td|j|f��WYdd}~XnXtj|jd�dS)Nr,i�Zwtz%s.F)�mode�prefix�dir�deletez!Failed to open temporary file: %sZrtzUTF-8)rF�encodingzFailed to open '%s': %sr%Trr-r2r3z%s=%s
rrz%s.oldzBackup of '%s' failed: %szFailed to create '%s': %si�)rr) r:r�os�path�existsrZ
ETC_FIREWALLD�mkdir�tempfileZNamedTemporaryFile�basenamer�dirnamer7rr8�ior6r�writer;r�appendr&r=r!�name�shutilZcopy2�IOErrorZmove�chmod)r�doneZ	temp_filerCZmodified�emptyrBrD�pr r"rrrrS�s�









$$zfirewalld_conf.writeN)�__name__�
__module__�__qualname__rrrrr#r(rErSrrrrr%s	r)Zos.pathrKrRrOrVZfirewallrZfirewall.core.loggerrZfirewall.functionsrrrr<�objectrrrrr�<module>sio/__pycache__/functions.cpython-36.pyc000064400000005256151731527100014033 0ustar003

��gy�@s�ddlZddlmZddlmZddlmZddlmZddl	m
Z
ddlmZddl
mZdd	lmZdd
lmZddlmZddlmZdd
lmZdd�ZdS)�N)�config)�
FirewallError)�FirewallConfig)�zone_reader)�service_reader)�ipset_reader)�icmptype_reader)�
helper_reader)�
policy_reader)�Direct)�LockdownWhitelist)�firewalld_confc	-Cs|t|�}t|jtjtjgd�t|jtjtj	gd�t
|jtjtj
gd�t|jtjtjgd�t|jtjtjgd�t|jtjtjgd�d�}�x
|j�D�]�}x�||dD]�}tjj|�s�q�x�ttj|��D]�}|j d�r�yD||d||�}|d
k�r�||_!|j"|j#��||d|�Wq�t$k
�rT}zt$|j%d	||j&f��WYdd}~Xq�t'k
�r�}zt'd	||f��WYdd}~Xq�Xq�Wq�Wq�Wtjj(tj)��r:y$t*tj)�}|j+�|j,|j-��Wnpt$k
�r}zt$|j%d	tj)|j&f��WYdd}~Xn6t'k
�r8}zt'd	tj)|f��WYdd}~XnXtjj(tj.��r�y$t/tj.�}|j+�|j,|j-��Wnpt$k
�r�}zt$|j%d	tj.|j&f��WYdd}~Xn6t'k
�r�}zt'd	tj.|f��WYdd}~XnXtjj(tj0��rxyt1tj0�}|j+�Wnpt$k
�rB}zt$|j%d	tj0|j&f��WYdd}~Xn6t'k
�rv}zt'd	tj0|f��WYdd}~XnXdS)N)�reader�add�dirs)Zipset�helperZicmptypeZservice�zone�policyrz.xmlrrrrz'%s': %s)rr)2rrZ	add_ipsetrZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSr	Z
add_helperZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSrZadd_icmptypeZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESrZadd_serviceZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESrZadd_zoneZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr
Zadd_policy_objectZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIES�keys�os�path�isdir�sorted�listdir�endswith�	fw_configZcheck_config_dictZexport_config_dictr�code�msg�	Exception�isfileZFIREWALLD_DIRECTr�read�check_configZ
export_configZLOCKDOWN_WHITELISTrZFIREWALLD_CONFr
)	�fwrZreadersrZ_dir�file�obj�errorr�r&�/usr/lib/python3.6/functions.pyr!&sz

&.
($
($
(r!)rZfirewallrZfirewall.errorsrZfirewall.core.fw_configrZfirewall.core.io.zonerZfirewall.core.io.servicerZfirewall.core.io.ipsetrZfirewall.core.io.icmptyperZfirewall.core.io.helperr	Zfirewall.core.io.policyr
Zfirewall.core.io.directrZ#firewall.core.io.lockdown_whitelistrZfirewall.core.io.firewalld_confr
r!r&r&r&r'�<module>sio/__pycache__/ipset.cpython-36.opt-1.pyc000064400000025614151731527100014106 0ustar003

��g�R�@sdZdddgZddljZddlZddlZddlZddlmZddl	m
Z
mZmZm
Z
mZmZmZmZmZddlmZmZmZmZdd	lmZmZdd
lmZmZmZmZddl m!Z!ddlm"Z"dd
l#m$Z$Gdd�de�Z%Gdd�de�Z&dd�Z'ddd�Z(dS)z$ipset io XML handler, reader, writer�IPSet�ipset_reader�ipset_writer�N)�config)	�checkIP�checkIP6�checkIPnMask�
checkIP6nMask�
u2b_if_py2�	check_mac�
check_port�checkInterface�
checkProtocol)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�IPSET_TYPES�IPSET_CREATE_OPTIONS)�check_icmp_name�check_icmp_type�check_icmpv6_name�check_icmpv6_type)�log)�errors)�
FirewallErrorcs�eZdZddd d!dddifddgffZdZd	d
ddgZd
d
dgdgd
d�Zdgdgd�Z�fdd�Zdd�Z	dd�Z
edd��Zdd�Z
�fdd�Z�ZS)"r�version��short�description�type�options�entriesz
(ssssa{ss}as)�_�-�:�.N�name)rr�ipset�option�entry�value)r(r)cs<tt|�j�d|_d|_d|_d|_g|_i|_d|_	dS)NrF)
�superr�__init__rrrr r"r!�applied)�self)�	__class__��/usr/lib/python3.6/ipset.pyr-CszIPSet.__init__cCs8d|_d|_d|_d|_|jdd�=|jj�d|_dS)NrF)rrrr r"r!�clearr.)r/r1r1r2�cleanupMs
z
IPSet.cleanupcCs\t|j�|_t|j�|_t|j�|_t|j�|_dd�|jj�D�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsi|]\}}t|�t|��qSr1)r
)�.0�k�vr1r1r2�
<dictcomp>^sz(IPSet.encode_strings.<locals>.<dictcomp>cSsg|]}t|��qSr1)r
)r5�er1r1r2�
<listcomp>`sz(IPSet.encode_strings.<locals>.<listcomp>N)r
rrrr r!�itemsr")r/r1r1r2�encode_stringsVszIPSet.encode_stringsc
Csd}d|kr|ddkrd}|jd�s6ttjd|��|dd�jd�}|jd�}t|�t|�ksnt|�d	kr�ttjd
||f���xztt|��D�]h}||}||}|dk�r�d|ko�|dk�rh|d	kr�ttjd
|||f��|jd�}	t|	�dk�rttjd||||f��x�|	D]J}
|dk�r2t|
��sH|dk�rt	|
��rttjd|
|||f���qWnh|dk�r�|dk�r�ttjd||||f��|dk�r�t
}nt}nt	}||��s�ttjd||||f��q�|dk�r@d|k�r�|jd�}	t|	�dk�rttjd||||f��|dk�r0t|	d��sJ|dk�rft	|	d��rfttjd|	d|||f��|dk�r�t
|	d	��s�|dk�r>t|	d	��r>ttjd|	d	|||f��n�|jd��r�|dk�o�|dk�o�|dk�s�ttjd||||f��|dk�rt
|��s&|dk�r�t|��r�ttjd||||f��q�|dk�rvt
|��s`|dk�r�ttjd||f��q�|dk�r�d|k�r�|jd�}	t|	�dk�r�ttjd|��|	ddk�r|dk�r�ttjd||f��t|	d	��r�t|	d	��r�ttjd|	d	|f��n�|	dd1k�r~|dk�rDttjd||f��t|	d	��r�t|	d	��r�ttjd!|	d	|f��n^|	dd2k�r�t|	d��r�ttjd&|	d|f��n&t|	d	��s�ttjd'|	d	|f��nt|��s�ttjd(||f��q�|d)k�r�|jd*��rPyt|d+�}Wn*tk
�rLttjd,||f��YnXn8yt|�}Wn*tk
�r�ttjd,||f��YnX|dk�s�|d-k�r�ttjd,||f��q�|d.k�r�t|��s�t|�d/k�r�ttjd0||f��q�ttjd|��q�WdS)3NZipv4�family�inet6Zipv6zhash:zipset type '%s' not usable��,�z)entry '%s' does not match ipset type '%s'Zipr$z invalid address '%s' in '%s'[%d]�z.invalid address range '%s' in '%s' for %s (%s)z(invalid address '%s' in '%s' for %s (%s)z0.0.0.0rZnetz/0zhash:net,ifaceZmacz00:00:00:00:00:00z invalid mac address '%s' in '%s'Zportr%zinvalid port '%s'Zicmpz(invalid protocol for family '%s' in '%s'zinvalid icmp type '%s' in '%s'�icmpv6�	ipv6-icmpz invalid icmpv6 type '%s' in '%s'�tcp�sctp�udp�udplitezinvalid protocol '%s' in '%s'zinvalid port '%s'in '%s'zinvalid port '%s' in '%s'ZmarkZ0x�zinvalid mark '%s' in '%s'l��Ziface�zinvalid interface '%s' in '%s')rCrD)rErFrGrH)�
startswithrr�
INVALID_IPSET�split�lenZ
INVALID_ENTRY�rangerrrr	�endswithrrrrrrr�int�
ValueErrorr
)
r*r!Z
ipset_typer=�flagsr;�i�flag�itemZsplitsZ_splitZip_checkZint_valr1r1r2�check_entrybs@























zIPSet.check_entrycCs�|dkr |tkr ttjd|��|dkr�x�|j�D]�}|tkrNttjd|��|dkr�yt||�}Wn,tk
r�ttj	d|||f��YnX|d	kr�ttj	d
|||f��q2|dkr2||dkr2ttj
||��q2WdS)Nr z'%s' is not valid ipset typer!zipset invalid option '%s'�timeout�hashsize�maxelemz)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer=�inetr>)rXrYrZ)r[r>)rrr�INVALID_TYPE�keysrrLrQrR�
INVALID_VALUE�INVALID_FAMILY)r/rrVZ
all_config�key�	int_valuer1r1r2�
_check_configs2

zIPSet._check_configcsrd|dkr6|dddkr6t|d�dkr6ttj��x&|dD]}tj||d|d�q@Wtt|�j|�dS)NrX��0r?r�)rNrrZIPSET_WITH_TIMEOUTrrWr,�
import_config)r/rr*)r0r1r2rf3s
zIPSet.import_config)rr)rr)rr)r r)�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr-r4r<�staticmethodrWrbrf�
__classcell__r1r1)r0r2r,s,


	7c@seZdZdd�Zdd�ZdS)�ipset_ContentHandlerc
Cs�tj|||�|jj||�|dkrpd|krX|dtkrLttjd|d��|d|j_d|krl|d|j_	�nz|dkr|�nn|dkr��nb|dk�r�d}d	|kr�|d	}|d
dkr�ttj
d|d
��|jjdko�|d
dk�r�ttj
d|d
|jjf��|d
dk�r&|�r&ttj
d|d
��|d
dk�r�yt|�}Wn.tk
�rnttj
d|d
|f��YnX|dk�r�ttj
d|d
|f��|d
dk�r�|dk�r�ttj|��|d
|jjk�r�||jj|d
<ntjd|d
�dS)Nr(r z%srrrr)rr+r'r=rXrYrZzUnknown option '%s'zhash:macz%Unsupported option '%s' for type '%s'z&Missing mandatory value of option '%s'z)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer[r>z Option %s already set, ignoring.)r=rXrYrZ)r=)r=rXrYrZ)rXrYrZ)r[r>)r�startElementrVZparser_check_element_attrsrrrr\r rZINVALID_OPTIONrQrRr^r_r!r�warning)r/r'�attrsr+rar1r1r2rm>sd

z!ipset_ContentHandler.startElementcCs(tj||�|dkr$|jjj|j�dS)Nr*)r�
endElementrVr"�appendZ_element)r/r'r1r1r2rpuszipset_ContentHandler.endElementN)rgrhrirmrpr1r1r1r2rl=s7rlc%Cst�}|jd�s ttjd|��|dd�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~d	|jk�rF|jd	d
k�rFt|j�dk�rFtjd|j�|jdd�=d}	t�}
x�|	t|j�k�r|j|	|
k�r�tjd
|j|	�|jj|	�nry|j |j|	|j|j!�Wn<tk
�r�}ztjd|�|jj|	�WYdd}~XnX|
j"|j|	�|	d7}	�qRW~
t#�r|j$�|S)Nz.xmlz'%s' is missing .xml suffixrcFTz%s/%s�rbznot a valid ipset file: %srXrdrz6ipset '%s': timeout option is set, entries are ignoredzEntry %s already set, ignoring.z
%s, ignoring.rA���)%rrPrrZINVALID_NAMEr'Z
check_name�filename�pathrKr�
ETC_FIREWALLDZbuiltin�defaultrl�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionrLZgetExceptionr!rNr"rrn�set�poprWr �addrr<)rtrur(�handler�parserr'�f�source�msgrTZentries_setr9r1r1r2rzs^




(cCs�|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�d	|ji}|j�r|jd
k�r|j|d<|jd|�|jd
�|j�rz|jd
k�rz|jd�|jdi�|j|j�|jd�|jd
�|j�r�|jd
k�r�|jd�|jdi�|j|j�|jd�|jd
�xZ|jj�D]L\}	}
|jd�|
d
k�r|jd|	|
d��n|jdd|	i�|jd
��q�WxD|jD]:}|jd�|jdi�|j|�|jd�|jd
��q(W|jd�|jd
�|j�|j �~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingr rrr(�
z  rrr))r'r+r'r*)!rurtr'�os�exists�shutilZcopy2�	Exceptionr�error�dirnamerKrrv�mkdir�ioryrZ
startDocumentr rrmZignorableWhitespacerZ
charactersrprr!r;Z
simpleElementr"ZendDocument�close)r(ru�_pathr'r��dirpathr�r~ror`r+r*r1r1r2r�sf 















)N))�__doc__�__all__Zxml.saxrxr�r�r�ZfirewallrZfirewall.functionsrrrr	r
rrr
rZfirewall.core.io.io_objectrrrrZfirewall.core.ipsetrrZfirewall.core.icmprrrrZfirewall.core.loggerrrZfirewall.errorsrrrlrrr1r1r1r2�<module>s&

,=5io/__pycache__/icmptype.cpython-36.opt-1.pyc000064400000011635151731527100014612 0ustar003

��g��@s�dddgZddljZddlZddlZddlZddlmZddlm	Z	ddl
mZmZm
Z
mZddlmZdd	lmZdd
lmZGdd�de�ZGdd
�d
e
�Zdd�Zddd�ZdS)�IcmpType�icmptype_reader�icmptype_writer�N)�config)�
u2b_if_py2)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�log)�errors)�
FirewallErrorcspeZdZdddddgffZdZddgZd	d	d	d
�Zddgdd
gd�Z�fdd�Zdd�Z	dd�Z
dd�Z�ZS)r�version��short�description�destinationz(sssas)�_�-N)rr�icmptype�name�ipv4�ipv6)rrcs*tt|�j�d|_d|_d|_g|_dS)Nr)�superr�__init__rrrr)�self)�	__class__��/usr/lib/python3.6/icmptype.pyr8s
zIcmpType.__init__cCs"d|_d|_d|_|jdd�=dS)Nr)rrrr)rrrr�cleanup?szIcmpType.cleanupcCs:t|j�|_t|j�|_t|j�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsg|]}t|��qSr)r)�.0�mrrr�
<listcomp>Lsz+IcmpType.encode_strings.<locals>.<listcomp>N)rrrrr)rrrr�encode_stringsEszIcmpType.encode_stringscCs2|dkr.x$|D]}|dkrttjd|��qWdS)Nrrrz'%s' not from {'ipv4'|'ipv6'})rr)r
rZINVALID_DESTINATION)rr�itemZ
all_configrrrr�
_check_configNs
zIcmpType._check_config)rr)rr)rr)
�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrr#r%�
__classcell__rr)rrr%s	c@seZdZdd�ZdS)�icmptype_ContentHandlercCs�tj|||�|jj||�|dkrTd|kr>tjd|d�d|kr�|d|j_nT|dkr^nJ|dkrhn@|dkr�x6dD].}||krv||j�d
krv|jjj	t
|��qvWdS)Nrrz'Ignoring deprecated attribute name='%s'rrrrrr�yes�true)rr)r+r,)r	�startElementr$Zparser_check_element_attrsrZwarningr�lowerr�append�str)rr�attrs�xrrrr-Ys"
z$icmptype_ContentHandler.startElementN)r&r'r(r-rrrrr*Xsr*c	Cst�}|jd�s ttjd|��|dd	�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~t�r|j�|S)
Nz.xmlz%s is missing .xml suffix�FTz%s/%s�rbznot a valid icmptype file: %s���)r�endswithr
rZINVALID_NAMErZ
check_name�filename�path�
startswithr�
ETC_FIREWALLDZbuiltin�defaultr*�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_ICMPTYPEZgetExceptionrr#)	r7r8r�handler�parserr�f�source�msgrrrrms8




(c
Cs.|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|jd|�|jd�|j�rt|jd	k�rt|jd
�|jdi�|j|j�|jd�|jd�|j�r�|jd	k�r�|jd
�|jdi�|j|j�|jd�|jd�|j�r|jd
�i}x|jD]}	d||	<�q�W|jd|�|jd�|jd�|jd�|j�|j�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrr�
z  rrr+r)r8r7r�os�exists�shutilZcopy2�	Exceptionr�error�dirnamer9rr:�mkdir�ior=r
Z
startDocumentrr-ZignorableWhitespacerZ
charactersZ
endElementrrZ
simpleElementZendDocument�close)
rr8�_pathrrC�dirpathrAr?r1r2rrrr�s\ 











)N)�__all__Zxml.saxr<rGrNrIZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr	r
Zfirewall.core.loggerrrZfirewall.errorsr
rr*rrrrrr�<module>s

3io/__pycache__/__init__.cpython-36.pyc000064400000001227151731527100013554 0ustar003

��g<�@sjddlZdejkrfddlmZeed�s<dd�Zeede�ddlmZeed�sfd	d
�Z	eede	�dS)�NZ_xmlplus)�AttributesImpl�__contains__cCs|t|d�kS)NZ_attrs)�getattr)�self�name�r�/usr/lib/python3.6/__init__.py�__AttributesImpl__contains__sr	)�XMLGeneratorZ_writecCst|d�j|�dS)NZ_out)r�write)r�textrrr�__XMLGenerator_write$sr
)
Zxml�__file__Zxml.sax.xmlreaderr�hasattrr	�setattrZxml.sax.saxutilsr
r
rrrr�<module>s


io/__pycache__/icmptype.cpython-36.pyc000064400000011635151731527100013653 0ustar003

��g��@s�dddgZddljZddlZddlZddlZddlmZddlm	Z	ddl
mZmZm
Z
mZddlmZdd	lmZdd
lmZGdd�de�ZGdd
�d
e
�Zdd�Zddd�ZdS)�IcmpType�icmptype_reader�icmptype_writer�N)�config)�
u2b_if_py2)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�log)�errors)�
FirewallErrorcspeZdZdddddgffZdZddgZd	d	d	d
�Zddgdd
gd�Z�fdd�Zdd�Z	dd�Z
dd�Z�ZS)r�version��short�description�destinationz(sssas)�_�-N)rr�icmptype�name�ipv4�ipv6)rrcs*tt|�j�d|_d|_d|_g|_dS)Nr)�superr�__init__rrrr)�self)�	__class__��/usr/lib/python3.6/icmptype.pyr8s
zIcmpType.__init__cCs"d|_d|_d|_|jdd�=dS)Nr)rrrr)rrrr�cleanup?szIcmpType.cleanupcCs:t|j�|_t|j�|_t|j�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsg|]}t|��qSr)r)�.0�mrrr�
<listcomp>Lsz+IcmpType.encode_strings.<locals>.<listcomp>N)rrrrr)rrrr�encode_stringsEszIcmpType.encode_stringscCs2|dkr.x$|D]}|dkrttjd|��qWdS)Nrrrz'%s' not from {'ipv4'|'ipv6'})rr)r
rZINVALID_DESTINATION)rr�itemZ
all_configrrrr�
_check_configNs
zIcmpType._check_config)rr)rr)rr)
�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrr#r%�
__classcell__rr)rrr%s	c@seZdZdd�ZdS)�icmptype_ContentHandlercCs�tj|||�|jj||�|dkrTd|kr>tjd|d�d|kr�|d|j_nT|dkr^nJ|dkrhn@|dkr�x6dD].}||krv||j�d
krv|jjj	t
|��qvWdS)Nrrz'Ignoring deprecated attribute name='%s'rrrrrr�yes�true)rr)r+r,)r	�startElementr$Zparser_check_element_attrsrZwarningr�lowerr�append�str)rr�attrs�xrrrr-Ys"
z$icmptype_ContentHandler.startElementN)r&r'r(r-rrrrr*Xsr*c	Cst�}|jd�s ttjd|��|dd	�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~t�r|j�|S)
Nz.xmlz%s is missing .xml suffix�FTz%s/%s�rbznot a valid icmptype file: %s���)r�endswithr
rZINVALID_NAMErZ
check_name�filename�path�
startswithr�
ETC_FIREWALLDZbuiltin�defaultr*�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_ICMPTYPEZgetExceptionrr#)	r7r8r�handler�parserr�f�source�msgrrrrms8




(c
Cs.|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|jd|�|jd�|j�rt|jd	k�rt|jd
�|jdi�|j|j�|jd�|jd�|j�r�|jd	k�r�|jd
�|jdi�|j|j�|jd�|jd�|j�r|jd
�i}x|jD]}	d||	<�q�W|jd|�|jd�|jd�|jd�|j�|j�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrr�
z  rrr+r)r8r7r�os�exists�shutilZcopy2�	Exceptionr�error�dirnamer9rr:�mkdir�ior=r
Z
startDocumentrr-ZignorableWhitespacerZ
charactersZ
endElementrrZ
simpleElementZendDocument�close)
rr8�_pathrrC�dirpathrAr?r1r2rrrr�s\ 











)N)�__all__Zxml.saxr<rGrNrIZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr	r
Zfirewall.core.loggerrrZfirewall.errorsr
rr*rrrrrr�<module>s

3io/__pycache__/io_object.cpython-36.opt-1.pyc000064400000027540151731527100014717 0ustar003

��g5�@sdZddddddddgZd	d
ljZd	d
ljjZd	d
lZd	d
lZd	dlm	Z	d	dl
mZd	d
lm
Z
d	dl
mZd	dlmZejdkZGdd�de�ZGdd�de�ZGdd�de�ZGdd�de�ZGdd�dejj�ZGdd�dej�Zdd�Zdd�Zdd�Z dd�Z!d
S)z5Generic io_object handler, io specific check methods.�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp�check_protocol�
check_address�N)�OrderedDict)�	functions)�b2u)�errors)�
FirewallError�3c@s|eZdZdZfZdZgZiZiZdd�Z	dd�Z
dd�Zd	d
�Zdd�Z
d
d�Zdd�Zdd�Zdd�Zdd�Zdd�ZdS)rz; Abstract IO_Object as base for icmptype, service and zone z()cCs"d|_d|_d|_d|_d|_dS)N�F)�filename�path�name�defaultZbuiltin)�self�r�/usr/lib/python3.6/io_object.py�__init__2s
zIO_Object.__init__cCs6g}x(|jD]}|jtjt||d���qWt|�S)Nr	)�IMPORT_EXPORT_STRUCTURE�append�copy�deepcopy�getattr�tuple)r�ret�xrrr�
export_config9szIO_Object.export_configcCsXi}tdd�|jD��}x:|D]2}t||�s<tt||�t�rtjt||��||<qW|S)NcSsg|]}|d|df�qS)r	�r)�.0r rrr�
<listcomp>Asz0IO_Object.export_config_dict.<locals>.<listcomp>)�dictrr�
isinstance�boolrr)r�conf�type_formats�keyrrr�export_config_dict?s
zIO_Object.export_config_dictcCs�|j|�x�t|j�D]~\}\}}t||t�r~g}t�}x,||D] }||krD|j|�|j|�qDW~t||t	j
|��qt||t	j
||��qWdS)N)�check_config�	enumeraterr&�list�setr�add�setattrrr)rr(�i�elementZdummyZ_confZ_setr rrr�
import_configGs

zIO_Object.import_configc	Cs~|j|�xn|D]f}t||�s0ttjdj|���t||t�r`t||tt	j
tj||����qt||tj||��qWdS)Nz-Internal error. '{}' is not a valid attribute)
�check_config_dict�hasattrrr
Z
UNKNOWN_ERROR�formatr&r.r1r
�fromkeysrr)rr(r*rrr�import_config_dictWs


"zIO_Object.import_config_dictcCszt|t�s(ttjd|td�t|�f��t|�dkr@ttjd��x4|D],}|j�rF||j	krFttjd||f��qFWdS)Nz'%s' not of type %s, but %srr"zname can't be emptyz'%s' is not allowed in '%s')
r&�strrr
�INVALID_TYPE�type�lenZINVALID_NAME�isalnum�ADDITIONAL_ALNUM_CHARS)rr�charrrr�
check_namecs


zIO_Object.check_namecCsjt|�t|j�kr0ttjdt|�t|j�f��i}x&t|j�D]\}\}}||||<q@W|j|�dS)Nz structure size mismatch %d != %d)r=rrr
r;r-r5)rr(Z	conf_dictr2r �yrrrr,pszIO_Object.check_configcCsrtdd�|jD��}xX|D]P}|dd�|jD�krDttjdj|���|j||||�|j||||�qWdS)NcSsg|]}|d|df�qS)r	r"r)r#r rrrr$|sz/IO_Object.check_config_dict.<locals>.<listcomp>cSsg|]\}}|�qSrr)r#r rBrrrr$~szoption '{}' is not valid)r%rrr
ZINVALID_OPTIONr7�_check_config_structure�
_check_config)rr(r)r*rrrr5{s
zIO_Object.check_config_dictcCsdS)Nr)rZdummy1Zdummy2Zdummy3rrrrD�szIO_Object._check_configc	Cs`t|t|��s,ttjd|t|�t|�f��t|t�rrt|�dkrRttjd|��x|D]}|j||d�qXWn�t|t�r�t|�t|�kr�ttjd|t|�f��x�t	|�D]\}}|j|||�q�Wn�t|t
��r\t|j��d\}}xn|j�D]b\}}t|t|���s,ttjd|t|�t|�f��t|t|��s�ttjd|t|�t|�f��q�WdS)Nz'%s' not of type %s, but %sr"zlen('%s') != 1r	zlen('%s') != %d)r&r<rr
r;r.r=rCrr-r%�items)	rr(Z	structurer r2�valueZskeyZsvaluer*rrrrC�s8



z!IO_Object._check_config_structurecCs�|j�}d}||jkrdd}|j|dk	rdx:|j|D],}||krL|j|�q4ttjd||f��q4W||jkr�d}x$|j|D]}||kr~|j|�q~W|s�ttjd|��x |D]}ttjd||f��q�WdS)NFTzMissing attribute %s for %szUnexpected element %sz%s: Unexpected attribute %s)ZgetNames�PARSER_REQUIRED_ELEMENT_ATTRS�removerr
ZPARSE_ERROR�PARSER_OPTIONAL_ELEMENT_ATTRS)rr�attrsZ_attrs�foundr rrr�parser_check_element_attrs�s,



z$IO_Object.parser_check_element_attrsN)�__name__�
__module__�__qualname__�__doc__rZDBUS_SIGNATUREr?rGrIrr!r+r4r9rAr,r5rDrCrLrrrrr)s"
!cs$eZdZ�fdd�Zdd�Z�ZS)�UnexpectedElementErrorcstt|�j�||_dS)N)�superrQrr)rr)�	__class__rrr�szUnexpectedElementError.__init__cCs
d|jS)NzUnexpected element '%s')r)rrrr�__str__�szUnexpectedElementError.__str__)rMrNrOrrT�
__classcell__rr)rSrrQ�srQcs$eZdZ�fdd�Zdd�Z�ZS)�MissingAttributeErrorcstt|�j�||_||_dS)N)rRrVrr�	attribute)rrrW)rSrrr�szMissingAttributeError.__init__cCsd|j|jfS)Nz$Element '%s': missing '%s' attribute)rrW)rrrrrT�szMissingAttributeError.__str__)rMrNrOrrTrUrr)rSrrV�srVcs$eZdZ�fdd�Zdd�Z�ZS)�UnexpectedAttributeErrorcstt|�j�||_||_dS)N)rRrXrrrW)rrrW)rSrrr�sz!UnexpectedAttributeError.__init__cCsd|j|jfS)Nz'Element '%s': unexpected attribute '%s')rrW)rrrrrT�sz UnexpectedAttributeError.__str__)rMrNrOrrTrUrr)rSrrX�srXc@s4eZdZdd�Zdd�Zdd�Zdd�Zd	d
�ZdS)rcCs||_d|_dS)Nr)�item�_element)rrYrrrr�sz!IO_Object_ContentHandler.__init__cCs
d|_dS)Nr)rZ)rrrr�
startDocument�sz&IO_Object_ContentHandler.startDocumentcCs
d|_dS)Nr)rZ)rrrJrrr�startElement�sz%IO_Object_ContentHandler.startElementcCs*|dkr|j|j_n|dkr&|j|j_dS)N�short�description)rZrYr]r^)rrrrr�
endElement�sz#IO_Object_ContentHandler.endElementcCs|j|jdd�7_dS)N�
� )rZ�replace)r�contentrrr�
characters�sz#IO_Object_ContentHandler.charactersN)rMrNrOrr[r\r_rdrrrrr�s
c@s<eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
S)rcCsNtjjj|�|j|_|j|_ig|_|jd|_	g|_
d|_d|_d|_
dS)Nr"zutf-8F���)�sax�handler�ContentHandlerr�write�_write�flushZ_flushZ_ns_contextsZ_current_contextZ_undeclared_ns_mapsZ	_encodingZ_pending_start_elementZ_short_empty_elements)r�outrrrr�szIO_Object_XMLGenerator.__init__cCs*trdd�|j�D�}tjj|||�dS)a saxutils.XMLGenerator.startElement() expects name and attrs to be
            unicode and bad things happen if any of them is (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        cSsi|]\}}t|�t|��qSr)r)r#rrFrrr�
<dictcomp>sz7IO_Object_XMLGenerator.startElement.<locals>.<dictcomp>N)rrE�saxutils�XMLGeneratorr\)rrrJrrrr\sz#IO_Object_XMLGenerator.startElementcCs�trX|jdt|��x4|j�D](\}}|jdt|�tjt|��f�q W|jd�nF|jd|�x,|j�D] \}}|jd|tj|�f�qpW|jd�dS)z* slightly modified startElement()
        �<z %s=%sz/>N)rrjrrErnZ	quoteattr)rrrJrFrrr�
simpleElementsz$IO_Object_XMLGenerator.simpleElementcCstjj|t|��dS)z� saxutils.XMLGenerator.endElement() expects name to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        N)rnror_r)rrrrrr_sz!IO_Object_XMLGenerator.endElementcCstjj|t|��dS)z� saxutils.XMLGenerator.characters() expects content to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        N)rnrordr)rrcrrrrd%sz!IO_Object_XMLGenerator.characterscCstjj|t|��dS)a saxutils.XMLGenerator.ignorableWhitespace() expects content to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        N)rnro�ignorableWhitespacer)rrcrrrrr-sz*IO_Object_XMLGenerator.ignorableWhitespaceN)	rMrNrOrr\rqr_rdrrrrrrr�s
cCs�tj|�}|dkr$ttjd|��n`|dkr>ttjd|��nF|dkrXttjd|��n,t|�dkr�|d|dkr�ttjd|��dS)	N�zport number in '%s' is too bigr"z'%s' is invalid port rangezport range '%s' is ambiguousr	���re)rZgetPortRangerr
ZINVALID_PORTr=)ZportZ
port_rangerrrr5s
cCs|dkrttjd|��dS)N�tcp�udp�sctp�dccpz)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'})rurvrwrx)rr
�INVALID_PROTOCOL)�protocolrrrrDscCstj|�sttj|��dS)N)rZ
checkProtocolrr
ry)rzrrrrJs
cCs$tj||�s ttjd||f��dS)Nz'%s' is not valid %s address)rrrr
ZINVALID_ADDR)ZipvZaddrrrrrNs)"rP�__all__Zxml.saxrfZxml.sax.saxutilsrnr�sys�collectionsr
ZfirewallrZfirewall.functionsrr
Zfirewall.errorsr�versionr�objectr�	ExceptionrQrVrXrgrhrrorrrrrrrrr�<module>s0

		Cio/__pycache__/direct.cpython-36.pyc000064400000027263151731527100013277 0ustar003

��g�=�@s�ddljZddlZddlZddlZddlmZddlmZddl	m
Z
mZmZddl
mZmZmZddlmZddlmZddlmZdd	lmZdd
lmZGdd�de�ZGd
d�de�ZdS)�N)�config)�LastUpdatedOrderedDict)�	splitArgs�joinArgs�
u2b_if_py2)�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�log)�	ipXtables)�ebtables)�errors)�
FirewallErrorc@s$eZdZdd�Zdd�Zdd�ZdS)�direct_ContentHandlercCstj||�d|_dS)NF)r�__init__�direct)�self�item�r�/usr/lib/python3.6/direct.pyr(szdirect_ContentHandler.__init__cCs�tj|||�|jj||�|dkr@|jr6ttjd��d|_�n>|dkr�|js\tj	d�dS|d}|d}|d}|jj
t|�t|�t|��n�|dk�r6|js�tj	d	�dS|d}|dkr�ttjd
|��|d}|d}yt
|d�}Wn(tk
�rtj	d|d�dSXt|�t|�t|�|g|_nH|dk�rl|j�sVtj	d�dS|d}t|�g|_ntj	d|�dSdS)NrzMore than one direct tag.T�chainz$Parse Error: chain outside of direct�ipv�table�rulez#Parse Error: rule outside of direct�ipv4�ipv6�ebz"'%s' not from {'ipv4'|'ipv6'|'eb'}�priorityz'Parse Error: %s is not a valid priority�passthroughz&Parse Error: command outside of directzUnknown XML element %s)rrr)r�startElementrZparser_check_element_attrsrrr
ZPARSE_ERRORr
�error�	add_chainr�INVALID_IPV�int�
ValueError�_rule�_passthrough)r�nameZattrsrrrrrrrr,sT






z"direct_ContentHandler.startElementcCs�tj||�|dkrX|jrF|jjdd�t|j�D��|jj|j�n
tj	d�d|_nJ|dkr�|jr�|j
jdd�t|j�D��|jj|j
�n
tj	d	�d|_
dS)
NrcSsg|]}t|��qSr)r)�.0�xrrr�
<listcomp>dsz4direct_ContentHandler.endElement.<locals>.<listcomp>z2Error: rule does not have any arguments, ignoring.rcSsg|]}t|��qSr)r)r(r)rrrr*msz0Error: passthrough does not have any arguments, z	ignoring.z9Error: passthrough does not have any arguments, ignoring.)r�
endElementZ_elementr%�appendrr�add_ruler
r r&�add_passthrough)rr'rrrr+^s 
z direct_ContentHandler.endElementN)�__name__�
__module__�__qualname__rrr+rrrrr's2rcs<eZdZdZddBgfddddddgfgfdddgfgffZdZdd	d
dgd	d
ddgd	gd
�ZiZ�fdd�Zdd�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Zd>d?�Z d@dA�Z!�Z"S)C�Directz Direct class �chains��rulesr�passthroughsz(a(sss)a(sssias)a(sas))Nrrrr)rrrrcs0tt|�j�||_t�|_t�|_t�|_dS)N)�superr2r�filenamerr3r5r6)rr8)�	__class__rrr�s
zDirect.__init__cCsdS)Nr)r�confrZall_confrrr�
_check_config�szDirect._check_configcCsg}g}x>|jD]4}x.|j|D] }|jtt|�t|g���q WqW|j|�g}xR|jD]H}xB|j|D]4}|jt|d|d|d|dt|d�f��qnWq^W|j|�g}x8|jD].}x(|j|D]}|jt|t|�f��q�Wq�W|j|�t|�S)Nr��)r3r,�tuple�listr5r6)r�retr)�keyrrrrr�
export_config�s$$


zDirect.export_configcCs�|j�|j|�x�t|j�D]x\}\}}|dkrNx||D]}|j|�q<W|dkrrx||D]}|j|�q`W|dkrx||D]}|j|�q�WqWdS)Nr3r5r6)�cleanupZcheck_config�	enumerate�IMPORT_EXPORT_STRUCTUREr!r-r.)rr:�i�elementZdummyr)rrr�
import_config�s
zDirect.import_configcCs"|jj�|jj�|jj�dS)N)r3�clearr5r6)rrrrrC�s

zDirect.cleanupcCs�td�x4|jD]*}td|d|ddj|j|�f�qWtd�xZ|jD]P}td|d|d|df�x,|j|D]\}}td	|d
j|�f�q|WqNWtd�x@|jD]6}td|�x$|j|D]}td
d
j|��q�Wq�WdS)Nr3z  (%s, %s): %srr<�,r5z  (%s, %s, %s):r=z    (%d, ('%s'))z','r6z  %s:z
    ('%s'))�printr3�joinr5r6)rrAr�argsrrr�output�sz
Direct.outputcCs*dddg}||kr&ttjd||f��dS)Nrrrz'%s' not in '%s')rr
r")rrZipvsrrr�
_check_ipv�s
zDirect._check_ipvcCsF|j|�|dkrtjj�ntjj�}||krBttjd||f��dS)Nrrz'%s' not in '%s')rr)rOrZBUILT_IN_CHAINS�keysrrr
Z
INVALID_TABLE)rrrZtablesrrr�_check_ipv_table�s

zDirect._check_ipv_tablecCsd|j||�||f}||jkr(g|j|<||j|krH|j|j|�ntjd|||fd�dS)Nz(Chain '%s' for table '%s' with ipv '%s' zalready in list, ignoring)rQr3r,r
�warning)rrrrrArrrr!�s

zDirect.add_chaincCsn|j||�||f}||jkrX||j|krX|j|j|�t|j|�dkrj|j|=ntd|||f��dS)Nrz4Chain '%s' with table '%s' with ipv '%s' not in list)rQr3�remove�lenr$)rrrrrArrr�remove_chain�s
zDirect.remove_chaincCs,|j||�||f}||jko*||j|kS)N)rQr3)rrrrrArrr�query_chain�szDirect.query_chaincCs<|j||�||f}||jkr(|j|Std||f��dS)Nz&No chains for table '%s' with ipv '%s')rQr3r$)rrrrArrr�
get_chains�s

zDirect.get_chainscCs|jS)N)r3)rrrr�get_all_chainsszDirect.get_all_chainscCs�|j||�|||f}||jkr,t�|j|<|t|�f}||j|krV||j||<n*tjddj|�||fd||fd�dS)Nz(Rule '%s' for table '%s' and chain '%s' z',zwith ipv '%s' and priority %d zalready in list, ignoring)rQr5rr>r
rRrL)rrrrrrMrA�valuerrrr-s

zDirect.add_rulecCs�|j||�|||f}|t|�f}||jkrb||j|krb|j||=t|j|�dkr�|j|=n$tddj|�||fd||f��dS)Nrz(Rule '%s' for table '%s' and chain '%s' z',z)with ipv '%s' and priority %d not in list)rQr>r5rTr$rL)rrrrrrMrArYrrr�remove_rules

zDirect.remove_rulecCsb|j||�|||f}||jkr^x"|j|j�D]}|j||=q0Wt|j|�dkr^|j|=dS)Nr)rQr5rPrT)rrrrrArYrrr�remove_rules"s

zDirect.remove_rulescCs:|j||�|||f}|t|�f}||jko8||j|kS)N)rQr>r5)rrrrrrMrArYrrr�
query_rule+s
zDirect.query_rulecCsF|j||�|||f}||jkr*|j|Std||fd|��dS)Nz'No rules for table '%s' and chain '%s' z
with ipv '%s')rQr5r$)rrrrrArrr�	get_rules1s


zDirect.get_rulescCs|jS)N)r5)rrrr�
get_all_rules:szDirect.get_all_rulescCs^|j|�||jkrg|j|<||j|kr>|j|j|�ntjddj|�|fd�dS)NzPassthrough '%s' for ipv '%s'z',zalready in list, ignoring)rOr6r,r
rRrL)rrrMrrrr.?s


zDirect.add_passthroughcCsl|j|�||jkrN||j|krN|j|j|�t|j|�dkrh|j|=ntddj|�|fd��dS)NrzPassthrough '%s' for ipv '%s'z',znot in list)rOr6rSrTr$rL)rrrMrrr�remove_passthroughIs

zDirect.remove_passthroughcCs"|j|�||jko ||j|kS)N)rOr6)rrrMrrr�query_passthroughSs
zDirect.query_passthroughcCs.|j|�||jkr|j|Std|��dS)NzNo passthroughs for ipv '%s')rOr6r$)rrrrr�get_passthroughsWs


zDirect.get_passthroughscCs|jS)N)r6)rrrr�get_all_passthroughs^szDirect.get_all_passthroughscCs�|j�|jjd�s&ttjd|j��t|�}tj�}|j	|�t
|jd��b}tjd�}|j|�y|j
|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRXdS)Nz.xmlz'%s' is missing .xml suffix�rbzNot a valid file: %s)rCr8�endswithrr
ZINVALID_NAMEr�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_TYPEZgetException)r�handler�parser�f�source�msgrrr�readcs 


zDirect.readc
CsBtjj|j�r\ytj|jd|j�Wn4tk
rZ}ztd|j|f��WYdd}~XnXtjjtj	�sxtj
tj	d�tj|jddd�}t
|�}|j�|jdi�|jd�xR|jD]H}|\}}x:|j|D],}|jd	�|jd
|||d��|jd�q�Wq�Wx�|jD]�}|\}}}xx|j|D]j\}}	t|	�dk�r@�q&|jd	�|jd
|||d|d��|jtjjt|	���|jd
�|jd��q&W�qWx||jD]r}xj|j|D]\}	t|	�dk�rȐq�|jd	�|jdd|i�|jtjjt|	���|jd�|jd��q�W�q�W|jd�|jd�|j�|j�~dS)Nz%s.oldzBackup of '%s' failed: %si�ZwtzUTF-8)�mode�encodingr�
z  r)rrrr<rz%d)rrrrrr)�os�path�existsr8�shutilZcopy2�	Exception�IOErrorrZ
ETC_FIREWALLD�mkdir�iorfr	Z
startDocumentrZignorableWhitespacer3Z
simpleElementr5rTreZsaxutils�escaperr+r6ZendDocument�close)
rrlrjrhrArrrrrMrrr�writeusZ$











zDirect.write)r4r4r4)#r/r0r1�__doc__rEZDBUS_SIGNATUREZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr;rBrHrCrNrOrQr!rUrVrWrXr-rZr[r\r]r^r.r_r`rarbrmr{�
__classcell__rr)r9rr2usH

	
		

r2)Zxml.saxrerqrxrtZfirewallrZfirewall.fw_typesrZfirewall.functionsrrrZfirewall.core.io.io_objectrrr	Zfirewall.core.loggerr
Z
firewall.corerrr
Zfirewall.errorsrrr2rrrr�<module>s
Nio/__pycache__/direct.cpython-36.opt-1.pyc000064400000027263151731527110014237 0ustar003

��g�=�@s�ddljZddlZddlZddlZddlmZddlmZddl	m
Z
mZmZddl
mZmZmZddlmZddlmZddlmZdd	lmZdd
lmZGdd�de�ZGd
d�de�ZdS)�N)�config)�LastUpdatedOrderedDict)�	splitArgs�joinArgs�
u2b_if_py2)�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�log)�	ipXtables)�ebtables)�errors)�
FirewallErrorc@s$eZdZdd�Zdd�Zdd�ZdS)�direct_ContentHandlercCstj||�d|_dS)NF)r�__init__�direct)�self�item�r�/usr/lib/python3.6/direct.pyr(szdirect_ContentHandler.__init__cCs�tj|||�|jj||�|dkr@|jr6ttjd��d|_�n>|dkr�|js\tj	d�dS|d}|d}|d}|jj
t|�t|�t|��n�|dk�r6|js�tj	d	�dS|d}|dkr�ttjd
|��|d}|d}yt
|d�}Wn(tk
�rtj	d|d�dSXt|�t|�t|�|g|_nH|dk�rl|j�sVtj	d�dS|d}t|�g|_ntj	d|�dSdS)NrzMore than one direct tag.T�chainz$Parse Error: chain outside of direct�ipv�table�rulez#Parse Error: rule outside of direct�ipv4�ipv6�ebz"'%s' not from {'ipv4'|'ipv6'|'eb'}�priorityz'Parse Error: %s is not a valid priority�passthroughz&Parse Error: command outside of directzUnknown XML element %s)rrr)r�startElementrZparser_check_element_attrsrrr
ZPARSE_ERRORr
�error�	add_chainr�INVALID_IPV�int�
ValueError�_rule�_passthrough)r�nameZattrsrrrrrrrr,sT






z"direct_ContentHandler.startElementcCs�tj||�|dkrX|jrF|jjdd�t|j�D��|jj|j�n
tj	d�d|_nJ|dkr�|jr�|j
jdd�t|j�D��|jj|j
�n
tj	d	�d|_
dS)
NrcSsg|]}t|��qSr)r)�.0�xrrr�
<listcomp>dsz4direct_ContentHandler.endElement.<locals>.<listcomp>z2Error: rule does not have any arguments, ignoring.rcSsg|]}t|��qSr)r)r(r)rrrr*msz0Error: passthrough does not have any arguments, z	ignoring.z9Error: passthrough does not have any arguments, ignoring.)r�
endElementZ_elementr%�appendrr�add_ruler
r r&�add_passthrough)rr'rrrr+^s 
z direct_ContentHandler.endElementN)�__name__�
__module__�__qualname__rrr+rrrrr's2rcs<eZdZdZddBgfddddddgfgfdddgfgffZdZdd	d
dgd	d
ddgd	gd
�ZiZ�fdd�Zdd�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Zd>d?�Z d@dA�Z!�Z"S)C�Directz Direct class �chains��rulesr�passthroughsz(a(sss)a(sssias)a(sas))Nrrrr)rrrrcs0tt|�j�||_t�|_t�|_t�|_dS)N)�superr2r�filenamerr3r5r6)rr8)�	__class__rrr�s
zDirect.__init__cCsdS)Nr)r�confrZall_confrrr�
_check_config�szDirect._check_configcCsg}g}x>|jD]4}x.|j|D] }|jtt|�t|g���q WqW|j|�g}xR|jD]H}xB|j|D]4}|jt|d|d|d|dt|d�f��qnWq^W|j|�g}x8|jD].}x(|j|D]}|jt|t|�f��q�Wq�W|j|�t|�S)Nr��)r3r,�tuple�listr5r6)r�retr)�keyrrrrr�
export_config�s$$


zDirect.export_configcCs�|j�|j|�x�t|j�D]x\}\}}|dkrNx||D]}|j|�q<W|dkrrx||D]}|j|�q`W|dkrx||D]}|j|�q�WqWdS)Nr3r5r6)�cleanupZcheck_config�	enumerate�IMPORT_EXPORT_STRUCTUREr!r-r.)rr:�i�elementZdummyr)rrr�
import_config�s
zDirect.import_configcCs"|jj�|jj�|jj�dS)N)r3�clearr5r6)rrrrrC�s

zDirect.cleanupcCs�td�x4|jD]*}td|d|ddj|j|�f�qWtd�xZ|jD]P}td|d|d|df�x,|j|D]\}}td	|d
j|�f�q|WqNWtd�x@|jD]6}td|�x$|j|D]}td
d
j|��q�Wq�WdS)Nr3z  (%s, %s): %srr<�,r5z  (%s, %s, %s):r=z    (%d, ('%s'))z','r6z  %s:z
    ('%s'))�printr3�joinr5r6)rrAr�argsrrr�output�sz
Direct.outputcCs*dddg}||kr&ttjd||f��dS)Nrrrz'%s' not in '%s')rr
r")rrZipvsrrr�
_check_ipv�s
zDirect._check_ipvcCsF|j|�|dkrtjj�ntjj�}||krBttjd||f��dS)Nrrz'%s' not in '%s')rr)rOrZBUILT_IN_CHAINS�keysrrr
Z
INVALID_TABLE)rrrZtablesrrr�_check_ipv_table�s

zDirect._check_ipv_tablecCsd|j||�||f}||jkr(g|j|<||j|krH|j|j|�ntjd|||fd�dS)Nz(Chain '%s' for table '%s' with ipv '%s' zalready in list, ignoring)rQr3r,r
�warning)rrrrrArrrr!�s

zDirect.add_chaincCsn|j||�||f}||jkrX||j|krX|j|j|�t|j|�dkrj|j|=ntd|||f��dS)Nrz4Chain '%s' with table '%s' with ipv '%s' not in list)rQr3�remove�lenr$)rrrrrArrr�remove_chain�s
zDirect.remove_chaincCs,|j||�||f}||jko*||j|kS)N)rQr3)rrrrrArrr�query_chain�szDirect.query_chaincCs<|j||�||f}||jkr(|j|Std||f��dS)Nz&No chains for table '%s' with ipv '%s')rQr3r$)rrrrArrr�
get_chains�s

zDirect.get_chainscCs|jS)N)r3)rrrr�get_all_chainsszDirect.get_all_chainscCs�|j||�|||f}||jkr,t�|j|<|t|�f}||j|krV||j||<n*tjddj|�||fd||fd�dS)Nz(Rule '%s' for table '%s' and chain '%s' z',zwith ipv '%s' and priority %d zalready in list, ignoring)rQr5rr>r
rRrL)rrrrrrMrA�valuerrrr-s

zDirect.add_rulecCs�|j||�|||f}|t|�f}||jkrb||j|krb|j||=t|j|�dkr�|j|=n$tddj|�||fd||f��dS)Nrz(Rule '%s' for table '%s' and chain '%s' z',z)with ipv '%s' and priority %d not in list)rQr>r5rTr$rL)rrrrrrMrArYrrr�remove_rules

zDirect.remove_rulecCsb|j||�|||f}||jkr^x"|j|j�D]}|j||=q0Wt|j|�dkr^|j|=dS)Nr)rQr5rPrT)rrrrrArYrrr�remove_rules"s

zDirect.remove_rulescCs:|j||�|||f}|t|�f}||jko8||j|kS)N)rQr>r5)rrrrrrMrArYrrr�
query_rule+s
zDirect.query_rulecCsF|j||�|||f}||jkr*|j|Std||fd|��dS)Nz'No rules for table '%s' and chain '%s' z
with ipv '%s')rQr5r$)rrrrrArrr�	get_rules1s


zDirect.get_rulescCs|jS)N)r5)rrrr�
get_all_rules:szDirect.get_all_rulescCs^|j|�||jkrg|j|<||j|kr>|j|j|�ntjddj|�|fd�dS)NzPassthrough '%s' for ipv '%s'z',zalready in list, ignoring)rOr6r,r
rRrL)rrrMrrrr.?s


zDirect.add_passthroughcCsl|j|�||jkrN||j|krN|j|j|�t|j|�dkrh|j|=ntddj|�|fd��dS)NrzPassthrough '%s' for ipv '%s'z',znot in list)rOr6rSrTr$rL)rrrMrrr�remove_passthroughIs

zDirect.remove_passthroughcCs"|j|�||jko ||j|kS)N)rOr6)rrrMrrr�query_passthroughSs
zDirect.query_passthroughcCs.|j|�||jkr|j|Std|��dS)NzNo passthroughs for ipv '%s')rOr6r$)rrrrr�get_passthroughsWs


zDirect.get_passthroughscCs|jS)N)r6)rrrr�get_all_passthroughs^szDirect.get_all_passthroughscCs�|j�|jjd�s&ttjd|j��t|�}tj�}|j	|�t
|jd��b}tjd�}|j|�y|j
|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRXdS)Nz.xmlz'%s' is missing .xml suffix�rbzNot a valid file: %s)rCr8�endswithrr
ZINVALID_NAMEr�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_TYPEZgetException)r�handler�parser�f�source�msgrrr�readcs 


zDirect.readc
CsBtjj|j�r\ytj|jd|j�Wn4tk
rZ}ztd|j|f��WYdd}~XnXtjjtj	�sxtj
tj	d�tj|jddd�}t
|�}|j�|jdi�|jd�xR|jD]H}|\}}x:|j|D],}|jd	�|jd
|||d��|jd�q�Wq�Wx�|jD]�}|\}}}xx|j|D]j\}}	t|	�dk�r@�q&|jd	�|jd
|||d|d��|jtjjt|	���|jd
�|jd��q&W�qWx||jD]r}xj|j|D]\}	t|	�dk�rȐq�|jd	�|jdd|i�|jtjjt|	���|jd�|jd��q�W�q�W|jd�|jd�|j�|j�~dS)Nz%s.oldzBackup of '%s' failed: %si�ZwtzUTF-8)�mode�encodingr�
z  r)rrrr<rz%d)rrrrrr)�os�path�existsr8�shutilZcopy2�	Exception�IOErrorrZ
ETC_FIREWALLD�mkdir�iorfr	Z
startDocumentrZignorableWhitespacer3Z
simpleElementr5rTreZsaxutils�escaperr+r6ZendDocument�close)
rrlrjrhrArrrrrMrrr�writeusZ$











zDirect.write)r4r4r4)#r/r0r1�__doc__rEZDBUS_SIGNATUREZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr;rBrHrCrNrOrQr!rUrVrWrXr-rZr[r\r]r^r.r_r`rarbrmr{�
__classcell__rr)r9rr2usH

	
		

r2)Zxml.saxrerqrxrtZfirewallrZfirewall.fw_typesrZfirewall.functionsrrrZfirewall.core.io.io_objectrrr	Zfirewall.core.loggerr
Z
firewall.corerrr
Zfirewall.errorsrrr2rrrr�<module>s
Nio/__pycache__/policy.cpython-36.pyc000064400000051212151731527110013314 0ustar003

��gϢ�@s dddgZddljZddlZddlZddlZddlmZddlm	Z	m
Z
ddlmZmZm
Z
ddlmZmZmZdd	lmZmZmZmZmZmZdd
lmZddlmZddlmZdd
lmZdd�Z dd�Z!dd�Z"dd�Z#dd�Z$Gdd�de�Z%Gdd�de�Z&ddd�Z'ddd�Z(dS) �Policy�
policy_reader�
policy_writer�N)�config)�checkIP�checkIP6)�uniqify�max_policy_name_len�portStr)�DEFAULT_POLICY_TARGET�POLICY_TARGETS�DEFAULT_POLICY_PRIORITY)�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp�check_protocol)�rich)�log)�errors)�
FirewallErrorc	Cs�|dkr�n�|dkr�n�|dkr�|jr`|jjrJtjdt|j��d|_dStj|d�|j_dS|d|jj	kr�|jj	j
|d�ntjd|d��n|dk�rN|jr�|jjr�tjdt|j��d|_dStj|d|d	�|j_dSt|d�t
|d	�t|dd
�|d	f}||jjk�r4|jjj
|�ntjd|d|d	��nN|d	k�r�|j�r�|jj�r�tjdt|j��d|_dStj|d�|j_nBt|d�|d|jjk�r�|jjj
|d�ntjd
|d��n�|dk�rh|j�r.|jj�rtjdt|j��d|_dStj|d�|j_dS|d|jjk�rT|jjj
|d�ntjd|d��n4|dk�r�|j�r�|jj�r�tjdt|j��d|_dStj|d�|j_dStjd|d��n�|dk�r2|j�r|jj�rtjdt|j��d|_dStj�|j_n|jj�r&tjd�nd|j_�nj|dk�r�d}d|k�rR|d}d}d|k�rh|d}|j�r�|jj�r�tjdt|j��d|_dStj|d|d	||�|j_dSt|d�t
|d	�|�r�t|�|�r
t|��r
t|��r
ttjd|��t|dd
�|d	t|d
�t|�f}||jjk�rL|jjj
|�n6tjd|d|d	|�rld|nd|�r|d|nd��n|dk�r@|j�r�|jj�r�tjdt|j��d|_dStj|d|d	�|j_dSt|d�t
|d	�t|dd
�|d	f}||jj k�r&|jj j
|�ntjd|d|d	��n\|dk�r�|j�sftjd�d|_dS|jj!�r�tjd t|j��dSd!}d}d"|k�r�|d"}d}d#|k�r�|d#}d$|k�r�|d$j"�dLk�r�d}tj#|||�|j_!�n�|dMk�r�|j�stjd+�d|_dS|jj$�r0tjd,�d|_dS|d'k�rHtj%�|j_$nh|d(k�rxd}	d-|k�rh|d-}	tj&|	�|j_$n8|d)k�r�tj'�|j_$n |d*k�r�|d.}
tj(|
�|j_$|jj$|_)�n�|d/k�r^|j�s�tjd0�dS|jj�r�tjd1�dSd}d2|k�r*|d2}|dNk�r*tjd;�d|_dSd<|k�r<|d<nd}tj*||�|j_|jj|_)�n>|d=k�r�|j�s~tjd>�dS|jj+�r�tjd?t|j��d|_dStj,�|j_+|jj+|_)n�|d@k�r,d}
dA}dB|k�r|dB}
|
dOk�rtjdE|dB�d|_dSdF|k�rt-|dF�}tj.|
|dG�|_np|dHk�r�|j)�sRtjdI�d|_dS|j)j/�rxtjdJt|j��d|_dS|d}tj0||j1dK��|j)_/nd!SdS)PN�short�description�servicez;Invalid rule: More than one element in rule '%s', ignoring.T�namez#Service '%s' already set, ignoring.�port�protocol�-z#Port '%s/%s' already set, ignoring.�valuez$Protocol '%s' already set, ignoring.z
icmp-blockz&icmp-block '%s' already set, ignoring.z	icmp-typez-Invalid rule: icmp-block '%s' outside of rule�
masqueradez!Masquerade already set, ignoring.zforward-port�zto-portzto-addrz#to-addr '%s' is not a valid addressz-Forward port %s/%s%s%s already set, ignoring.z >%sz @%szsource-portz*Source port '%s/%s' already set, ignoring.�destinationz)Invalid rule: Destination outside of rulez?Invalid rule: More than one destination in rule '%s', ignoring.F�address�ipset�invert�yes�true�accept�reject�drop�markz$Invalid rule: Action outside of rulez"Invalid rule: More than one action�type�setrz!Invalid rule: Log outside of rulezInvalid rule: More than one log�level�emerg�alert�crit�error�warning�notice�info�debugzInvalid rule: Invalid log level�prefix�auditz#Invalid rule: Audit outside of rulez9Invalid rule: More than one audit in rule '%s', ignoring.�ruler�family�ipv4�ipv6z&Invalid rule: Rule family "%s" invalid�priority)r:r=�limitz4Invalid rule: Limit outside of action, log and auditz9Invalid rule: More than one limit in rule '%s', ignoring.�burst)r&r')r(r)r*r+)r/r0r1r2r3r4r5r6)r;r<)2�_rule�elementrr3�str�_rule_errorr�Rich_Service�item�services�append�	Rich_Portrrr
�ports�
Rich_Protocolr�	protocols�Rich_IcmpBlock�icmp_blocks�
Rich_IcmpType�Rich_Masquerader �Rich_ForwardPortrrrr�INVALID_ADDR�
forward_ports�Rich_SourcePort�source_portsr"�lowerZRich_Destination�action�Rich_Accept�Rich_Reject�	Rich_Drop�	Rich_Mark�	_limit_okZRich_Logr8Z
Rich_Audit�int�	Rich_Ruler>Z
Rich_Limit�get)�objr�attrs�entry�to_portZto_addrr%r#r$Z_typeZ_setr.r7r:r=r�rc�/usr/lib/python3.6/policy.py�common_startElements�


















































recCs�|dkr�|js�y|jj�Wn6tk
rR}ztjd|t|j��WYdd}~XnLXt|j�|jjkr�|jj	j
|j�|jjj
t|j��ntjdt|j��d|_d|_n|dkr�d|_dS)Nr9z%s: %sz Rule '%s' already set, ignoring.Fr(r)r*r+rr8)r(r)r*r+rr8)rCr@Zcheck�	Exceptionrr3rBrE�	rules_str�rulesrGr[)r_r�ercrcrd�common_endElements&rjcCs�t|t�rdnd}|dkrT|jrT|jj�}x$|D]}||kr0ttjd|��q0W�n�|dkr�x$|D]}t|d�t|d�qbW�nb|dkr�x|D]}t	|�q�W�n@|d	kr�|jr�|jj
�}	x$|D]}
|
|	kr�ttjd
|
��q�W�n�|dk�r�x�|D]�}t|d�t|d�|d�r>|d
�r>ttjd|��|d�rTt|d�|d
r�t
|d
�r�t|d
�r�ttjd|d
��q�W�nT|dk�r�x&|D]}t|d�t|d��q�W�n|dk�r�x|D�]}tj|d�}
|j�r�|
j�r�t|
jtj��st|
jtj��r�|jj
�}	|
jj|	k�rLttjd
|
jj��nH|
j�r�|jj|
jj�}|j�r�|
j|jk�r�ttjd|
j|
jjf��nL|j�r�t|
jtj��r�|jj�}|
jj|k�r�ttjdj||j|
jj����q�WdS)NrZZonerFz '%s' not among existing servicesrIr�rKrMz"'%s' not among existing icmp typesrR��z$'%s' is missing to-port AND to-addr z#to-addr '%s' is not a valid addressrTrg�
rich_rules)�rule_strz3rich rule family '%s' conflicts with icmp type '%s'z){} '{}': '{}' not among existing services)rgrn)�
isinstancer�	fw_configZget_servicesrrZINVALID_SERVICErrrZ
get_icmptypesZINVALID_ICMPTYPE�INVALID_FORWARDrrrQrr]rArLrNrr:Zget_icmptyper"rD�format)r_rrE�
all_configZobj_typeZexisting_servicesrr�protoZexisting_icmptypesZicmptype�fwd_portr9Zobj_richZictrcrcrd�common_check_config2s�












 

rwcCs0d|ji}|j}|dk	r ||d<|jd|�dS)Nrr?r>)rr?�
simpleElement)�handlerr>�dr?rcrcrd�_handler_add_rich_limitxs

r{cCs�|jrF|jdkrF|jd�|jdi�|j|j�|jd�|jd�|jr�|jdkr�|jd�|jdi�|j|j�|jd�|jd�x6t|j�D](}|jd�|jdd|i�|jd�q�Wx@t|j	�D]2}|jd�|jd|d	|d
d��|jd�q�Wx8t|j
�D]*}|jd�|jdd
|i�|jd��qWx8t|j�D]*}|jd�|jdd|i�|jd��qLW|j�r�|jd�|jdi�|jd�x�t|j
�D]�}|jd�|d	|d
d�}|d�r�|ddk�r�|d|d<|d�r|ddk�r|d|d<|jd|�|jd��q�WxBt|j�D]4}|jd�|jd|d	|d
d��|jd��q>W�xT|jD�]H}i}|j�r�|j|d<|jd	k�r�t|j�|d<|jd�|jd|�|jd�|j�rVi}|jj�r�|jj|d<|jj�r|jj|d<|jj�r$|jj|d<|jj�r6d|d<|jd�|jd|�|jd�|j�r�i}|jj�rx|jj|d<|jj�r�|jj|d<|jj�r�d|d<|jd�|jd |�|jd�|j�rxd}	i}t|j�tjk�r�d}	|jj|d<�nbt|j�tjk�r(d}	|jj|d<|jj |d<�n0t|j�tj!k�rNd}	|jj"|d
<�n
t|j�tj#k�rfd}	n�t|j�tj$k�r�d}	|jj|d<n�t|j�tj%k�r�d!}	|jj|d<n�t|j�tj&k�rd}	|jj|d<|jj |d<|jj'dk�r�|jj'|d<|jj(dk�rX|jj(|d<nFt|j�tj)k�rBd}	|jj|d<|jj |d<nt*t+j,d"t|j���|jd�|j|	|�|jd�|j-�ri}|j-j.�r�|j-j.|d#<|j-j/�r�|j-j/|d$<|j-j0�r�|jd�|jd%|�|jd&�t1||j-j0�|jd'�|jd%�n|jd�|jd%|�|jd�|j2�r�i}|j2j0�rx|jd�|jd(i�|jd&�t1||j2j0�|jd'�|jd(�n|jd�|jd(|�|jd�|j3�r�d}
i}t|j3�tj4k�r�d)}
n|t|j3�tj5k�r�d*}
|j3j�r<|j3j|d+<nNt|j3�tj6k�rd,}
n6t|j3�tj7k�r*d-}
|j3j8|d.<nt-j9d/t|j3��|j3j0�r�|jd�|j|
|�|jd&�t1||j3j0�|jd'�|j|
�n|jd�|j|
|�|jd�|jd�|jd�|jd��q�WdS)0Nr!z  r�
rrrrrrk)rrrrz
icmp-blockr rlzto-portrmzto-addrzforward-portzsource-portr:r=r9r#�macr$�Truer%z    �sourcer"z	icmp-typez"Unknown element '%s' in obj_writerr7r.rz
      z
    r8r(r)r,r*r+r-zUnknown action '%s'):r�ignorableWhitespace�startElementZ
characters�
endElementrrrFrxrIrKrMr rRrTrhr:r=rBr�addrr}r$r%r"rAr,rrDrrHrrrJrrOrLrNrPrb�
to_addressrSrrZINVALID_OBJECTrr7r.r>r{r8rVrWrXrYrZr-r3)r_ryrrrZicmpZforwardr`r9rArVrcrcrd�
common_writer�s\




















































r�csPeZdZd7ZdZeZdgZd8d9d:d;d	dgfd
d<gfddgfd=dd>gfddgfddgfdd?gfd@ddgfddgffZdddgZ	dddgdgddgdgdgdddgddddgddgddddddgdgdgdgd�Z
ddgdd gd!dgd"d#d$d!d%gd"d$d%gd&d'gd(gd)gd*�Z�fd+d,�Zd-d.�Z
�fd/d0�Z�fd1d2�Zd3d4�Z�fd5d6�Z�ZS)Ari�i�r�versionr!rr�targetrFrIrMr FrRrnrKrTr=�
ingress_zones�egress_zones�_r�/Nrrrrr-)rr�policyrrz
icmp-blockz	icmp-typer zforward-portr9rr"rzsource-portrr8r(r)r*r+r>zingress-zonezegress-zonezto-portzto-addrr:r#r}r%r$r7r.r,r?)r�zforward-portr9rr"rr)r>cs�tt|�j�d|_d|_d|_t|_g|_g|_	g|_
g|_d|_g|_
g|_d|_g|_g|_d|_|j|_d|_g|_g|_dS)Nr!F)�superr�__init__r�rrrr�rFrIrKrMr rRrTrqrhrg�applied�priority_defaultr=Zderived_from_zoner�r�)�self)�	__class__rcrdr��s(zPolicy.__init__cCs�d|_d|_d|_t|_|jdd�=|jdd�=|jdd�=|jdd�=d|_	|j
dd�=|jdd�=d|_|j
dd�=|jdd�=d|_|j|_|jdd�=|jdd�=dS)Nr!F)r�rrrr�rFrIrKrMr rRrTrqrhrgr�r�r=r�r�)r�rcrcrd�cleanup�s$zPolicy.cleanupcs"|dkr|jSttt|�|�SdS)Nrn)rg�getattrr�r)r�r)r�rcrd�__getattr__�szPolicy.__getattr__csB|dkr,dd�|D�|_dd�|jD�|_ntt|�j||�dS)NrncSsg|]}tj|d��qS))ro)rr])�.0�srcrcrd�
<listcomp>�sz&Policy.__setattr__.<locals>.<listcomp>cSsg|]}t|��qSrc)rB)r�r�rcrcrdr��s)rhrgr�r�__setattr__)r�rr)r�rcrdr��szPolicy.__setattr__c
Cst||||�|dkr2|tkr.ttjd|���n�|dkrz||jksX||jksX||jkrvttjd||j|j|jf���n�|dk�rhddg}|j	r�||j	j
�7}x�|D]�}||kr�ttjd	|��|dkr�tddg�t|�@�s�|dk�rt|�t|g��rttjd
|��|dkr�|dk�r8d|k�r8d|dk�sT|dkr�d|kr�d|dkr�ttjd��q�W�n�|dk�r|�rd|k�r�d|dk�r�ttjd
��nxd|k�rd|dk�r�ttjd��xR|dD]F}|dk�rސq�|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�n�|dk�r4�x�|D�]}tj|d�}|j�r�t|jtj��r�d|k�r|d|dk�r|ttjd
��nxd|k�r,d|dk�r�ttjd��xR|dD]F}|dk�r��q�|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�q,|j�r�t|jtj��r�d|k�r,d|dk�r@|jj�r�ttjd��nt|d�r,|jj�s`ttjd��d|dk�r,x�|dD]8}|j	j
|�}|j	�rxd|j	j|�k�rxttjd���qxWnv|j�r,t|jtj��r,d|k�r,xR|dD]F}|dk�r�q�|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�q,Wn�|dk�rx�|D]�}	d|k�rnd|dk�rnttjd��n�d|k�rDd|dk�r�|	d�rttjd��nt|d�rD|	d�s�ttjd��d|dk�rDxD|dD]8}|j	j
|�}|j	�r�d|j	j|�k�r�ttjd���q�W�qDWdS)Nr�z'%s' is invalid targetr=zQ%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %sr�r��ANY�HOSTz'%s' not among existing zonesz>'%s' may only contain one of: many regular zones, ANY, or HOSTzF'HOST' can only appear in either ingress or egress zones, but not bothr z.'masquerade' is invalid for egress zone 'HOST'z/'masquerade' is invalid for ingress zone 'HOST'Z
interfaceszR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesrn)rozAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesrRz1'forward-port' is invalid for ingress zone 'HOST'rm)r�r�)r�r�)r�r�)r�r�)rwrrr�INVALID_TARGET�priority_reserved�priority_max�priority_minZINVALID_PRIORITYrq�	get_zonesZINVALID_ZONEr-Zget_zoneZget_zone_config_dictrr]rArprOrPr�rrrVrZ)
r�rrErtZexisting_zones�zoneZz_objr9r_rvrcrcrd�
_check_config�s�






"
















zPolicy._check_configcs�tt|�j|�|jd�r,ttjd|��n�|jd�rHttjd|��n�|jd�dkrhttjd|��njd|kr�|d|j	d��}n|}t
|�t�kr�ttjd|t
|�t�f��|jr�||jj
�kr�ttjd��dS)Nr�z'%s' can't start with '/'z'%s' can't end with '/'rkzmore than one '/' in '%s'z&Policy of '%s' has %d chars, max is %dz,Policies can't have the same name as a zone.)r�r�
check_name�
startswithrr�INVALID_NAME�endswith�count�find�lenr	rqr�Z
NAME_CONFLICT)r�rZchecked_name)r�rcrdr�,s*

zPolicy.check_namei���)r�r!)rr!)rr!)r�r!)r!r!)r F)r!r!r!r!)r!r!)r=r)�__name__�
__module__�__qualname__r�r�r
r�r�ZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr�r�r�r�r�r��
__classcell__rcrc)r�rdrZsr


^c@s$eZdZdd�Zdd�Zdd�ZdS)�policy_ContentHandlercCs"tj||�d|_d|_d|_dS)NF)rr�r@rCr[)r�rErcrcrdr�Hszpolicy_ContentHandler.__init__cCstj|||�|jrdS|jj||�t|||�r6dS|dkr�d|krR|d|j_d|krjt|d�|j_d|kr�|d}|t	kr�t
tj|��|r�||j_
�n^|dkr�|d|jjkr�|jjj|d�ntjd|d��n|dk�r |d|jjk�r|jjj|d�ntjd	|d�n�|d
k�r�|j�sFtjd�d|_dS|jj�rltjd
t|j��d|_dSd}d|k�r�|dj�dk�r�d}d}}}d|k�r�|d}d|k�r�|d}d|k�r�|d}tj||||d�|j_dStjd|�dSdS)Nr�r�r=r�zingress-zonerz(Ingress zone '%s' already set, ignoring.zegress-zonez'Egress zone '%s' already set, ignoring.rz$Invalid rule: Source outside of ruleTz:Invalid rule: More than one source in rule '%s', ignoring.Fr%r&r'r#r}r$)r%zUnknown XML element '%s')r&r')rr�rCrEZparser_check_element_attrsrer�r\r=rrrr�r�r�rGrr3r�r@rrBrUrZRich_Source)r�rr`r�r%r�r}r$rcrcrdr�Nsf








z"policy_ContentHandler.startElementcCstj||�t||�dS)N)rr�rj)r�rrcrcrdr��sz policy_ContentHandler.endElementN)r�r�r�r�r�r�rcrcrcrdr�Gs@r�Fc
Cst�}|jd�s ttjd|��|dd	�|_|s>|j|j�||_||_|j	t
j�rZdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}	zttjd|	j���WYdd}	~	XnXWdQRX~~|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid policy file: %s���)rr�rrr�rr��filename�pathr�r�
ETC_FIREWALLDZbuiltin�defaultr��saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_POLICYZgetException)
r�r�Z
no_check_namer�ry�parserr�fr�msgrcrcrdr�s6




(c
Cs�|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|j|jk�r0t|j�|d<|j|d<|jd
|�|jd�t||�x8t|j�D]*}	|jd�|jdd|	i�|jd��qfWx8t|j�D]*}	|jd�|jdd|	i�|jd��q�W|jd
�|jd�|j �|j!�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingr!r�r=r�r�r|z  zingress-zonerzegress-zone)"r�r�r�os�exists�shutilZcopy2rfrr2�dirnamer�rr��mkdir�ior�rZ
startDocumentr�r=r�rBr�r�r�r�rr�rxr�r�ZendDocument�close)
r�r��_pathrr��dirpathr�ryr`r�rcrcrdr�sN 







)F)N))�__all__Zxml.saxr�r�r�r�ZfirewallrZfirewall.functionsrrrr	r
Zfirewall.core.baserrr
Zfirewall.core.io.io_objectrrrrrrZ
firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrerjrwr{r�rr�rrrcrcrcrd�<module>s4

 F[nL
io/__pycache__/lockdown_whitelist.cpython-36.pyc000064400000022550151731527110015734 0ustar003

��g�1�@s�ddljZddlZddlZddlZddlmZddlmZm	Z	m
Z
mZddlm
Z
ddlmZmZmZmZmZmZddlmZddlmZGdd	�d	e
�ZGd
d�de	�ZdS)�N)�config)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator)�log)�uniqify�	checkUser�checkUid�checkCommand�checkContext�
u2b_if_py2)�errors)�
FirewallErrorc@seZdZdd�Zdd�ZdS)�!lockdown_whitelist_ContentHandlercCstj||�d|_dS)NF)r�__init__�	whitelist)�self�item�r�(/usr/lib/python3.6/lockdown_whitelist.pyr%sz*lockdown_whitelist_ContentHandler.__init__cCsVtj|||�|jj||�|dkr@|jr6ttjd��d|_�n|dkrr|js\tj	d�dS|d}|jj
|�n�|dkr�|js�tj	d�dSd	|kr�yt|d	�}Wn&tk
r�tj	d
|d	�dSX|jj
|�nd|kr�|jj|d�n\|dk�r@|j�stj	d�dSd
|k�r.tj	d�dS|jj|d
�ntj	d|�dSdS)NrzMore than one whitelist.T�commandz)Parse Error: command outside of whitelist�name�userz&Parse Error: user outside of whitelist�idz"Parse Error: %s is not a valid uid�selinuxz)Parse Error: selinux outside of whitelist�contextzParse Error: no contextzUnknown XML element %s)r�startElementrZparser_check_element_attrsrrrZPARSE_ERRORr�error�add_command�int�
ValueError�add_uid�add_user�add_context)rrZattrsr�uidrrrr)sJ






z.lockdown_whitelist_ContentHandler.startElementN)�__name__�
__module__�__qualname__rrrrrrr$srcs4eZdZdZddgfddgfddgfddgffZdZd	gZd
dgd
dgd
�ZdddgiZ�fdd�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Zd>d?�Z d@dA�Z!dBdC�Z"�Z#S)D�LockdownWhitelistz LockdownWhitelist class �commands��contexts�users�uidsrz
(asasasai)�_Nrr)rrrrrrcs6tt|�j�||_d|_g|_g|_g|_g|_dS)N)	�superr)r�filename�parserr*r,r-r.)rr1)�	__class__rrrnszLockdownWhitelist.__init__cCs�|d
kr.x�|D]}|j||dd�|�qWnv|dkrLt|�s�ttj|��nX|dkrjt|�s�ttj|��n:|dkr�t|�s�ttj|��n|d	kr�t	|�s�ttj
|��dS)Nr*r,r-r.�rrrr%)r*r,r-r.���)�
_check_configrrr�INVALID_COMMANDr�INVALID_CONTEXTr	�INVALID_USERr
�INVALID_UID)rrrZ
all_config�xrrrr6ys
zLockdownWhitelist._check_configcCs4|jdd�=|jdd�=|jdd�=|jdd�=dS)N)r*r,r-r.)rrrr�cleanup�szLockdownWhitelist.cleanupcCs:dd�|jD�|_dd�|jD�|_dd�|jD�|_dS)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSsg|]}t|��qSr)r
)�.0r;rrr�
<listcomp>�sz4LockdownWhitelist.encode_strings.<locals>.<listcomp>cSsg|]}t|��qSr)r
)r=r;rrrr>�scSsg|]}t|��qSr)r
)r=r;rrrr>�sN)r*r,r-)rrrr�encode_strings�sz LockdownWhitelist.encode_stringscCs@t|�sttj|��||jkr,|jj|�nttjd|��dS)Nz!Command "%s" already in whitelist)rrrr7r*�append�ALREADY_ENABLED)rrrrrr�s
zLockdownWhitelist.add_commandcCs,||jkr|jj|�nttjd|��dS)NzCommand "%s" not in whitelist.)r*�removerr�NOT_ENABLED)rrrrr�remove_command�s
z LockdownWhitelist.remove_commandcCs
||jkS)N)r*)rrrrr�has_command�szLockdownWhitelist.has_commandcCsBx<|jD]2}|jd�r.|j|dd��r:dSq||krdSqWdS)N�*r4TFr5)r*�endswith�
startswith)rrZ_commandrrr�
match_command�s
zLockdownWhitelist.match_commandcCs|jS)N)r*)rrrr�get_commands�szLockdownWhitelist.get_commandscCsDt|�sttjt|���||jkr0|jj|�nttjd|��dS)NzUid "%s" already in whitelist)r
rrr:�strr.r@rA)rr%rrrr"�s
zLockdownWhitelist.add_uidcCs,||jkr|jj|�nttjd|��dS)NzUid "%s" not in whitelist.)r.rBrrrC)rr%rrr�
remove_uid�s
zLockdownWhitelist.remove_uidcCs
||jkS)N)r.)rr%rrr�has_uid�szLockdownWhitelist.has_uidcCs
||jkS)N)r.)rr%rrr�	match_uid�szLockdownWhitelist.match_uidcCs|jS)N)r.)rrrr�get_uids�szLockdownWhitelist.get_uidscCs@t|�sttj|��||jkr,|jj|�nttjd|��dS)NzUser "%s" already in whitelist)r	rrr9r-r@rA)rrrrrr#�s
zLockdownWhitelist.add_usercCs,||jkr|jj|�nttjd|��dS)NzUser "%s" not in whitelist.)r-rBrrrC)rrrrr�remove_user�s
zLockdownWhitelist.remove_usercCs
||jkS)N)r-)rrrrr�has_user�szLockdownWhitelist.has_usercCs
||jkS)N)r-)rrrrr�
match_user�szLockdownWhitelist.match_usercCs|jS)N)r-)rrrr�	get_users�szLockdownWhitelist.get_userscCs@t|�sttj|��||jkr,|jj|�nttjd|��dS)Nz!Context "%s" already in whitelist)rrrr8r,r@rA)rrrrrr$"s
zLockdownWhitelist.add_contextcCs,||jkr|jj|�nttjd|��dS)NzContext "%s" not in whitelist.)r,rBrrrC)rrrrr�remove_context,s
z LockdownWhitelist.remove_contextcCs
||jkS)N)r,)rrrrr�has_context3szLockdownWhitelist.has_contextcCs
||jkS)N)r,)rrrrr�
match_context6szLockdownWhitelist.match_contextcCs|jS)N)r,)rrrr�get_contexts9szLockdownWhitelist.get_contextscCs�|j�|jjd�s&ttjd|j��t|�}tj�}|j	|�y|j
|j�Wn8tjk
r�}zttjd|j
���WYdd}~XnX~~tr�|j�dS)Nz.xmlz'%s' is missing .xml suffixzNot a valid file: %s)r<r1rGrrZINVALID_NAMEr�saxZmake_parserZsetContentHandler�parseZSAXParseExceptionZINVALID_TYPEZgetExceptionrr?)r�handlerr2�msgrrr�read>s"
zLockdownWhitelist.readcCs�tjj|j�r\ytj|jd|j�Wn4tk
rZ}ztd|j|f��WYdd}~XnXtjjtj	�sxtj
tj	d�tj|jddd�}t
|�}|j�|jdi�|jd�x6t|j�D](}|jd	�|jd
d|i�|jd�q�Wx:t|j�D],}|jd	�|jdd
t|�i�|jd�q�Wx8t|j�D]*}|jd	�|jdd|i�|jd��q0Wx8t|j�D]*}|jd	�|jdd|i�|jd��qjW|jd�|jd�|j�|j�~dS)Nz%s.oldzBackup of '%s' failed: %si�ZwtzUTF-8)�mode�encodingr�
z  rrrrrr)�os�path�existsr1�shutilZcopy2�	Exception�IOErrorrZ
ETC_FIREWALLD�mkdir�io�openrZ
startDocumentrZignorableWhitespacerr*Z
simpleElementr.rKr-r,Z
endElementZendDocument�close)rr[�frZrr%rrrrr�writeQsB$






zLockdownWhitelist.write)$r&r'r(�__doc__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr6r<r?rrDrErIrJr"rLrMrNrOr#rPrQrRrSr$rTrUrVrWr\rk�
__classcell__rr)r3rr)WsL

	


1
r))Zxml.saxrXr`rgrcZfirewallrZfirewall.core.io.io_objectrrrrZfirewall.core.loggerrZfirewall.functionsrr	r
rrr
rZfirewall.errorsrrr)rrrr�<module>s
 3io/__pycache__/ifcfg.cpython-36.opt-1.pyc000064400000007721151731527110014040 0ustar003

��g��@s^dZdgZddlZddlZddlZddlZddlmZddl	m
Z
mZmZGdd�de
�ZdS)zifcfg file parser�ifcfg�N)�log)�b2u�u2b�PY2c@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)rcCsi|_g|_||_|j�dS)N)�_config�_deleted�filename�clear)�selfr	�r�/usr/lib/python3.6/ifcfg.py�__init__#szifcfg.__init__cCsi|_g|_dS)N)rr)rrrr
r
)szifcfg.clearcCs|jj�dS)N)rr
)rrrr
�cleanup-sz
ifcfg.cleanupcCs|jj|j��S)N)r�get�strip)r�keyrrr
r0sz	ifcfg.getcCs8t|j��}t|j��|j|<||jkr4|jj|�dS)N)rrrr�remove)rr�valueZ_keyrrr
�set3s
z	ifcfg.setcCsHd}x2|jj�D]$\}}|r$|d7}|d||f7}qWtrDt|�S|S)N��
z%s=%s)r�itemsrr)r�srrrrr
�__str__9sz
ifcfg.__str__cCsB|j�yt|jd�}Wn4tk
rL}ztjd|j|��WYdd}~XnXx�|D]�}|s^P|j�}t|�dksT|ddkr�qTdd�|jd	d�D�}t|�d
kr�qTt|d�d
kr�|dj	d�r�|dj
d�r�|ddd�|d<|ddkr�qTn,|jj|d�dk	�r tj
d
|j|j��qT|d|j|d<qTW|j�dS)N�rzFailed to load '%s': %s�r�#�;cSsg|]}|j��qSr)r)�.0�xrrr
�
<listcomp>Qszifcfg.read.<locals>.<listcomp>�=��"rz%%s: Duplicate option definition: '%s')rr���)r
�openr	�	Exceptionr�errorr�len�split�
startswith�endswithrrZwarning�close)r�f�msg�lineZpairrrr
�readBs2
z
ifcfg.readc:Cs�t|j�dkrdSg}y.tjddtjj|j�tjj|j�dd�}Wn2t	k
rv}zt
jd|��WYdd}~XnXd}d}ytj
|jddd	�}WnNt	k
r�}z0tjj|j�r�t
jd
|j|f��nd}WYdd}~X�ndX�x^|D�]T}|s�P|jd�}t|�dk�r(|�sD|jd�d}q�|d
dk�rPd}|j|�|jd�q�|jdd�}t|�dk�r~d}|j|d�q�|d
j�}	|dj�}
t|
�dk�r�|
jd��r�|
jd��r�|
dd�}
|	|k�r@|	|jk�r|j|	|
k�rd}|jd|	|j|	f�d}n$|	|jk�r"d}nd}|j|d�|j|	�q�d}q�Wt|j�d
k�r�xF|jj�D]8\}	}
|	|k�rz�qd|�s�d}|jd|	|
f�d}�qdW|�r�|j�|j�|�s�tj|j�dStjj|j��r8ytj|jd|j�WnBt	k
�r6}z$tj|j�td|j|f��WYdd}~XnXytj|j|j�WnBt	k
�r�}z$tj|j�td|j|f��WYdd}~XnXtj|jd�dS)NrZwtz%s.F)�mode�prefix�dir�deletez!Failed to open temporary file: %sZrtzUTF-8)r2�encodingzFailed to open '%s': %srTrrr"r#r$z%s=%s
z%s.bakzBackup of '%s' failed: %szFailed to create '%s': %si�r%)r)r�tempfileZNamedTemporaryFile�os�path�basenamer	�dirnamer'rr(�ior&�existsr�writer*r+r,r�appendrr-r�name�shutilZcopy2�IOErrorZmove�chmod)r�doneZ	temp_filer/Zmodified�emptyr.r0�prrrrr
r>_s�





$$zifcfg.writeN)�__name__�
__module__�__qualname__rr
rrrrr1r>rrrr
r"s	)�__doc__�__all__Zos.pathr8r<r7rAZfirewall.core.loggerrZfirewall.functionsrrr�objectrrrrr
�<module>sio/__pycache__/firewalld_conf.cpython-36.opt-1.pyc000064400000016616151731527110015743 0ustar003

��g�5�
@s~ddlZddlZddlZddlZddlmZddlmZddl	m
Z
mZmZddddd	d
ddd
ddddg
Z
Gdd�de�ZdS)�N)�config)�log)�b2u�u2b�PY2�DefaultZone�MinimalMark�
CleanupOnExit�CleanupModulesOnExit�Lockdown�
IPv6_rpfilter�IndividualCalls�	LogDenied�AutomaticHelpers�FirewallBackend�FlushAllOnReload�RFC3964_IPv4�AllowZoneDriftingc@sLeZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dS)�firewalld_confcCsi|_g|_||_|j�dS)N)�_config�_deleted�filename�clear)�selfr�r�$/usr/lib/python3.6/firewalld_conf.py�__init__&szfirewalld_conf.__init__cCsi|_g|_dS)N)rr)rrrrr,szfirewalld_conf.clearcCs|jj�g|_dS)N)rrr)rrrr�cleanup0s
zfirewalld_conf.cleanupcCs|jj|j��S)N)r�get�strip)r�keyrrrr4szfirewalld_conf.getcCs8t|j��}t|j��|j|<||jkr4|jj|�dS)N)rrrr�remove)rr �valueZ_keyrrr�set7s
zfirewalld_conf.setcCsHd}x2|jj�D]$\}}|r$|d7}|d||f7}qWtrDt|�S|S)N��
z%s=%s)r�itemsrr)r�sr r"rrr�__str__=szfirewalld_conf.__str__cCs�|j�yt|jd�}W�n8tk
�rR}�ztjd|j|�|jdtj�|jdt	tj
��|jdtjrpdnd�|jdtjr�dnd�|jd	tj
r�dnd�|jd
tjr�dnd�|jdtjr�dnd�|jdtj�|jd
tj�|jdtj�|jdtj�r
dnd�|jdtj�r"dnd�|jdtj�r:dnd��WYdd}~XnX�x�|D]�}|�shP|j�}t|�dk�s\|dd.k�r��q\dd�|jd�D�}t|�dk�r�tjd|j���q\nr|dtk�r�tjd|j���q\nN|ddk�rtjd|j���q\n*|jj|d�dk	�r:tjd|j���q\|d|j|d<�q\W|j�|jd��s�tjdtj�|jdt	tj��|jd�}yt|�WnPttfk
�r�|dk	�r�tj d |�r�|ndtj
�|jdt	tj
��YnX|jd�}|�s|j!�d/k�rJ|dk	�r2tj d#|�r(|ndtj�|jdtj�rDdnd�|jd�}|�sj|j!�d0k�r�|dk	�r�tj d$|�r�|ndtj�|jdtj�r�dnd�|jd	�}|�s�|j!�d1k�r|dk	�r�tj d%|�r�|ndtj
�|jd	tj
�r�dnd�|jd
�}|�s"|j!�d2k�r^|dk	�rFtj d&|�r<|ndtj�|jd
tj�rXdnd�|jd�}|�s~|j!�d3k�r�|dk	�r�tj d'|�r�|ndtj�|jdtj�r�dnd�|jd�}|�s�|tj"k�r|dk	�r�tj d(|tj�|jdt	tj��|jd
�}|�s&|j!�tj#k�r\|dk	�rJtj d)|�r@|ndtj�|jd
t	tj��|jd�}|�s~|j!�tj$k�r�|dk	�r�tj d*|�r�|ndtj�|jdt	tj��|jd�}|�s�|j!�d4k�r
|dk	�r�tj d+|�r�|ndtj�|jdt	tj��|jd�}|�s*|j!�d5k�r`|dk	�rNtj d,|�rD|ndtj�|jdt	tj��|jd�}|�s�|j!�d6k�r�|dk	�r�tj d-|�r�|ndtj�|jdt	tj��dS)7N�rzFailed to load '%s': %srrr	�yes�nor
rrr
rrrrrr�r�#�;cSsg|]}|j��qSr)r)�.0�xrrr�
<listcomp>bsz'firewalld_conf.read.<locals>.<listcomp>�=�zInvalid option definition: '%s'zInvalid option: '%s'r$zMissing value: '%s'z!Duplicate option definition: '%s'z0DefaultZone is not set, using default value '%s'z7MinimalMark '%s' is not valid, using default value '%d'�false�truez7CleanupOnExit '%s' is not valid, using default value %sz>CleanupModulesOnExit '%s' is not valid, using default value %sz2Lockdown '%s' is not valid, using default value %sz7IPv6_rpfilter '%s' is not valid, using default value %sz9IndividualCalls '%s' is not valid, using default value %sz3LogDenied '%s' is invalid, using default value '%s'z:AutomaticHelpers '%s' is not valid, using default value %sz9FirewallBackend '%s' is not valid, using default value %sz:FlushAllOnReload '%s' is not valid, using default value %sz6RFC3964_IPv4 '%s' is not valid, using default value %sz;AllowZoneDrifting '%s' is not valid, using default value %s)r-r.)r+r4r*r5)r+r4r*r5)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)%r�openr�	Exceptionr�errorr#rZ
FALLBACK_ZONE�strZFALLBACK_MINIMAL_MARKZFALLBACK_CLEANUP_ON_EXITZ FALLBACK_CLEANUP_MODULES_ON_EXITZFALLBACK_LOCKDOWNZFALLBACK_IPV6_RPFILTERZFALLBACK_INDIVIDUAL_CALLSZFALLBACK_LOG_DENIEDZFALLBACK_AUTOMATIC_HELPERSZFALLBACK_FIREWALL_BACKENDZFALLBACK_FLUSH_ALL_ON_RELOADZFALLBACK_RFC3964_IPV4ZFALLBACK_ALLOW_ZONE_DRIFTINGr�len�split�
valid_keysrr�close�int�
ValueError�	TypeErrorZwarning�lowerZLOG_DENIED_VALUESZAUTOMATIC_HELPERS_VALUESZFIREWALL_BACKEND_VALUES)r�f�msg�lineZpairr"rrr�readFs
























zfirewalld_conf.readc:Cs�t|j�dkrdSg}tjjtj�s2tjtjd�y.tj	ddtjj
|j�tjj|j�dd�}Wn2t
k
r�}ztjd|��WYdd}~XnXd}d}ytj|jdd	d
�}WnPt
k
�r}z0tjj|j�r�tjd|j|f��nd}WYdd}~X�n6X�x0|D�]&}|�sP|jd�}t|�dk�rH|�s2|jd�d
}n�|ddk�rpd}|j|�|jd�n�|jd�}t|�dk�r�d}|j|d��q|dj�}	|dj�}
|	|k�r.|	|jk�r�|j|	|
k�r�d}|jd|	|j|	f�d
}n$|	|jk�rd
}nd}|j|d�|j|	�nd
}�qWt|j�dk�r�x^|jj�D]P\}	}
|	|k�rj�qT|	dk�rx�qT|�s�|jd�d
}|jd|	|
f�d
}�qTW|�r�|j�|j�|�s�tj|j�dStjj|j��r@ytj|jd|j�WnBt
k
�r>}z$tj|j�td|j|f��WYdd}~XnXytj|j|j�WnBt
k
�r�}z$tj|j�td|j|f��WYdd}~XnXtj|jd�dS)Nr,i�Zwtz%s.F)�mode�prefix�dir�deletez!Failed to open temporary file: %sZrtzUTF-8)rF�encodingzFailed to open '%s': %sr%Trr-r2r3z%s=%s
rrz%s.oldzBackup of '%s' failed: %szFailed to create '%s': %si�)rr) r:r�os�path�existsrZ
ETC_FIREWALLD�mkdir�tempfileZNamedTemporaryFile�basenamer�dirnamer7rr8�ior6r�writer;r�appendr&r=r!�name�shutilZcopy2�IOErrorZmove�chmod)r�doneZ	temp_filerCZmodified�emptyrBrD�pr r"rrrrS�s�









$$zfirewalld_conf.writeN)�__name__�
__module__�__qualname__rrrrr#r(rErSrrrrr%s	r)Zos.pathrKrRrOrVZfirewallrZfirewall.core.loggerrZfirewall.functionsrrrr<�objectrrrrr�<module>sio/__pycache__/__init__.cpython-36.opt-1.pyc000064400000001227151731527110014514 0ustar003

��g<�@sjddlZdejkrfddlmZeed�s<dd�Zeede�ddlmZeed�sfd	d
�Z	eede	�dS)�NZ_xmlplus)�AttributesImpl�__contains__cCs|t|d�kS)NZ_attrs)�getattr)�self�name�r�/usr/lib/python3.6/__init__.py�__AttributesImpl__contains__sr	)�XMLGeneratorZ_writecCst|d�j|�dS)NZ_out)r�write)r�textrrr�__XMLGenerator_write$sr
)
Zxml�__file__Zxml.sax.xmlreaderr�hasattrr	�setattrZxml.sax.saxutilsr
r
rrrr�<module>s


io/__pycache__/io_object.cpython-36.pyc000064400000027540151731527110013761 0ustar003

��g5�@sdZddddddddgZd	d
ljZd	d
ljjZd	d
lZd	d
lZd	dlm	Z	d	dl
mZd	d
lm
Z
d	dl
mZd	dlmZejdkZGdd�de�ZGdd�de�ZGdd�de�ZGdd�de�ZGdd�dejj�ZGdd�dej�Zdd�Zdd�Zdd�Z dd�Z!d
S)z5Generic io_object handler, io specific check methods.�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp�check_protocol�
check_address�N)�OrderedDict)�	functions)�b2u)�errors)�
FirewallError�3c@s|eZdZdZfZdZgZiZiZdd�Z	dd�Z
dd�Zd	d
�Zdd�Z
d
d�Zdd�Zdd�Zdd�Zdd�Zdd�ZdS)rz; Abstract IO_Object as base for icmptype, service and zone z()cCs"d|_d|_d|_d|_d|_dS)N�F)�filename�path�name�defaultZbuiltin)�self�r�/usr/lib/python3.6/io_object.py�__init__2s
zIO_Object.__init__cCs6g}x(|jD]}|jtjt||d���qWt|�S)Nr	)�IMPORT_EXPORT_STRUCTURE�append�copy�deepcopy�getattr�tuple)r�ret�xrrr�
export_config9szIO_Object.export_configcCsXi}tdd�|jD��}x:|D]2}t||�s<tt||�t�rtjt||��||<qW|S)NcSsg|]}|d|df�qS)r	�r)�.0r rrr�
<listcomp>Asz0IO_Object.export_config_dict.<locals>.<listcomp>)�dictrr�
isinstance�boolrr)r�conf�type_formats�keyrrr�export_config_dict?s
zIO_Object.export_config_dictcCs�|j|�x�t|j�D]~\}\}}t||t�r~g}t�}x,||D] }||krD|j|�|j|�qDW~t||t	j
|��qt||t	j
||��qWdS)N)�check_config�	enumeraterr&�list�setr�add�setattrrr)rr(�i�elementZdummyZ_confZ_setr rrr�
import_configGs

zIO_Object.import_configc	Cs~|j|�xn|D]f}t||�s0ttjdj|���t||t�r`t||tt	j
tj||����qt||tj||��qWdS)Nz-Internal error. '{}' is not a valid attribute)
�check_config_dict�hasattrrr
Z
UNKNOWN_ERROR�formatr&r.r1r
�fromkeysrr)rr(r*rrr�import_config_dictWs


"zIO_Object.import_config_dictcCszt|t�s(ttjd|td�t|�f��t|�dkr@ttjd��x4|D],}|j�rF||j	krFttjd||f��qFWdS)Nz'%s' not of type %s, but %srr"zname can't be emptyz'%s' is not allowed in '%s')
r&�strrr
�INVALID_TYPE�type�lenZINVALID_NAME�isalnum�ADDITIONAL_ALNUM_CHARS)rr�charrrr�
check_namecs


zIO_Object.check_namecCsjt|�t|j�kr0ttjdt|�t|j�f��i}x&t|j�D]\}\}}||||<q@W|j|�dS)Nz structure size mismatch %d != %d)r=rrr
r;r-r5)rr(Z	conf_dictr2r �yrrrr,pszIO_Object.check_configcCsrtdd�|jD��}xX|D]P}|dd�|jD�krDttjdj|���|j||||�|j||||�qWdS)NcSsg|]}|d|df�qS)r	r"r)r#r rrrr$|sz/IO_Object.check_config_dict.<locals>.<listcomp>cSsg|]\}}|�qSrr)r#r rBrrrr$~szoption '{}' is not valid)r%rrr
ZINVALID_OPTIONr7�_check_config_structure�
_check_config)rr(r)r*rrrr5{s
zIO_Object.check_config_dictcCsdS)Nr)rZdummy1Zdummy2Zdummy3rrrrD�szIO_Object._check_configc	Cs`t|t|��s,ttjd|t|�t|�f��t|t�rrt|�dkrRttjd|��x|D]}|j||d�qXWn�t|t�r�t|�t|�kr�ttjd|t|�f��x�t	|�D]\}}|j|||�q�Wn�t|t
��r\t|j��d\}}xn|j�D]b\}}t|t|���s,ttjd|t|�t|�f��t|t|��s�ttjd|t|�t|�f��q�WdS)Nz'%s' not of type %s, but %sr"zlen('%s') != 1r	zlen('%s') != %d)r&r<rr
r;r.r=rCrr-r%�items)	rr(Z	structurer r2�valueZskeyZsvaluer*rrrrC�s8



z!IO_Object._check_config_structurecCs�|j�}d}||jkrdd}|j|dk	rdx:|j|D],}||krL|j|�q4ttjd||f��q4W||jkr�d}x$|j|D]}||kr~|j|�q~W|s�ttjd|��x |D]}ttjd||f��q�WdS)NFTzMissing attribute %s for %szUnexpected element %sz%s: Unexpected attribute %s)ZgetNames�PARSER_REQUIRED_ELEMENT_ATTRS�removerr
ZPARSE_ERROR�PARSER_OPTIONAL_ELEMENT_ATTRS)rr�attrsZ_attrs�foundr rrr�parser_check_element_attrs�s,



z$IO_Object.parser_check_element_attrsN)�__name__�
__module__�__qualname__�__doc__rZDBUS_SIGNATUREr?rGrIrr!r+r4r9rAr,r5rDrCrLrrrrr)s"
!cs$eZdZ�fdd�Zdd�Z�ZS)�UnexpectedElementErrorcstt|�j�||_dS)N)�superrQrr)rr)�	__class__rrr�szUnexpectedElementError.__init__cCs
d|jS)NzUnexpected element '%s')r)rrrr�__str__�szUnexpectedElementError.__str__)rMrNrOrrT�
__classcell__rr)rSrrQ�srQcs$eZdZ�fdd�Zdd�Z�ZS)�MissingAttributeErrorcstt|�j�||_||_dS)N)rRrVrr�	attribute)rrrW)rSrrr�szMissingAttributeError.__init__cCsd|j|jfS)Nz$Element '%s': missing '%s' attribute)rrW)rrrrrT�szMissingAttributeError.__str__)rMrNrOrrTrUrr)rSrrV�srVcs$eZdZ�fdd�Zdd�Z�ZS)�UnexpectedAttributeErrorcstt|�j�||_||_dS)N)rRrXrrrW)rrrW)rSrrr�sz!UnexpectedAttributeError.__init__cCsd|j|jfS)Nz'Element '%s': unexpected attribute '%s')rrW)rrrrrT�sz UnexpectedAttributeError.__str__)rMrNrOrrTrUrr)rSrrX�srXc@s4eZdZdd�Zdd�Zdd�Zdd�Zd	d
�ZdS)rcCs||_d|_dS)Nr)�item�_element)rrYrrrr�sz!IO_Object_ContentHandler.__init__cCs
d|_dS)Nr)rZ)rrrr�
startDocument�sz&IO_Object_ContentHandler.startDocumentcCs
d|_dS)Nr)rZ)rrrJrrr�startElement�sz%IO_Object_ContentHandler.startElementcCs*|dkr|j|j_n|dkr&|j|j_dS)N�short�description)rZrYr]r^)rrrrr�
endElement�sz#IO_Object_ContentHandler.endElementcCs|j|jdd�7_dS)N�
� )rZ�replace)r�contentrrr�
characters�sz#IO_Object_ContentHandler.charactersN)rMrNrOrr[r\r_rdrrrrr�s
c@s<eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
S)rcCsNtjjj|�|j|_|j|_ig|_|jd|_	g|_
d|_d|_d|_
dS)Nr"zutf-8F���)�sax�handler�ContentHandlerr�write�_write�flushZ_flushZ_ns_contextsZ_current_contextZ_undeclared_ns_mapsZ	_encodingZ_pending_start_elementZ_short_empty_elements)r�outrrrr�szIO_Object_XMLGenerator.__init__cCs*trdd�|j�D�}tjj|||�dS)a saxutils.XMLGenerator.startElement() expects name and attrs to be
            unicode and bad things happen if any of them is (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        cSsi|]\}}t|�t|��qSr)r)r#rrFrrr�
<dictcomp>sz7IO_Object_XMLGenerator.startElement.<locals>.<dictcomp>N)rrE�saxutils�XMLGeneratorr\)rrrJrrrr\sz#IO_Object_XMLGenerator.startElementcCs�trX|jdt|��x4|j�D](\}}|jdt|�tjt|��f�q W|jd�nF|jd|�x,|j�D] \}}|jd|tj|�f�qpW|jd�dS)z* slightly modified startElement()
        �<z %s=%sz/>N)rrjrrErnZ	quoteattr)rrrJrFrrr�
simpleElementsz$IO_Object_XMLGenerator.simpleElementcCstjj|t|��dS)z� saxutils.XMLGenerator.endElement() expects name to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        N)rnror_r)rrrrrr_sz!IO_Object_XMLGenerator.endElementcCstjj|t|��dS)z� saxutils.XMLGenerator.characters() expects content to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        N)rnrordr)rrcrrrrd%sz!IO_Object_XMLGenerator.characterscCstjj|t|��dS)a saxutils.XMLGenerator.ignorableWhitespace() expects content to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        N)rnro�ignorableWhitespacer)rrcrrrrr-sz*IO_Object_XMLGenerator.ignorableWhitespaceN)	rMrNrOrr\rqr_rdrrrrrrr�s
cCs�tj|�}|dkr$ttjd|��n`|dkr>ttjd|��nF|dkrXttjd|��n,t|�dkr�|d|dkr�ttjd|��dS)	N�zport number in '%s' is too bigr"z'%s' is invalid port rangezport range '%s' is ambiguousr	���re)rZgetPortRangerr
ZINVALID_PORTr=)ZportZ
port_rangerrrr5s
cCs|dkrttjd|��dS)N�tcp�udp�sctp�dccpz)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'})rurvrwrx)rr
�INVALID_PROTOCOL)�protocolrrrrDscCstj|�sttj|��dS)N)rZ
checkProtocolrr
ry)rzrrrrJs
cCs$tj||�s ttjd||f��dS)Nz'%s' is not valid %s address)rrrr
ZINVALID_ADDR)ZipvZaddrrrrrNs)"rP�__all__Zxml.saxrfZxml.sax.saxutilsrnr�sys�collectionsr
ZfirewallrZfirewall.functionsrr
Zfirewall.errorsr�versionr�objectr�	ExceptionrQrVrXrgrhrrorrrrrrrrr�<module>s0

		Cio/__pycache__/functions.cpython-36.opt-1.pyc000064400000005256151731527110014773 0ustar003

��gy�@s�ddlZddlmZddlmZddlmZddlmZddl	m
Z
ddlmZddl
mZdd	lmZdd
lmZddlmZddlmZdd
lmZdd�ZdS)�N)�config)�
FirewallError)�FirewallConfig)�zone_reader)�service_reader)�ipset_reader)�icmptype_reader)�
helper_reader)�
policy_reader)�Direct)�LockdownWhitelist)�firewalld_confc	-Cs|t|�}t|jtjtjgd�t|jtjtj	gd�t
|jtjtj
gd�t|jtjtjgd�t|jtjtjgd�t|jtjtjgd�d�}�x
|j�D�]�}x�||dD]�}tjj|�s�q�x�ttj|��D]�}|j d�r�yD||d||�}|d
k�r�||_!|j"|j#��||d|�Wq�t$k
�rT}zt$|j%d	||j&f��WYdd}~Xq�t'k
�r�}zt'd	||f��WYdd}~Xq�Xq�Wq�Wq�Wtjj(tj)��r:y$t*tj)�}|j+�|j,|j-��Wnpt$k
�r}zt$|j%d	tj)|j&f��WYdd}~Xn6t'k
�r8}zt'd	tj)|f��WYdd}~XnXtjj(tj.��r�y$t/tj.�}|j+�|j,|j-��Wnpt$k
�r�}zt$|j%d	tj.|j&f��WYdd}~Xn6t'k
�r�}zt'd	tj.|f��WYdd}~XnXtjj(tj0��rxyt1tj0�}|j+�Wnpt$k
�rB}zt$|j%d	tj0|j&f��WYdd}~Xn6t'k
�rv}zt'd	tj0|f��WYdd}~XnXdS)N)�reader�add�dirs)Zipset�helperZicmptypeZservice�zone�policyrz.xmlrrrrz'%s': %s)rr)2rrZ	add_ipsetrZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSr	Z
add_helperZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSrZadd_icmptypeZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESrZadd_serviceZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESrZadd_zoneZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr
Zadd_policy_objectZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIES�keys�os�path�isdir�sorted�listdir�endswith�	fw_configZcheck_config_dictZexport_config_dictr�code�msg�	Exception�isfileZFIREWALLD_DIRECTr�read�check_configZ
export_configZLOCKDOWN_WHITELISTrZFIREWALLD_CONFr
)	�fwrZreadersrZ_dir�file�obj�errorr�r&�/usr/lib/python3.6/functions.pyr!&sz

&.
($
($
(r!)rZfirewallrZfirewall.errorsrZfirewall.core.fw_configrZfirewall.core.io.zonerZfirewall.core.io.servicerZfirewall.core.io.ipsetrZfirewall.core.io.icmptyperZfirewall.core.io.helperr	Zfirewall.core.io.policyr
Zfirewall.core.io.directrZ#firewall.core.io.lockdown_whitelistrZfirewall.core.io.firewalld_confr
r!r&r&r&r'�<module>sio/__pycache__/service.cpython-36.opt-1.pyc000064400000020377151731527110014424 0ustar003

��g�2�@s�dddgZddljZddlZddlZddlZddlmZddlm	Z	ddl
mZmZm
Z
mZmZmZmZmZddlmZdd	lmZdd
lmZGdd�de�ZGdd
�d
e
�Zdd�Zddd�ZdS)�Service�service_reader�service_writer�N)�config)�
u2b_if_py2)�PY2�	IO_Object�IO_Object_ContentHandler�IO_Object_XMLGenerator�
check_port�check_tcpudp�check_protocol�
check_address)�log)�errors)�
FirewallErrorcs�eZdZd d!d"dd#gfddgfdddifddgfd	d$gfd
dgfddgff
Zdd
gZdddd�Zddgddgdgdgddgddgdgdgd�Z�fdd�Zdd�Zdd�Z	dd�Z
�ZS)%r�version��short�description�ports�modules�destination�	protocols�source_ports�includes�helpers�_�-N)rr�service�name�port�protocol�value�ipv4�ipv6r)rr!r"�modulerzsource-port�include�helpercsNtt|�j�d|_d|_d|_g|_g|_g|_i|_	g|_
g|_g|_dS)Nr)
�superr�__init__rrrrrrrrrr)�self)�	__class__��/usr/lib/python3.6/service.pyr*DszService.__init__cCshd|_d|_d|_|jdd�=|jdd�=|jdd�=|jj�|jdd�=|j	dd�=|j
dd�=dS)Nr)rrrrrrr�clearrrr)r+r-r-r.�cleanupQs
zService.cleanupcCs�t|j�|_t|j�|_t|j�|_dd�|jD�|_dd�|jD�|_dd�|jj�D�|_dd�|jD�|_dd�|j	D�|_	dd�|j
D�|_
d	d�|jD�|_d
S)z� HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support.cSs g|]\}}t|�t|�f�qSr-)r)�.0�po�prr-r-r.�
<listcomp>dsz*Service.encode_strings.<locals>.<listcomp>cSsg|]}t|��qSr-)r)r1�mr-r-r.r4escSsi|]\}}t|�t|��qSr-)r)r1�k�vr-r-r.�
<dictcomp>fsz*Service.encode_strings.<locals>.<dictcomp>cSsg|]}t|��qSr-)r)r1r3r-r-r.r4gscSs g|]\}}t|�t|�f�qSr-)r)r1r2r3r-r-r.r4hscSsg|]}t|��qSr-)r)r1�sr-r-r.r4jscSsg|]}t|��qSr-)r)r1r9r-r-r.r4ksN)rrrrrrr�itemsrrrr)r+r-r-r.�encode_strings]szService.encode_stringscCs:|dkrJx>|D]6}|ddkr8t|d�t|d�qt|d�qWn�|dkrjx�|D]}t|�qXWn�|dkr�x�|D]}t|d�t|d�qxWn�|dkr�x�|D]*}|dkr�ttjd
|��t|||�q�Wn^|dk�r6xR|D]J}|jd��r|jdd�}d
|k�r|jd
d�}t	|�dkr�ttj
|��q�WdS)Nrrr�rrrr$r%z'%s' not in {'ipv4'|'ipv6'}r�
nf_conntrack_rr�)r$r%)rrr
rrZINVALID_DESTINATIONr�
startswith�replace�lenZINVALID_MODULE)r+r�itemZ
all_configr!�protorr&r-r-r.�
_check_configms8






zService._check_config)rr)rr)rr)rr)rr)�__name__�
__module__�__qualname__ZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr*r0r;rD�
__classcell__r-r-)r,r.r&s4


c@seZdZdd�ZdS)�service_ContentHandlercCs0tj|||�|jj||�|dkrTd|kr<tjd|d�d|krP|d|j_�n�|dkr`�n�|dkrl�n�|dk�r$|ddkr�t|d�t|d	�|d|d	f}||jj	kr�|jj	j
|�ntjd
|d|d	�nBt|d	�|d	|jjk�r|jjj
|d	�ntjd|d	��n|d	k�rtt|d�|d|jjk�r`|jjj
|d�ntjd|d��n�|d
k�r�t|d�t|d	�|d|d	f}||jj
k�r�|jj
j
|�ntjd|d|d	��nN|dk�r>xRdD]J}||k�r�t|||�||jjk�r&tjd|�n|||jj|<�q�Wn�|dk�r�|d}|jd��r~|jdd�}d|k�r~|jdd�}||jjk�r�|jjj
|�ntjd|�n�|dk�r�|d|jjk�r�|jjj
|d�ntjd|d�n@|dk�r,|d|jjk�r|jjj
|d�ntjd|d�dS)Nrr z'Ignoring deprecated attribute name='%s'rrrr!rr"z#Port '%s/%s' already set, ignoring.z$Protocol '%s' already set, ignoring.r#zsource-portz)SourcePort '%s/%s' already set, ignoring.rr$r%z2Destination address for '%s' already set, ignoringr&r=rrz"Module '%s' already set, ignoring.r'z#Include '%s' already set, ignoring.r(z"Helper '%s' already set, ignoring.)r$r%)r	�startElementrBZparser_check_element_attrsrZwarningrrrr�appendr
rrrrr?r@rrr)r+r �attrs�entry�xr&r-r-r.rJ�s�










z#service_ContentHandler.startElementN)rErFrGrJr-r-r-r.rI�srIc	Cst�}|jd�s ttjd|��|dd	�|_|j|j�||_||_|j	t
j�rVdnd|_|j|_
t|�}tj�}|j|�d||f}t|d��b}tjd�}|j|�y|j|�Wn8tjk
r�}zttjd|j���WYdd}~XnXWdQRX~~t�r|j�|S)
Nz.xmlz'%s' is missing .xml suffix�FTz%s/%s�rbznot a valid service file: %s���)r�endswithrrZINVALID_NAMEr Z
check_name�filename�pathr?r�
ETC_FIREWALLDZbuiltin�defaultrI�saxZmake_parserZsetContentHandler�openZInputSourceZ
setByteStream�parseZSAXParseExceptionZINVALID_SERVICEZgetExceptionrr;)	rSrTr�handler�parserr �f�source�msgr-r-r.r�s8




(cCsr|r|n|j}|jr$d||jf}nd||jf}tjj|�r�ytj|d|�Wn0tk
r�}ztj	d||�WYdd}~XnXtjj
|�}|jtj
�r�tjj|�r�tjjtj
�s�tjtj
d�tj|d�tj|ddd�}t|�}|j�i}|j�r|jd	k�r|j|d
<|jd|�|jd�|j�rt|jd	k�rt|jd
�|jdi�|j|j�|jd�|jd�|j�r�|jd	k�r�|jd
�|jdi�|j|j�|jd�|jd�x>|jD]4}	|jd
�|jd|	d|	dd��|jd��q�Wx4|jD]*}
|jd
�|jdd|
i�|jd��qWx>|jD]4}	|jd
�|jd|	d|	dd��|jd��q<Wx4|jD]*}|jd
�|jdd|i�|jd��q|Wt|j �dk�r�|jd
�|jd|j �|jd�x4|j!D]*}|jd
�|jdd|i�|jd��q�Wx4|j"D]*}
|jd
�|jdd|
i�|jd��qW|jd�|jd�|j#�|j$�~dS)Nz%s/%sz	%s/%s.xmlz%s.oldzBackup of file '%s' failed: %si�ZwtzUTF-8)�mode�encodingrrr�
z  rrr!rr<)r!r"r"r#zsource-portr&r rr'r()%rTrSr �os�exists�shutilZcopy2�	Exceptionr�error�dirnamer?rrU�mkdir�iorXr
Z
startDocumentrrJZignorableWhitespacerZ
charactersZ
endElementrrZ
simpleElementrrrrArrrZendDocument�close)rrT�_pathr r^�dirpathr\rZrLr!r"r&r'r(r-r-r.rs� 

















)N)�__all__Zxml.saxrWrbrirdZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr	r
rrr
rZfirewall.core.loggerrrZfirewall.errorsrrrIrrr-r-r-r.�<module>s

(mQio/io_object.py000064400000032422151731527110007470 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""Generic io_object handler, io specific check methods."""

__all__ = [ "PY2",
            "IO_Object", "IO_Object_ContentHandler", "IO_Object_XMLGenerator",
            "check_port", "check_tcpudp", "check_protocol", "check_address" ]

import xml.sax as sax
import xml.sax.saxutils as saxutils
import copy
import sys
from collections import OrderedDict

from firewall import functions
from firewall.functions import b2u
from firewall import errors
from firewall.errors import FirewallError

PY2 = sys.version < '3'

class IO_Object(object):
    """ Abstract IO_Object as base for icmptype, service and zone """

    IMPORT_EXPORT_STRUCTURE = ( )
    DBUS_SIGNATURE = '()'
    ADDITIONAL_ALNUM_CHARS = [ ] # additional to alnum
    PARSER_REQUIRED_ELEMENT_ATTRS = { }
    PARSER_OPTIONAL_ELEMENT_ATTRS = { }

    def __init__(self):
        self.filename = ""
        self.path = ""
        self.name = ""
        self.default = False
        self.builtin = False

    def export_config(self):
        ret = [ ]
        for x in self.IMPORT_EXPORT_STRUCTURE:
            ret.append(copy.deepcopy(getattr(self, x[0])))
        return tuple(ret)

    def export_config_dict(self):
        conf = {}
        type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE])
        for key in type_formats:
            if getattr(self, key) or isinstance(getattr(self, key), bool):
                conf[key] = copy.deepcopy(getattr(self, key))
        return conf

    def import_config(self, conf):
        self.check_config(conf)
        for i,(element,dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
            if isinstance(conf[i], list):
                # remove duplicates without changing the order
                _conf = [ ]
                _set = set()
                for x in conf[i]:
                    if x not in _set:
                        _conf.append(x)
                        _set.add(x)
                del _set
                setattr(self, element, copy.deepcopy(_conf))
            else:
                setattr(self, element, copy.deepcopy(conf[i]))

    def import_config_dict(self, conf):
        self.check_config_dict(conf)

        for key in conf:
            if not hasattr(self, key):
                raise FirewallError(errors.UNKNOWN_ERROR, "Internal error. '{}' is not a valid attribute".format(key))
            if isinstance(conf[key], list):
                # maintain list order while removing duplicates
                setattr(self, key, list(OrderedDict.fromkeys(copy.deepcopy(conf[key]))))
            else:
                setattr(self, key, copy.deepcopy(conf[key]))

    def check_name(self, name):
        if not isinstance(name, str):
            raise FirewallError(errors.INVALID_TYPE,
                                "'%s' not of type %s, but %s" % (name, type(""),
                                                                 type(name)))
        if len(name) < 1:
            raise FirewallError(errors.INVALID_NAME, "name can't be empty")
        for char in name:
            if not char.isalnum() and char not in self.ADDITIONAL_ALNUM_CHARS:
                raise FirewallError(
                    errors.INVALID_NAME,
                    "'%s' is not allowed in '%s'" % ((char, name)))

    def check_config(self, conf):
        if len(conf) != len(self.IMPORT_EXPORT_STRUCTURE):
            raise FirewallError(
                errors.INVALID_TYPE,
                "structure size mismatch %d != %d" % \
                (len(conf), len(self.IMPORT_EXPORT_STRUCTURE)))
        conf_dict = {}
        for i,(x,y) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
            conf_dict[x] = conf[i]
        self.check_config_dict(conf_dict)

    def check_config_dict(self, conf):
        type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE])
        for key in conf:
            if key not in [x for (x,y) in self.IMPORT_EXPORT_STRUCTURE]:
                raise FirewallError(errors.INVALID_OPTION, "option '{}' is not valid".format(key))
            self._check_config_structure(conf[key], type_formats[key])
            self._check_config(conf[key], key, conf)

    def _check_config(self, dummy1, dummy2, dummy3):
        # to be overloaded by sub classes
        return

    def _check_config_structure(self, conf, structure):
        if not isinstance(conf, type(structure)):
            raise FirewallError(errors.INVALID_TYPE,
                                "'%s' not of type %s, but %s" % \
                                (conf, type(structure), type(conf)))
        if isinstance(structure, list):
            # same type elements, else struct
            if len(structure) != 1:
                raise FirewallError(errors.INVALID_TYPE,
                                    "len('%s') != 1" % structure)
            for x in conf:
                self._check_config_structure(x, structure[0])
        elif isinstance(structure, tuple):
            if len(structure) != len(conf):
                raise FirewallError(errors.INVALID_TYPE,
                                    "len('%s') != %d" % (conf,
                                                         len(structure)))
            for i,value in enumerate(structure):
                self._check_config_structure(conf[i], value)
        elif isinstance(structure, dict):
            # only one key value pair in structure
            (skey, svalue) = list(structure.items())[0]
            for (key, value) in conf.items():
                if not isinstance(key, type(skey)):
                    raise FirewallError(errors.INVALID_TYPE,
                                        "'%s' not of type %s, but %s" % (\
                            key, type(skey), type(key)))
                if not isinstance(value, type(svalue)):
                    raise FirewallError(errors.INVALID_TYPE,
                                        "'%s' not of type %s, but %s" % (\
                            value, type(svalue), type(value)))

    # check required elements and attributes and also optional attributes
    def parser_check_element_attrs(self, name, attrs):
        _attrs = attrs.getNames()

        found = False
        if name in self.PARSER_REQUIRED_ELEMENT_ATTRS:
            found = True
            if self.PARSER_REQUIRED_ELEMENT_ATTRS[name] is not None:
                for x in self.PARSER_REQUIRED_ELEMENT_ATTRS[name]:
                    if x in _attrs:
                        _attrs.remove(x)
                    else:
                        raise FirewallError(
                            errors.PARSE_ERROR,
                            "Missing attribute %s for %s" % (x, name))
        if name in self.PARSER_OPTIONAL_ELEMENT_ATTRS:
            found = True
            for x in self.PARSER_OPTIONAL_ELEMENT_ATTRS[name]:
                if x in _attrs:
                    _attrs.remove(x)
        if not found:
            raise FirewallError(errors.PARSE_ERROR,
                                "Unexpected element %s" % name)
        # raise attributes[0]
        for x in _attrs:
            raise FirewallError(errors.PARSE_ERROR,
                                "%s: Unexpected attribute %s" % (name, x))

# PARSER

class UnexpectedElementError(Exception):
    def __init__(self, name):
        super(UnexpectedElementError, self).__init__()
        self.name = name
    def __str__(self):
        return "Unexpected element '%s'" % (self.name)

class MissingAttributeError(Exception):
    def __init__(self, name, attribute):
        super(MissingAttributeError, self).__init__()
        self.name = name
        self.attribute = attribute
    def __str__(self):
        return "Element '%s': missing '%s' attribute" % \
            (self.name, self.attribute)

class UnexpectedAttributeError(Exception):
    def __init__(self, name, attribute):
        super(UnexpectedAttributeError, self).__init__()
        self.name = name
        self.attribute = attribute
    def __str__(self):
        return "Element '%s': unexpected attribute '%s'" % \
            (self.name, self.attribute)

class IO_Object_ContentHandler(sax.handler.ContentHandler):
    def __init__(self, item):
        self.item = item
        self._element = ""

    def startDocument(self):
        self._element = ""

    def startElement(self, name, attrs):
        self._element = ""

    def endElement(self, name):
        if name == "short":
            self.item.short = self._element
        elif name == "description":
            self.item.description = self._element

    def characters(self, content):
        self._element += content.replace('\n', ' ')

class IO_Object_XMLGenerator(saxutils.XMLGenerator):
    def __init__(self, out):
        # fix memory leak in saxutils.XMLGenerator.__init__:
        #   out = _gettextwriter(out, encoding)
        # creates unbound object results in garbage in gc
        #
        # saxutils.XMLGenerator.__init__(self, out, "utf-8")
        #   replaced by modified saxutils.XMLGenerator.__init__ code:
        sax.handler.ContentHandler.__init__(self)
        self._write = out.write
        self._flush = out.flush
        self._ns_contexts = [{}] # contains uri -> prefix dicts
        self._current_context = self._ns_contexts[-1]
        self._undeclared_ns_maps = []
        self._encoding = "utf-8"
        self._pending_start_element = False
        self._short_empty_elements = False

    def startElement(self, name, attrs):
        """ saxutils.XMLGenerator.startElement() expects name and attrs to be
            unicode and bad things happen if any of them is (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        """
        if PY2:
            attrs = { b2u(name):b2u(value) for name, value in attrs.items() }
        saxutils.XMLGenerator.startElement(self, name, attrs)

    def simpleElement(self, name, attrs):
        """ slightly modified startElement()
        """
        if PY2:
            self._write(u'<' + b2u(name))
            for (name, value) in attrs.items():
                self._write(u' %s=%s' % (b2u(name),
                                         saxutils.quoteattr(b2u(value))))
            self._write(u'/>')
        else:
            self._write('<' + name)
            for (name, value) in attrs.items():
                self._write(' %s=%s' % (name, saxutils.quoteattr(value)))
            self._write('/>')

    def endElement(self, name):
        """ saxutils.XMLGenerator.endElement() expects name to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        """
        saxutils.XMLGenerator.endElement(self, b2u(name))

    def characters(self, content):
        """ saxutils.XMLGenerator.characters() expects content to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        """
        saxutils.XMLGenerator.characters(self, b2u(content))

    def ignorableWhitespace(self, content):
        """ saxutils.XMLGenerator.ignorableWhitespace() expects content to be
            unicode and bad things happen if it's (utf-8) encoded.
            We override the method here to sanitize this case.
            Can be removed once we drop Python2 support.
        """
        saxutils.XMLGenerator.ignorableWhitespace(self, b2u(content))

def check_port(port):
    port_range = functions.getPortRange(port)
    if port_range == -2:
        raise FirewallError(errors.INVALID_PORT,
                            "port number in '%s' is too big" % port)
    elif port_range == -1:
        raise FirewallError(errors.INVALID_PORT,
                            "'%s' is invalid port range" % port)
    elif port_range is None:
        raise FirewallError(errors.INVALID_PORT,
                            "port range '%s' is ambiguous" % port)
    elif len(port_range) == 2 and port_range[0] >= port_range[1]:
        raise FirewallError(errors.INVALID_PORT,
                            "'%s' is invalid port range" % port)

def check_tcpudp(protocol):
    if protocol not in [ "tcp", "udp", "sctp", "dccp" ]:
        raise FirewallError(errors.INVALID_PROTOCOL,
                            "'%s' not from {'tcp'|'udp'|'sctp'|'dccp'}" % \
                            protocol)

def check_protocol(protocol):
    if not functions.checkProtocol(protocol):
        raise FirewallError(errors.INVALID_PROTOCOL, protocol)

def check_address(ipv, addr):
    if not functions.check_address(ipv, addr):
        raise FirewallError(errors.INVALID_ADDR,
                            "'%s' is not valid %s address" % (addr, ipv))

io/policy.py000064400000121317151731527110007034 0ustar00# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: GPL-2.0-or-later

__all__ = [ "Policy", "policy_reader", "policy_writer" ]

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.functions import checkIP, checkIP6
from firewall.functions import uniqify, max_policy_name_len, portStr
from firewall.core.base import DEFAULT_POLICY_TARGET, POLICY_TARGETS, DEFAULT_POLICY_PRIORITY
from firewall.core.io.io_object import IO_Object, \
    IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \
    check_tcpudp, check_protocol
from firewall.core import rich
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError


def common_startElement(obj, name, attrs):
    if name == "short":
        pass
    elif name == "description":
        pass

    elif name == "service":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Service(attrs["name"])
            return True
        if attrs["name"] not in obj.item.services:
            obj.item.services.append(attrs["name"])
        else:
            log.warning("Service '%s' already set, ignoring.",
                        attrs["name"])

    elif name == "port":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Port(attrs["port"],
                                                attrs["protocol"])
            return True
        check_port(attrs["port"])
        check_tcpudp(attrs["protocol"])
        entry = (portStr(attrs["port"], "-"), attrs["protocol"])
        if entry not in obj.item.ports:
            obj.item.ports.append(entry)
        else:
            log.warning("Port '%s/%s' already set, ignoring.",
                        attrs["port"], attrs["protocol"])

    elif name == "protocol":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Protocol(attrs["value"])
        else:
            check_protocol(attrs["value"])
            if attrs["value"] not in obj.item.protocols:
                obj.item.protocols.append(attrs["value"])
            else:
                log.warning("Protocol '%s' already set, ignoring.",
                            attrs["value"])
    elif name == "icmp-block":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_IcmpBlock(attrs["name"])
            return True
        if attrs["name"] not in obj.item.icmp_blocks:
            obj.item.icmp_blocks.append(attrs["name"])
        else:
            log.warning("icmp-block '%s' already set, ignoring.",
                        attrs["name"])

    elif name == "icmp-type":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_IcmpType(attrs["name"])
            return True
        else:
            log.warning("Invalid rule: icmp-block '%s' outside of rule",
                        attrs["name"])

    elif name == "masquerade":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Masquerade()
        else:
            if obj.item.masquerade:
                log.warning("Masquerade already set, ignoring.")
            else:
                obj.item.masquerade = True

    elif name == "forward-port":
        to_port = ""
        if "to-port" in attrs:
            to_port = attrs["to-port"]
        to_addr = ""
        if "to-addr" in attrs:
            to_addr = attrs["to-addr"]

        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_ForwardPort(attrs["port"],
                                                       attrs["protocol"],
                                                       to_port, to_addr)
            return True

        check_port(attrs["port"])
        check_tcpudp(attrs["protocol"])
        if to_port:
            check_port(to_port)
        if to_addr:
            if not checkIP(to_addr) and not checkIP6(to_addr):
                raise FirewallError(errors.INVALID_ADDR,
                                    "to-addr '%s' is not a valid address" \
                                    % to_addr)
        entry = (portStr(attrs["port"], "-"), attrs["protocol"],
                 portStr(to_port, "-"), str(to_addr))
        if entry not in obj.item.forward_ports:
            obj.item.forward_ports.append(entry)
        else:
            log.warning("Forward port %s/%s%s%s already set, ignoring.",
                        attrs["port"], attrs["protocol"],
                        " >%s" % to_port if to_port else "",
                        " @%s" % to_addr if to_addr else "")

    elif name == "source-port":
        if obj._rule:
            if obj._rule.element:
                log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
                            str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_SourcePort(attrs["port"],
                                                      attrs["protocol"])
            return True
        check_port(attrs["port"])
        check_tcpudp(attrs["protocol"])
        entry = (portStr(attrs["port"], "-"), attrs["protocol"])
        if entry not in obj.item.source_ports:
            obj.item.source_ports.append(entry)
        else:
            log.warning("Source port '%s/%s' already set, ignoring.",
                        attrs["port"], attrs["protocol"])

    elif name == "destination":
        if not obj._rule:
            log.warning('Invalid rule: Destination outside of rule')
            obj._rule_error = True
            return True
        if obj._rule.destination:
            log.warning("Invalid rule: More than one destination in rule '%s', ignoring.",
                        str(obj._rule))
            return True
        invert = False
        address = None
        if "address" in attrs:
            address = attrs["address"]
        ipset = None
        if "ipset" in attrs:
            ipset = attrs["ipset"]
        if "invert" in attrs and \
                attrs["invert"].lower() in [ "yes", "true" ]:
            invert = True
        obj._rule.destination = rich.Rich_Destination(address,
                                                      ipset,
                                                      invert)

    elif name in [ "accept", "reject", "drop", "mark" ]:
        if not obj._rule:
            log.warning('Invalid rule: Action outside of rule')
            obj._rule_error = True
            return True
        if obj._rule.action:
            log.warning('Invalid rule: More than one action')
            obj._rule_error = True
            return True
        if name == "accept":
            obj._rule.action = rich.Rich_Accept()
        elif name == "reject":
            _type = None
            if "type" in attrs:
                _type = attrs["type"]
            obj._rule.action = rich.Rich_Reject(_type)
        elif name == "drop":
            obj._rule.action = rich.Rich_Drop()
        elif name == "mark":
            _set = attrs["set"]
            obj._rule.action = rich.Rich_Mark(_set)
        obj._limit_ok = obj._rule.action

    elif name == "log":
        if not obj._rule:
            log.warning('Invalid rule: Log outside of rule')
            return True
        if obj._rule.log:
            log.warning('Invalid rule: More than one log')
            return True
        level = None
        if "level" in attrs:
            level = attrs["level"]
            if level not in [ "emerg", "alert", "crit", "error",
                              "warning", "notice", "info", "debug" ]:
                log.warning('Invalid rule: Invalid log level')
                obj._rule_error = True
                return True
        prefix = attrs["prefix"] if "prefix" in attrs else None
        obj._rule.log = rich.Rich_Log(prefix, level)
        obj._limit_ok = obj._rule.log

    elif name == "audit":
        if not obj._rule:
            log.warning('Invalid rule: Audit outside of rule')
            return True
        if obj._rule.audit:
            log.warning("Invalid rule: More than one audit in rule '%s', ignoring.",
                        str(obj._rule))
            obj._rule_error = True
            return True
        obj._rule.audit = rich.Rich_Audit()
        obj._limit_ok = obj._rule.audit

    elif name == "rule":
        family = None
        priority = 0
        if "family" in attrs:
            family = attrs["family"]
            if family not in [ "ipv4", "ipv6" ]:
                log.warning('Invalid rule: Rule family "%s" invalid',
                            attrs["family"])
                obj._rule_error = True
                return True
        if "priority" in attrs:
            priority = int(attrs["priority"])
        obj._rule = rich.Rich_Rule(family=family, priority=priority)

    elif name == "limit":
        if not obj._limit_ok:
            log.warning('Invalid rule: Limit outside of action, log and audit')
            obj._rule_error = True
            return True
        if obj._limit_ok.limit:
            log.warning("Invalid rule: More than one limit in rule '%s', ignoring.",
                        str(obj._rule))
            obj._rule_error = True
            return True
        value = attrs["value"]
        obj._limit_ok.limit = rich.Rich_Limit(value, attrs.get("burst"))
    else:
        return False

    return True

def common_endElement(obj, name):
    if name == "rule":
        if not obj._rule_error:
            try:
                obj._rule.check()
            except Exception as e:
                log.warning("%s: %s", e, str(obj._rule))
            else:
                if str(obj._rule) not in obj.item.rules_str:
                    obj.item.rules.append(obj._rule)
                    obj.item.rules_str.append(str(obj._rule))
                else:
                    log.warning("Rule '%s' already set, ignoring.",
                                str(obj._rule))
        obj._rule = None
        obj._rule_error = False
    elif name in [ "accept", "reject", "drop", "mark", "log", "audit" ]:
        obj._limit_ok = None

def common_check_config(obj, config, item, all_config):
    obj_type = "Policy" if isinstance(obj, Policy) else "Zone"

    if item == "services" and obj.fw_config:
        existing_services = obj.fw_config.get_services()
        for service in config:
            if service not in existing_services:
                raise FirewallError(errors.INVALID_SERVICE,
                                    "'%s' not among existing services" % \
                                    service)
    elif item == "ports":
        for port in config:
            check_port(port[0])
            check_tcpudp(port[1])
    elif item == "protocols":
        for proto in config:
            check_protocol(proto)
    elif item == "icmp_blocks" and obj.fw_config:
        existing_icmptypes = obj.fw_config.get_icmptypes()
        for icmptype in config:
            if icmptype not in existing_icmptypes:
                raise FirewallError(errors.INVALID_ICMPTYPE,
                                    "'%s' not among existing icmp types" % \
                                    icmptype)
    elif item == "forward_ports":
        for fwd_port in config:
            check_port(fwd_port[0])
            check_tcpudp(fwd_port[1])
            if not fwd_port[2] and not fwd_port[3]:
                raise FirewallError(
                    errors.INVALID_FORWARD,
                    "'%s' is missing to-port AND to-addr " % fwd_port)
            if fwd_port[2]:
                check_port(fwd_port[2])
            if fwd_port[3]:
                if not checkIP(fwd_port[3]) and not checkIP6(fwd_port[3]):
                    raise FirewallError(
                        errors.INVALID_ADDR,
                        "to-addr '%s' is not a valid address" % fwd_port[3])
    elif item == "source_ports":
        for port in config:
            check_port(port[0])
            check_tcpudp(port[1])
    elif item in ["rules_str", "rich_rules"]:
        for rule in config:
            obj_rich = rich.Rich_Rule(rule_str=rule)
            if obj.fw_config and obj_rich.element and (isinstance(obj_rich.element, rich.Rich_IcmpBlock) or
                                                       isinstance(obj_rich.element, rich.Rich_IcmpType)):
                existing_icmptypes = obj.fw_config.get_icmptypes()
                if obj_rich.element.name not in existing_icmptypes:
                    raise FirewallError(errors.INVALID_ICMPTYPE,
                                        "'%s' not among existing icmp types" % \
                                        obj_rich.element.name)
                elif obj_rich.family:
                    ict = obj.fw_config.get_icmptype(obj_rich.element.name)
                    if ict.destination and obj_rich.family not in ict.destination:
                        raise FirewallError(errors.INVALID_ICMPTYPE,
                                            "rich rule family '%s' conflicts with icmp type '%s'" % \
                                            (obj_rich.family, obj_rich.element.name))
            elif obj.fw_config and isinstance(obj_rich.element, rich.Rich_Service):
                existing_services = obj.fw_config.get_services()
                if obj_rich.element.name not in existing_services:
                    raise FirewallError(
                        errors.INVALID_SERVICE,
                        "{} '{}': '{}' not among existing services".format(
                            obj_type, obj.name, obj_rich.element.name
                        ),
                    )


def _handler_add_rich_limit(handler, limit):
    d = {"value": limit.value}
    burst = limit.burst
    if burst is not None:
        d["burst"] = burst
    handler.simpleElement("limit", d)


def common_writer(obj, handler):
    # short
    if obj.short and obj.short != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("short", { })
        handler.characters(obj.short)
        handler.endElement("short")
        handler.ignorableWhitespace("\n")

    # description
    if obj.description and obj.description != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("description", { })
        handler.characters(obj.description)
        handler.endElement("description")
        handler.ignorableWhitespace("\n")

    # services
    for service in uniqify(obj.services):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("service", { "name": service })
        handler.ignorableWhitespace("\n")

    # ports
    for port in uniqify(obj.ports):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("port", { "port": port[0], "protocol": port[1] })
        handler.ignorableWhitespace("\n")

    # protocols
    for protocol in uniqify(obj.protocols):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("protocol", { "value": protocol })
        handler.ignorableWhitespace("\n")

    # icmp-blocks
    for icmp in uniqify(obj.icmp_blocks):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("icmp-block", { "name": icmp })
        handler.ignorableWhitespace("\n")

    # masquerade
    if obj.masquerade:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("masquerade", { })
        handler.ignorableWhitespace("\n")

    # forward-ports
    for forward in uniqify(obj.forward_ports):
        handler.ignorableWhitespace("  ")
        attrs = { "port": forward[0], "protocol": forward[1] }
        if forward[2] and forward[2] != "" :
            attrs["to-port"] = forward[2]
        if forward[3] and forward[3] != "" :
            attrs["to-addr"] = forward[3]
        handler.simpleElement("forward-port", attrs)
        handler.ignorableWhitespace("\n")

    # source-ports
    for port in uniqify(obj.source_ports):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("source-port", { "port": port[0],
                                               "protocol": port[1] })
        handler.ignorableWhitespace("\n")

    # rules
    for rule in obj.rules:
        attrs = { }
        if rule.family:
            attrs["family"] = rule.family
        if rule.priority != 0:
            attrs["priority"] = str(rule.priority)
        handler.ignorableWhitespace("  ")
        handler.startElement("rule", attrs)
        handler.ignorableWhitespace("\n")

        # source
        if rule.source:
            attrs = { }
            if rule.source.addr:
                attrs["address"] = rule.source.addr
            if rule.source.mac:
                attrs["mac"] = rule.source.mac
            if rule.source.ipset:
                attrs["ipset"] = rule.source.ipset
            if rule.source.invert:
                attrs["invert"] = "True"
            handler.ignorableWhitespace("    ")
            handler.simpleElement("source", attrs)
            handler.ignorableWhitespace("\n")

        # destination
        if rule.destination:
            attrs = { }
            if rule.destination.addr:
                attrs["address"] = rule.destination.addr
            if rule.destination.ipset:
                attrs["ipset"] = rule.destination.ipset
            if rule.destination.invert:
                attrs["invert"] = "True"
            handler.ignorableWhitespace("    ")
            handler.simpleElement("destination", attrs)
            handler.ignorableWhitespace("\n")

        # element
        if rule.element:
            element = ""
            attrs = { }

            if type(rule.element) == rich.Rich_Service:
                element = "service"
                attrs["name"] = rule.element.name
            elif type(rule.element) == rich.Rich_Port:
                element = "port"
                attrs["port"] = rule.element.port
                attrs["protocol"] = rule.element.protocol
            elif type(rule.element) == rich.Rich_Protocol:
                element = "protocol"
                attrs["value"] = rule.element.value
            elif type(rule.element) == rich.Rich_Masquerade:
                element = "masquerade"
            elif type(rule.element) == rich.Rich_IcmpBlock:
                element = "icmp-block"
                attrs["name"] = rule.element.name
            elif type(rule.element) == rich.Rich_IcmpType:
                element = "icmp-type"
                attrs["name"] = rule.element.name
            elif type(rule.element) == rich.Rich_ForwardPort:
                element = "forward-port"
                attrs["port"] = rule.element.port
                attrs["protocol"] = rule.element.protocol
                if rule.element.to_port != "":
                    attrs["to-port"] = rule.element.to_port
                if rule.element.to_address != "":
                    attrs["to-addr"] = rule.element.to_address
            elif type(rule.element) == rich.Rich_SourcePort:
                element = "source-port"
                attrs["port"] = rule.element.port
                attrs["protocol"] = rule.element.protocol
            else:
                raise FirewallError(
                    errors.INVALID_OBJECT,
                    "Unknown element '%s' in obj_writer" % type(rule.element))

            handler.ignorableWhitespace("    ")
            handler.simpleElement(element, attrs)
            handler.ignorableWhitespace("\n")

        # rule.element

        # log
        if rule.log:
            attrs = { }
            if rule.log.prefix:
                attrs["prefix"] = rule.log.prefix
            if rule.log.level:
                attrs["level"] = rule.log.level
            if rule.log.limit:
                handler.ignorableWhitespace("    ")
                handler.startElement("log", attrs)
                handler.ignorableWhitespace("\n      ")
                _handler_add_rich_limit(handler, rule.log.limit)
                handler.ignorableWhitespace("\n    ")
                handler.endElement("log")
            else:
                handler.ignorableWhitespace("    ")
                handler.simpleElement("log", attrs)
            handler.ignorableWhitespace("\n")

        # audit
        if rule.audit:
            attrs = {}
            if rule.audit.limit:
                handler.ignorableWhitespace("    ")
                handler.startElement("audit", { })
                handler.ignorableWhitespace("\n      ")
                _handler_add_rich_limit(handler, rule.audit.limit)
                handler.ignorableWhitespace("\n    ")
                handler.endElement("audit")
            else:
                handler.ignorableWhitespace("    ")
                handler.simpleElement("audit", attrs)
            handler.ignorableWhitespace("\n")

        # action
        if rule.action:
            action = ""
            attrs = { }
            if type(rule.action) == rich.Rich_Accept:
                action = "accept"
            elif type(rule.action) == rich.Rich_Reject:
                action = "reject"
                if rule.action.type:
                    attrs["type"] = rule.action.type
            elif type(rule.action) == rich.Rich_Drop:
                action = "drop"
            elif type(rule.action) == rich.Rich_Mark:
                action = "mark"
                attrs["set"] = rule.action.set
            else:
                log.warning("Unknown action '%s'", type(rule.action))
            if rule.action.limit:
                handler.ignorableWhitespace("    ")
                handler.startElement(action, attrs)
                handler.ignorableWhitespace("\n      ")
                _handler_add_rich_limit(handler, rule.action.limit)
                handler.ignorableWhitespace("\n    ")
                handler.endElement(action)
            else:
                handler.ignorableWhitespace("    ")
                handler.simpleElement(action, attrs)
            handler.ignorableWhitespace("\n")

        handler.ignorableWhitespace("  ")
        handler.endElement("rule")
        handler.ignorableWhitespace("\n")


class Policy(IO_Object):
    priority_min = -32768
    priority_max =  32767
    priority_default = DEFAULT_POLICY_PRIORITY
    priority_reserved = [0]

    IMPORT_EXPORT_STRUCTURE = (
        ( "version",  "" ),                            # s
        ( "short", "" ),                               # s
        ( "description", "" ),                         # s
        ( "target", "" ),                              # s
        ( "services", [ "", ], ),                      # as
        ( "ports", [ ( "", "" ), ], ),                 # a(ss)
        ( "icmp_blocks", [ "", ], ),                   # as
        ( "masquerade", False ),                       # b
        ( "forward_ports", [ ( "", "", "", "" ), ], ), # a(ssss)
        ( "rich_rules", [ "" ] ),                      # as
        ( "protocols", [ "", ], ),                     # as
        ( "source_ports", [ ( "", "" ), ], ),          # a(ss)
        ( "priority", 0 ),                             # i
        ( "ingress_zones", [ "" ] ),                   # as
        ( "egress_zones", [ "" ] ),                    # as
        )
    ADDITIONAL_ALNUM_CHARS = [ "_", "-", "/" ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "short": None,
        "description": None,
        "policy": ["target"],
        "service": [ "name" ],
        "port": [ "port", "protocol" ],
        "icmp-block": [ "name" ],
        "icmp-type": [ "name" ],
        "masquerade": None,
        "forward-port": [ "port", "protocol" ],
        "rule": None,
        "source": None,
        "destination": None,
        "protocol": [ "value" ],
        "source-port": [ "port", "protocol" ],
        "log":  None,
        "audit": None,
        "accept": None,
        "reject": None,
        "drop": None,
        "mark": [ "set" ],
        "limit": [ "value" ],
        "ingress-zone": [ "name" ],
        "egress-zone": [ "name" ],
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "policy": [ "version", "priority" ],
        "forward-port": [ "to-port", "to-addr" ],
        "rule": [ "family", "priority" ],
        "source": [ "address", "mac", "invert", "family", "ipset" ],
        "destination": [ "address", "invert", "ipset" ],
        "log": [ "prefix", "level" ],
        "reject": [ "type" ],
        "limit": ["burst"],
        }

    def __init__(self):
        super(Policy, self).__init__()
        self.version = ""
        self.short = ""
        self.description = ""
        self.target = DEFAULT_POLICY_TARGET
        self.services = [ ]
        self.ports = [ ]
        self.protocols = [ ]
        self.icmp_blocks = [ ]
        self.masquerade = False
        self.forward_ports = [ ]
        self.source_ports = [ ]
        self.fw_config = None # to be able to check services and a icmp_blocks
        self.rules = [ ]
        self.rules_str = [ ]
        self.applied = False
        self.priority = self.priority_default
        self.derived_from_zone = None
        self.ingress_zones = []
        self.egress_zones = []

    def cleanup(self):
        self.version = ""
        self.short = ""
        self.description = ""
        self.target = DEFAULT_POLICY_TARGET
        del self.services[:]
        del self.ports[:]
        del self.protocols[:]
        del self.icmp_blocks[:]
        self.masquerade = False
        del self.forward_ports[:]
        del self.source_ports[:]
        self.fw_config = None # to be able to check services and a icmp_blocks
        del self.rules[:]
        del self.rules_str[:]
        self.applied = False
        self.priority = self.priority_default
        del self.ingress_zones[:]
        del self.egress_zones[:]

    def __getattr__(self, name):
        if name == "rich_rules":
            return self.rules_str
        else:
            return getattr(super(Policy, self), name)

    def __setattr__(self, name, value):
        if name == "rich_rules":
            self.rules = [rich.Rich_Rule(rule_str=s) for s in value]
            # must convert back to string to get the canonical string.
            self.rules_str = [str(s) for s in self.rules]
        else:
            super(Policy, self).__setattr__(name, value)

    def _check_config(self, config, item, all_config):
        common_check_config(self, config, item, all_config)

        if item == "target":
            if config not in POLICY_TARGETS:
                raise FirewallError(errors.INVALID_TARGET, "'%s' is invalid target" % (config))
        elif item == "priority":
            if config in self.priority_reserved or \
               config > self.priority_max or \
               config < self.priority_min:
                raise FirewallError(errors.INVALID_PRIORITY, "%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %s" %
                                                             (config, self.priority_min, self.priority_max, self.priority_reserved))
        elif item in ["ingress_zones", "egress_zones"]:
            existing_zones = ["ANY", "HOST"]
            if self.fw_config:
                existing_zones += self.fw_config.get_zones()
            for zone in config:
                if zone not in existing_zones:
                    raise FirewallError(errors.INVALID_ZONE,
                                        "'%s' not among existing zones" % (zone))
                if ((zone not in ["ANY", "HOST"] and (set(["ANY", "HOST"]) & set(config))) or \
                   (zone in ["ANY", "HOST"] and (set(config) - set([zone])))):
                    raise FirewallError(errors.INVALID_ZONE,
                                        "'%s' may only contain one of: many regular zones, ANY, or HOST" % (item))
                if zone == "HOST" and \
                   ((item == "ingress_zones" and "egress_zones" in all_config and "HOST" in all_config["egress_zones"]) or \
                   (item == "egress_zones" and "ingress_zones" in all_config and "HOST" in all_config["ingress_zones"])):
                    raise FirewallError(errors.INVALID_ZONE,
                                        "'HOST' can only appear in either ingress or egress zones, but not both")
        elif item == "masquerade" and config:
            if "egress_zones" in all_config and "HOST" in all_config["egress_zones"]:
                raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'")
            elif "ingress_zones" in all_config:
                if "HOST" in all_config["ingress_zones"]:
                    raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'")
                for zone in all_config["ingress_zones"]:
                    if zone == "ANY":
                        continue
                    z_obj = self.fw_config.get_zone(zone)
                    if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj):
                        raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces")
        elif item == "rich_rules":
            for rule in config:
                obj = rich.Rich_Rule(rule_str=rule)
                if obj.element and isinstance(obj.element, rich.Rich_Masquerade):
                    if "egress_zones" in all_config and "HOST" in all_config["egress_zones"]:
                        raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'")
                    elif "ingress_zones" in all_config:
                        if "HOST" in all_config["ingress_zones"]:
                            raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'")
                        for zone in all_config["ingress_zones"]:
                            if zone == "ANY":
                                continue
                            z_obj = self.fw_config.get_zone(zone)
                            if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj):
                                raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces")
                elif obj.element and isinstance(obj.element, rich.Rich_ForwardPort):
                    if "egress_zones" in all_config:
                        if "HOST" in all_config["egress_zones"]:
                            if obj.element.to_address:
                                raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'")
                        elif all_config["egress_zones"]:
                            if not obj.element.to_address:
                                raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone")
                            if "ANY" not in all_config["egress_zones"]:
                                for zone in all_config["egress_zones"]:
                                    z_obj = self.fw_config.get_zone(zone)
                                    if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj):
                                        raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces")
                elif obj.action and isinstance(obj.action, rich.Rich_Mark):
                    if "egress_zones" in all_config:
                        for zone in all_config["egress_zones"]:
                            if zone in ["ANY", "HOST"]:
                                continue
                            z_obj = self.fw_config.get_zone(zone)
                            if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj):
                                raise FirewallError(errors.INVALID_ZONE, "'mark' action cannot be used in a policy if an egress zone has assigned interfaces")
        elif item == "forward_ports":
            for fwd_port in config:
                if "ingress_zones" in all_config and "HOST" in all_config["ingress_zones"]:
                    raise FirewallError(errors.INVALID_ZONE, "'forward-port' is invalid for ingress zone 'HOST'")
                elif "egress_zones" in all_config:
                    if "HOST" in all_config["egress_zones"]:
                        if fwd_port[3]:
                            raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'")
                    elif all_config["egress_zones"]:
                        if not fwd_port[3]:
                            raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone")
                        if "ANY" not in all_config["egress_zones"]:
                            for zone in all_config["egress_zones"]:
                                z_obj = self.fw_config.get_zone(zone)
                                if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj):
                                    raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces")

    def check_name(self, name):
        super(Policy, self).check_name(name)
        if name.startswith('/'):
            raise FirewallError(errors.INVALID_NAME,
                                "'%s' can't start with '/'" % name)
        elif name.endswith('/'):
            raise FirewallError(errors.INVALID_NAME,
                                "'%s' can't end with '/'" % name)
        elif name.count('/') > 1:
            raise FirewallError(errors.INVALID_NAME,
                                "more than one '/' in '%s'" % name)
        else:
            if "/" in name:
                checked_name = name[:name.find('/')]
            else:
                checked_name = name
            if len(checked_name) > max_policy_name_len():
                raise FirewallError(errors.INVALID_NAME,
                                    "Policy of '%s' has %d chars, max is %d" % (
                                    name, len(checked_name),
                                    max_policy_name_len()))
            if self.fw_config:
                if checked_name in self.fw_config.get_zones():
                    raise FirewallError(errors.NAME_CONFLICT, "Policies can't have the same name as a zone.")

# PARSER

class policy_ContentHandler(IO_Object_ContentHandler):
    def __init__(self, item):
        IO_Object_ContentHandler.__init__(self, item)
        self._rule = None
        self._rule_error = False
        self._limit_ok = None

    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        if self._rule_error:
            return

        self.item.parser_check_element_attrs(name, attrs)

        if common_startElement(self, name, attrs):
            return

        elif name == "policy":
            if "version" in attrs:
                self.item.version = attrs["version"]
            if "priority" in attrs:
                self.item.priority = int(attrs["priority"])
            if "target" in attrs:
                target = attrs["target"]
                if target not in POLICY_TARGETS:
                    raise FirewallError(errors.INVALID_TARGET, target)
                if target:
                    self.item.target = target

        elif name == "ingress-zone":
            if attrs["name"] not in self.item.ingress_zones:
                self.item.ingress_zones.append(attrs["name"])
            else:
                log.warning("Ingress zone '%s' already set, ignoring.", attrs["name"])

        elif name == "egress-zone":
            if attrs["name"] not in self.item.egress_zones:
                self.item.egress_zones.append(attrs["name"])
            else:
                log.warning("Egress zone '%s' already set, ignoring.", attrs["name"])

        elif name == "source":
            if not self._rule:
                log.warning('Invalid rule: Source outside of rule')
                self._rule_error = True
                return

            if self._rule.source:
                log.warning("Invalid rule: More than one source in rule '%s', ignoring.",
                            str(self._rule))
                self._rule_error = True
                return
            invert = False
            if "invert" in attrs and \
                    attrs["invert"].lower() in [ "yes", "true" ]:
                invert = True
            addr = mac = ipset = None
            if "address" in attrs:
                addr = attrs["address"]
            if "mac" in attrs:
                mac = attrs["mac"]
            if "ipset" in attrs:
                ipset = attrs["ipset"]
            self._rule.source = rich.Rich_Source(addr, mac, ipset,
                                                 invert=invert)
            return

        else:
            log.warning("Unknown XML element '%s'", name)
            return

    def endElement(self, name):
        IO_Object_ContentHandler.endElement(self, name)

        common_endElement(self, name)

def policy_reader(filename, path, no_check_name=False):
    policy = Policy()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    policy.name = filename[:-4]
    if not no_check_name:
        policy.check_name(policy.name)
    policy.filename = filename
    policy.path = path
    policy.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    policy.default = policy.builtin
    handler = policy_ContentHandler(policy)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_POLICY,
                                "not a valid policy file: %s" % \
                                msg.getException())
    del handler
    del parser
    return policy

def policy_writer(policy, path=None):
    _path = path if path else policy.path

    if policy.filename:
        name = "%s/%s" % (_path, policy.filename)
    else:
        name = "%s/%s.xml" % (_path, policy.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)

    dirpath = os.path.dirname(name)
    if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start policy element
    attrs = {}
    if policy.version and policy.version != "":
        attrs["version"] = policy.version
    if policy.priority != policy.priority_default:
        attrs["priority"] = str(policy.priority)
    attrs["target"] = policy.target
    handler.startElement("policy", attrs)
    handler.ignorableWhitespace("\n")

    common_writer(policy, handler)

    # ingress-zones
    for zone in uniqify(policy.ingress_zones):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("ingress-zone", { "name": zone })
        handler.ignorableWhitespace("\n")

    # egress-zones
    for zone in uniqify(policy.egress_zones):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("egress-zone", { "name": zone })
        handler.ignorableWhitespace("\n")

    # end policy element
    handler.endElement("policy")
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
io/icmptype.py000064400000015244151731527110007370 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "IcmpType", "icmptype_reader", "icmptype_writer" ]

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.functions import u2b_if_py2
from firewall.core.io.io_object import PY2, IO_Object, \
    IO_Object_ContentHandler, IO_Object_XMLGenerator
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class IcmpType(IO_Object):
    IMPORT_EXPORT_STRUCTURE = (
        ( "version",  "" ),          # s
        ( "short", "" ),             # s
        ( "description", "" ),       # s
        ( "destination", [ "", ], ), # as
        )
    DBUS_SIGNATURE = '(sssas)'
    ADDITIONAL_ALNUM_CHARS = [ "_", "-" ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "short": None,
        "description": None,
        "icmptype": None,
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "icmptype": [ "name", "version" ],
        "destination": [ "ipv4", "ipv6" ],
        }

    def __init__(self):
        super(IcmpType, self).__init__()
        self.version = ""
        self.short = ""
        self.description = ""
        self.destination = [ ]

    def cleanup(self):
        self.version = ""
        self.short = ""
        self.description = ""
        del self.destination[:]

    def encode_strings(self):
        """ HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support."""
        self.version = u2b_if_py2(self.version)
        self.short = u2b_if_py2(self.short)
        self.description = u2b_if_py2(self.description)
        self.destination = [u2b_if_py2(m) for m in self.destination]

    def _check_config(self, config, item, all_config):
        if item == "destination":
            for destination in config:
                if destination not in [ "ipv4", "ipv6" ]:
                    raise FirewallError(errors.INVALID_DESTINATION,
                                        "'%s' not from {'ipv4'|'ipv6'}" % \
                                        destination)

# PARSER

class icmptype_ContentHandler(IO_Object_ContentHandler):
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)

        if name == "icmptype":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'" %
                            attrs["name"])
            if "version" in attrs:
                self.item.version = attrs["version"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "destination":
            for x in [ "ipv4", "ipv6" ]:
                if x in attrs and \
                        attrs[x].lower() in [ "yes", "true" ]:
                    self.item.destination.append(str(x))

def icmptype_reader(filename, path):
    icmptype = IcmpType()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "%s is missing .xml suffix" % filename)
    icmptype.name = filename[:-4]
    icmptype.check_name(icmptype.name)
    icmptype.filename = filename
    icmptype.path = path
    icmptype.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    icmptype.default = icmptype.builtin
    handler = icmptype_ContentHandler(icmptype)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_ICMPTYPE,
                                "not a valid icmptype file: %s" % \
                                msg.getException())
    del handler
    del parser
    if PY2:
        icmptype.encode_strings()
    return icmptype

def icmptype_writer(icmptype, path=None):
    _path = path if path else icmptype.path

    if icmptype.filename:
        name = "%s/%s" % (_path, icmptype.filename)
    else:
        name = "%s/%s.xml" % (_path, icmptype.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)

    dirpath = os.path.dirname(name)
    if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start icmptype element
    attrs = {}
    if icmptype.version and icmptype.version != "":
        attrs["version"] = icmptype.version
    handler.startElement("icmptype", attrs)
    handler.ignorableWhitespace("\n")

    # short
    if icmptype.short and icmptype.short != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("short", { })
        handler.characters(icmptype.short)
        handler.endElement("short")
        handler.ignorableWhitespace("\n")

    # description
    if icmptype.description and icmptype.description != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("description", { })
        handler.characters(icmptype.description)
        handler.endElement("description")
        handler.ignorableWhitespace("\n")

    # destination
    if icmptype.destination:
        handler.ignorableWhitespace("  ")
        attrs = { }
        for x in icmptype.destination:
            attrs[x] = "yes"
        handler.simpleElement("destination", attrs)
        handler.ignorableWhitespace("\n")

    # end icmptype element
    handler.endElement('icmptype')
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
io/__init__.py000064400000003074151731527110007273 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2012 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# fix xmlplus to be compatible with the python xml sax parser and python 3
# by adding __contains__ to xml.sax.xmlreader.AttributesImpl
import xml
if "_xmlplus" in xml.__file__:
    from xml.sax.xmlreader import AttributesImpl
    if not hasattr(AttributesImpl, "__contains__"):
        # this is missing:
        def __AttributesImpl__contains__(self, name):
            return name in getattr(self, "_attrs")
        # add it using the name __contains__
        setattr(AttributesImpl, "__contains__", __AttributesImpl__contains__)
    from xml.sax.saxutils import XMLGenerator
    if not hasattr(XMLGenerator, "_write"):
        # this is missing:
        def __XMLGenerator_write(self, text):
            getattr(self, "_out").write(text)
        # add it using the name _write
        setattr(XMLGenerator, "_write", __XMLGenerator_write)
io/functions.py000064400000011171151731527110007541 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 Red Hat, Inc.
#
# Authors:
# Eric Garver <egarver@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import os

from firewall import config
from firewall.errors import FirewallError

from firewall.core.fw_config import FirewallConfig
from firewall.core.io.zone import zone_reader
from firewall.core.io.service import service_reader
from firewall.core.io.ipset import ipset_reader
from firewall.core.io.icmptype import icmptype_reader
from firewall.core.io.helper import helper_reader
from firewall.core.io.policy import policy_reader
from firewall.core.io.direct import Direct
from firewall.core.io.lockdown_whitelist import LockdownWhitelist
from firewall.core.io.firewalld_conf import firewalld_conf

def check_config(fw):
    fw_config = FirewallConfig(fw)
    readers = {
        "ipset":    {"reader": ipset_reader,
                     "add": fw_config.add_ipset,
                     "dirs": [config.FIREWALLD_IPSETS, config.ETC_FIREWALLD_IPSETS],
                    },
        "helper":   {"reader": helper_reader,
                     "add": fw_config.add_helper,
                     "dirs": [config.FIREWALLD_HELPERS, config.ETC_FIREWALLD_HELPERS],
                    },
        "icmptype": {"reader": icmptype_reader,
                     "add": fw_config.add_icmptype,
                     "dirs": [config.FIREWALLD_ICMPTYPES, config.ETC_FIREWALLD_ICMPTYPES],
                    },
        "service":  {"reader": service_reader,
                     "add": fw_config.add_service,
                     "dirs": [config.FIREWALLD_SERVICES, config.ETC_FIREWALLD_SERVICES],
                    },
        "zone":     {"reader": zone_reader,
                     "add": fw_config.add_zone,
                     "dirs": [config.FIREWALLD_ZONES, config.ETC_FIREWALLD_ZONES],
                    },
        "policy":   {"reader": policy_reader,
                     "add": fw_config.add_policy_object,
                     "dirs": [config.FIREWALLD_POLICIES, config.ETC_FIREWALLD_POLICIES],
                    },
    }
    for reader in readers.keys():
        for _dir in readers[reader]["dirs"]:
            if not os.path.isdir(_dir):
                continue
            for file in sorted(os.listdir(_dir)):
                if file.endswith(".xml"):
                    try:
                        obj = readers[reader]["reader"](file, _dir)
                        if reader in ["zone", "policy"]:
                            obj.fw_config = fw_config
                        obj.check_config_dict(obj.export_config_dict())
                        readers[reader]["add"](obj)
                    except FirewallError as error:
                        raise FirewallError(error.code, "'%s': %s" % (file, error.msg))
                    except Exception as msg:
                        raise Exception("'%s': %s" % (file, msg))
    if os.path.isfile(config.FIREWALLD_DIRECT):
        try:
            obj = Direct(config.FIREWALLD_DIRECT)
            obj.read()
            obj.check_config(obj.export_config())
        except FirewallError as error:
            raise FirewallError(error.code, "'%s': %s" % (config.FIREWALLD_DIRECT, error.msg))
        except Exception as msg:
            raise Exception("'%s': %s" % (config.FIREWALLD_DIRECT, msg))
    if os.path.isfile(config.LOCKDOWN_WHITELIST):
        try:
            obj = LockdownWhitelist(config.LOCKDOWN_WHITELIST)
            obj.read()
            obj.check_config(obj.export_config())
        except FirewallError as error:
            raise FirewallError(error.code, "'%s': %s" % (config.LOCKDOWN_WHITELIST, error.msg))
        except Exception as msg:
            raise Exception("'%s': %s" % (config.LOCKDOWN_WHITELIST, msg))
    if os.path.isfile(config.FIREWALLD_CONF):
        try:
            obj = firewalld_conf(config.FIREWALLD_CONF)
            obj.read()
        except FirewallError as error:
            raise FirewallError(error.code, "'%s': %s" % (config.FIREWALLD_CONF, error.msg))
        except Exception as msg:
            raise Exception("'%s': %s" % (config.FIREWALLD_CONF, msg))
io/service.py000064400000031325151731527110007174 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "Service", "service_reader", "service_writer" ]

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.functions import u2b_if_py2
from firewall.core.io.io_object import PY2, IO_Object, \
    IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \
    check_tcpudp, check_protocol, check_address
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class Service(IO_Object):
    IMPORT_EXPORT_STRUCTURE = (
        ( "version",  "" ),
        ( "short", "" ),
        ( "description", "" ),
        ( "ports", [ ( "", "" ), ], ),
        ( "modules", [ "", ], ),
        ( "destination", { "": "", }, ),
        ( "protocols", [ "", ], ),
        ( "source_ports", [ ( "", "" ), ], ),
        ( "includes", [ "" ], ),
        ( "helpers", [ "", ], ),
        )
    ADDITIONAL_ALNUM_CHARS = [ "_", "-" ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "short": None,
        "description": None,
        "service": None,
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "service": [ "name", "version" ],
        "port": [ "port", "protocol" ],
        "protocol": [ "value" ],
        "module": [ "name" ],
        "destination": [ "ipv4", "ipv6" ],
        "source-port": [ "port", "protocol" ],
        "include": [ "service" ],
        "helper": [ "name" ],
        }

    def __init__(self):
        super(Service, self).__init__()
        self.version = ""
        self.short = ""
        self.description = ""
        self.ports = [ ]
        self.protocols = [ ]
        self.modules = [ ]
        self.destination = { }
        self.source_ports = [ ]
        self.includes = [ ]
        self.helpers = [ ]

    def cleanup(self):
        self.version = ""
        self.short = ""
        self.description = ""
        del self.ports[:]
        del self.protocols[:]
        del self.modules[:]
        self.destination.clear()
        del self.source_ports[:]
        del self.includes[:]
        del self.helpers[:]

    def encode_strings(self):
        """ HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support."""
        self.version = u2b_if_py2(self.version)
        self.short = u2b_if_py2(self.short)
        self.description = u2b_if_py2(self.description)
        self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports]
        self.modules = [u2b_if_py2(m) for m in self.modules]
        self.destination = {u2b_if_py2(k):u2b_if_py2(v) for k,v in self.destination.items()}
        self.protocols = [u2b_if_py2(pr) for pr in self.protocols]
        self.source_ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr)
                             in self.source_ports]
        self.includes = [u2b_if_py2(s) for s in self.includes]
        self.helpers = [u2b_if_py2(s) for s in self.helpers]

    def _check_config(self, config, item, all_config):
        if item == "ports":
            for port in config:
                if port[0] != "":
                    check_port(port[0])
                    check_tcpudp(port[1])
                else:
                    # only protocol
                    check_protocol(port[1])

        elif item == "protocols":
            for proto in config:
                check_protocol(proto)

        elif item == "source_ports":
            for port in config:
                check_port(port[0])
                check_tcpudp(port[1])

        elif item == "destination":
            for destination in config:
                if destination not in [ "ipv4", "ipv6" ]:
                    raise FirewallError(errors.INVALID_DESTINATION,
                                        "'%s' not in {'ipv4'|'ipv6'}" % \
                                        destination)
                check_address(destination, config[destination])

        elif item == "modules":
            for module in config:
                if module.startswith("nf_conntrack_"):
                    module = module.replace("nf_conntrack_", "")
                    if "_" in module:
                        module = module.replace("_", "-")
                if len(module) < 2:
                    raise FirewallError(errors.INVALID_MODULE, module)

# PARSER

class service_ContentHandler(IO_Object_ContentHandler):
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)
        if name == "service":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'",
                            attrs["name"])
            if "version" in attrs:
                self.item.version = attrs["version"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "port":
            if attrs["port"] != "":
                check_port(attrs["port"])
                check_tcpudp(attrs["protocol"])
                entry = (attrs["port"], attrs["protocol"])
                if entry not in self.item.ports:
                    self.item.ports.append(entry)
                else:
                    log.warning("Port '%s/%s' already set, ignoring.",
                                attrs["port"], attrs["protocol"])
            else:
                check_protocol(attrs["protocol"])
                if attrs["protocol"] not in self.item.protocols:
                    self.item.protocols.append(attrs["protocol"])
                else:
                    log.warning("Protocol '%s' already set, ignoring.",
                                attrs["protocol"])
        elif name == "protocol":
            check_protocol(attrs["value"])
            if attrs["value"] not in self.item.protocols:
                self.item.protocols.append(attrs["value"])
            else:
                log.warning("Protocol '%s' already set, ignoring.",
                            attrs["value"])
        elif name == "source-port":
            check_port(attrs["port"])
            check_tcpudp(attrs["protocol"])
            entry = (attrs["port"], attrs["protocol"])
            if entry not in self.item.source_ports:
                self.item.source_ports.append(entry)
            else:
                log.warning("SourcePort '%s/%s' already set, ignoring.",
                            attrs["port"], attrs["protocol"])
        elif name == "destination":
            for x in [ "ipv4", "ipv6" ]:
                if x in attrs:
                    check_address(x, attrs[x])
                    if x in self.item.destination:
                        log.warning("Destination address for '%s' already set, ignoring",
                                    x)
                    else:
                        self.item.destination[x] = attrs[x]
        elif name == "module":
            module = attrs["name"]
            if module.startswith("nf_conntrack_"):
                module = module.replace("nf_conntrack_", "")
                if "_" in module:
                    module = module.replace("_", "-")
            if module not in self.item.modules:
                self.item.modules.append(module)
            else:
                log.warning("Module '%s' already set, ignoring.",
                            module)
        elif name == "include":
            if attrs["service"] not in self.item.includes:
                self.item.includes.append(attrs["service"])
            else:
                log.warning("Include '%s' already set, ignoring.",
                            attrs["service"])
        elif name == "helper":
            if attrs["name"] not in self.item.helpers:
                self.item.helpers.append(attrs["name"])
            else:
                log.warning("Helper '%s' already set, ignoring.",
                            attrs["name"])


def service_reader(filename, path):
    service = Service()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    service.name = filename[:-4]
    service.check_name(service.name)
    service.filename = filename
    service.path = path
    service.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    service.default = service.builtin
    handler = service_ContentHandler(service)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_SERVICE,
                                "not a valid service file: %s" % \
                                msg.getException())
    del handler
    del parser
    if PY2:
        service.encode_strings()
    return service

def service_writer(service, path=None):
    _path = path if path else service.path

    if service.filename:
        name = "%s/%s" % (_path, service.filename)
    else:
        name = "%s/%s.xml" % (_path, service.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)

    dirpath = os.path.dirname(name)
    if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start service element
    attrs = {}
    if service.version and service.version != "":
        attrs["version"] = service.version
    handler.startElement("service", attrs)
    handler.ignorableWhitespace("\n")

    # short
    if service.short and service.short != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("short", { })
        handler.characters(service.short)
        handler.endElement("short")
        handler.ignorableWhitespace("\n")

    # description
    if service.description and service.description != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("description", { })
        handler.characters(service.description)
        handler.endElement("description")
        handler.ignorableWhitespace("\n")

    # ports
    for port in service.ports:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("port", { "port": port[0], "protocol": port[1] })
        handler.ignorableWhitespace("\n")

    # protocols
    for protocol in service.protocols:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("protocol", { "value": protocol })
        handler.ignorableWhitespace("\n")

    # source ports
    for port in service.source_ports:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("source-port", { "port": port[0],
                                               "protocol": port[1] })
        handler.ignorableWhitespace("\n")

    # modules
    for module in service.modules:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("module", { "name": module })
        handler.ignorableWhitespace("\n")

    # destination
    if len(service.destination) > 0:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("destination", service.destination)
        handler.ignorableWhitespace("\n")

    # includes
    for include in service.includes:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("include", { "service": include })
        handler.ignorableWhitespace("\n")

    # helpers
    for helper in service.helpers:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("helper", { "name": helper })
        handler.ignorableWhitespace("\n")

    # end service element
    handler.endElement('service')
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
io/lockdown_whitelist.py000064400000030647151731527110011456 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.core.io.io_object import PY2, IO_Object, \
                    IO_Object_ContentHandler, IO_Object_XMLGenerator
from firewall.core.logger import log
from firewall.functions import uniqify, checkUser, checkUid, checkCommand, \
                               checkContext, u2b_if_py2
from firewall import errors
from firewall.errors import FirewallError

class lockdown_whitelist_ContentHandler(IO_Object_ContentHandler):
    def __init__(self, item):
        IO_Object_ContentHandler.__init__(self, item)
        self.whitelist = False

    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)

        if name == "whitelist":
            if self.whitelist:
                raise FirewallError(errors.PARSE_ERROR,
                                    "More than one whitelist.")
            self.whitelist = True

        elif name == "command":
            if not self.whitelist:
                log.error("Parse Error: command outside of whitelist")
                return
            command = attrs["name"]
            self.item.add_command(command)

        elif name == "user":
            if not self.whitelist:
                log.error("Parse Error: user outside of whitelist")
                return
            if "id" in attrs:
                try:
                    uid = int(attrs["id"])
                except ValueError:
                    log.error("Parse Error: %s is not a valid uid" % 
                              attrs["id"])
                    return
                self.item.add_uid(uid)
            elif "name" in attrs:
                self.item.add_user(attrs["name"])

        elif name == "selinux":
            if not self.whitelist:
                log.error("Parse Error: selinux outside of whitelist")
                return
            if "context" not in attrs:
                log.error("Parse Error: no context")
                return
            self.item.add_context(attrs["context"])
            

        else:
            log.error('Unknown XML element %s' % name)
            return

class LockdownWhitelist(IO_Object):
    """ LockdownWhitelist class """

    IMPORT_EXPORT_STRUCTURE = (
        ( "commands", [ "" ] ),   # as
        ( "contexts", [ "" ] ),   # as
        ( "users", [ "" ] ),      # as
        ( "uids", [ 0 ] )         # ai
        )
    DBUS_SIGNATURE = '(asasasai)'
    ADDITIONAL_ALNUM_CHARS = [ "_" ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "whitelist": None,
        "command": [ "name" ],
        "user": None,
#        "group": None,
        "selinux": [ "context" ],
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "user": [ "id", "name" ],
#        "group": [ "id", "name" ],
        }

    def __init__(self, filename):
        super(LockdownWhitelist, self).__init__()
        self.filename = filename
        self.parser = None
        self.commands = [ ]
        self.contexts = [ ]
        self.users = [ ]
        self.uids = [ ]
#        self.gids = [ ]
#        self.groups = [ ]

    def _check_config(self, config, item, all_config):
        if item in [ "commands", "contexts", "users", "uids" ]:
            for x in config:
                self._check_config(x, item[:-1], all_config)
        elif item == "command":
            if not checkCommand(config):
                raise FirewallError(errors.INVALID_COMMAND, config)
        elif item == "context":
            if not checkContext(config):
                raise FirewallError(errors.INVALID_CONTEXT, config)
        elif item == "user":
            if not checkUser(config):
                raise FirewallError(errors.INVALID_USER, config)
        elif item == "uid":
            if not checkUid(config):
                raise FirewallError(errors.INVALID_UID, config)

    def cleanup(self):
        del self.commands[:]
        del self.contexts[:]
        del self.users[:]
        del self.uids[:]
#        del self.gids[:]
#        del self.groups[:]

    def encode_strings(self):
        """ HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support."""
        self.commands = [ u2b_if_py2(x) for x in self.commands ]
        self.contexts = [ u2b_if_py2(x) for x in self.contexts ]
        self.users = [ u2b_if_py2(x) for x in self.users ]

    # commands

    def add_command(self, command):
        if not checkCommand(command):
            raise FirewallError(errors.INVALID_COMMAND, command)
        if command not in self.commands:
            self.commands.append(command)
        else:
            raise FirewallError(errors.ALREADY_ENABLED,
                                'Command "%s" already in whitelist' % command)

    def remove_command(self, command):
        if command in self.commands:
            self.commands.remove(command)
        else:
            raise FirewallError(errors.NOT_ENABLED,
                                'Command "%s" not in whitelist.' % command)

    def has_command(self, command):
        return (command in self.commands)

    def match_command(self, command):
        for _command in self.commands:
            if _command.endswith("*"):
                if command.startswith(_command[:-1]):
                    return True
            else:
                if _command == command:
                    return True
        return False

    def get_commands(self):
        return self.commands

    # user ids

    def add_uid(self, uid):
        if not checkUid(uid):
            raise FirewallError(errors.INVALID_UID, str(uid))
        if uid not in self.uids:
            self.uids.append(uid)
        else:
            raise FirewallError(errors.ALREADY_ENABLED,
                                'Uid "%s" already in whitelist' % uid)


    def remove_uid(self, uid):
        if uid in self.uids:
            self.uids.remove(uid)
        else:
            raise FirewallError(errors.NOT_ENABLED,
                                'Uid "%s" not in whitelist.' % uid)

    def has_uid(self, uid):
        return (uid in self.uids)

    def match_uid(self, uid):
        return (uid in self.uids)

    def get_uids(self):
        return self.uids

    # users

    def add_user(self, user):
        if not checkUser(user):
            raise FirewallError(errors.INVALID_USER, user)
        if user not in self.users:
            self.users.append(user)
        else:
            raise FirewallError(errors.ALREADY_ENABLED,
                                'User "%s" already in whitelist' % user)


    def remove_user(self, user):
        if user in self.users:
            self.users.remove(user)
        else:
            raise FirewallError(errors.NOT_ENABLED,
                                'User "%s" not in whitelist.' % user)

    def has_user(self, user):
        return (user in self.users)

    def match_user(self, user):
        return (user in self.users)

    def get_users(self):
        return self.users

#    # group ids
#
#    def add_gid(self, gid):
#        if gid not in self.gids:
#            self.gids.append(gid)
#
#    def remove_gid(self, gid):
#        if gid in self.gids:
#            self.gids.remove(gid)
#        else:
#            raise FirewallError(errors.NOT_ENABLED,
#                                'Gid "%s" not in whitelist.' % gid)
#
#    def has_gid(self, gid):
#        return (gid in self.gids)
#
#    def match_gid(self, gid):
#        return (gid in self.gids)
#
#    def get_gids(self):
#        return self.gids

#    # groups
#
#    def add_group(self, group):
#        if group not in self.groups:
#            self.groups.append(group)
#
#    def remove_group(self, group):
#        if group in self.groups:
#            self.groups.remove(group)
#        else:
#            raise FirewallError(errors.NOT_ENABLED,
#                                'Group "%s" not in whitelist.' % group)
#
#    def has_group(self, group):
#        return (group in self.groups)
#
#    def match_group(self, group):
#        return (group in self.groups)
#
#    def get_groups(self):
#        return self.groups

    # selinux contexts

    def add_context(self, context):
        if not checkContext(context):
            raise FirewallError(errors.INVALID_CONTEXT, context)
        if context not in self.contexts:
            self.contexts.append(context)
        else:
            raise FirewallError(errors.ALREADY_ENABLED,
                                'Context "%s" already in whitelist' % context)


    def remove_context(self, context):
        if context in self.contexts:
            self.contexts.remove(context)
        else:
            raise FirewallError(errors.NOT_ENABLED,
                                'Context "%s" not in whitelist.' % context)

    def has_context(self, context):
        return (context in self.contexts)

    def match_context(self, context):
        return (context in self.contexts)

    def get_contexts(self):
        return self.contexts

    # read and write

    def read(self):
        self.cleanup()
        if not self.filename.endswith(".xml"):
            raise FirewallError(errors.INVALID_NAME,
                                "'%s' is missing .xml suffix" % self.filename)
        handler = lockdown_whitelist_ContentHandler(self)
        parser = sax.make_parser()
        parser.setContentHandler(handler)
        try:
            parser.parse(self.filename)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_TYPE,
                                "Not a valid file: %s" % \
                                msg.getException())
        del handler
        del parser
        if PY2:
            self.encode_strings()

    def write(self):
        if os.path.exists(self.filename):
            try:
                shutil.copy2(self.filename, "%s.old" % self.filename)
            except Exception as msg:
                raise IOError("Backup of '%s' failed: %s" % (self.filename, msg))

        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)

        f = io.open(self.filename, mode='wt', encoding='UTF-8')
        handler = IO_Object_XMLGenerator(f)
        handler.startDocument()

        # start whitelist element
        handler.startElement("whitelist", { })
        handler.ignorableWhitespace("\n")

        # commands
        for command in uniqify(self.commands):
            handler.ignorableWhitespace("  ")
            handler.simpleElement("command", { "name": command })
            handler.ignorableWhitespace("\n")

        for uid in uniqify(self.uids):
            handler.ignorableWhitespace("  ")
            handler.simpleElement("user", { "id": str(uid) })
            handler.ignorableWhitespace("\n")

        for user in uniqify(self.users):
            handler.ignorableWhitespace("  ")
            handler.simpleElement("user", { "name": user })
            handler.ignorableWhitespace("\n")

#        for gid in uniqify(self.gids):
#            handler.ignorableWhitespace("  ")
#            handler.simpleElement("user", { "id": str(gid) })
#            handler.ignorableWhitespace("\n")

#        for group in uniqify(self.groups):
#            handler.ignorableWhitespace("  ")
#            handler.simpleElement("group", { "name": group })
#            handler.ignorableWhitespace("\n")

        for context in uniqify(self.contexts):
            handler.ignorableWhitespace("  ")
            handler.simpleElement("selinux", { "context": context })
            handler.ignorableWhitespace("\n")

        # end whitelist element
        handler.endElement("whitelist")
        handler.ignorableWhitespace("\n")
        handler.endDocument()
        f.close()
        del handler
io/firewalld_conf.py000064400000032774151731527120010524 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2012 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import os.path
import io
import tempfile
import shutil

from firewall import config
from firewall.core.logger import log
from firewall.functions import b2u, u2b, PY2

valid_keys = [ "DefaultZone", "MinimalMark", "CleanupOnExit",
               "CleanupModulesOnExit", "Lockdown", "IPv6_rpfilter",
               "IndividualCalls", "LogDenied", "AutomaticHelpers",
               "FirewallBackend", "FlushAllOnReload", "RFC3964_IPv4",
               "AllowZoneDrifting" ]

class firewalld_conf(object):
    def __init__(self, filename):
        self._config = { }
        self._deleted = [ ]
        self.filename = filename
        self.clear()

    def clear(self):
        self._config = { }
        self._deleted = [ ]

    def cleanup(self):
        self._config.clear()
        self._deleted = [ ]

    def get(self, key):
        return self._config.get(key.strip())

    def set(self, key, value):
        _key = b2u(key.strip())
        self._config[_key] = b2u(value.strip())
        if _key in self._deleted:
            self._deleted.remove(_key)

    def __str__(self):
        s = ""
        for (key,value) in self._config.items():
            if s:
                s += '\n'
            s += '%s=%s' % (key, value)
        return u2b(s) if PY2 else s

    # load self.filename
    def read(self):
        self.clear()
        try:
            f = open(self.filename, "r")
        except Exception as msg:
            log.error("Failed to load '%s': %s", self.filename, msg)
            self.set("DefaultZone", config.FALLBACK_ZONE)
            self.set("MinimalMark", str(config.FALLBACK_MINIMAL_MARK))
            self.set("CleanupOnExit", "yes" if config.FALLBACK_CLEANUP_ON_EXIT else "no")
            self.set("CleanupModulesOnExit", "yes" if config.FALLBACK_CLEANUP_MODULES_ON_EXIT else "no")
            self.set("Lockdown", "yes" if config.FALLBACK_LOCKDOWN else "no")
            self.set("IPv6_rpfilter","yes" if config.FALLBACK_IPV6_RPFILTER else "no")
            self.set("IndividualCalls", "yes" if config.FALLBACK_INDIVIDUAL_CALLS else "no")
            self.set("LogDenied", config.FALLBACK_LOG_DENIED)
            self.set("AutomaticHelpers", config.FALLBACK_AUTOMATIC_HELPERS)
            self.set("FirewallBackend", config.FALLBACK_FIREWALL_BACKEND)
            self.set("FlushAllOnReload", "yes" if config.FALLBACK_FLUSH_ALL_ON_RELOAD else "no")
            self.set("RFC3964_IPv4", "yes" if config.FALLBACK_RFC3964_IPV4 else "no")
            self.set("AllowZoneDrifting", "yes" if config.FALLBACK_ALLOW_ZONE_DRIFTING else "no")
            raise

        for line in f:
            if not line:
                break
            line = line.strip()
            if len(line) < 1 or line[0] in ['#', ';']:
                continue
            # get key/value pair
            pair = [ x.strip() for x in line.split("=") ]
            if len(pair) != 2:
                log.error("Invalid option definition: '%s'", line.strip())
                continue
            elif pair[0] not in valid_keys:
                log.error("Invalid option: '%s'", line.strip())
                continue
            elif pair[1] == '':
                log.error("Missing value: '%s'", line.strip())
                continue
            elif self._config.get(pair[0]) is not None:
                log.error("Duplicate option definition: '%s'", line.strip())
                continue
            self._config[pair[0]] = pair[1]
        f.close()

        # check default zone
        if not self.get("DefaultZone"):
            log.error("DefaultZone is not set, using default value '%s'",
                      config.FALLBACK_ZONE)
            self.set("DefaultZone", str(config.FALLBACK_ZONE))

        # check minimal mark
        value = self.get("MinimalMark")
        try:
            int(value)
        except (ValueError, TypeError):
            if value is not None:
                log.warning("MinimalMark '%s' is not valid, using default "
                            "value '%d'", value if value else '',
                            config.FALLBACK_MINIMAL_MARK)
            self.set("MinimalMark", str(config.FALLBACK_MINIMAL_MARK))

        # check cleanup on exit
        value = self.get("CleanupOnExit")
        if not value or value.lower() not in [ "no", "false", "yes", "true" ]:
            if value is not None:
                log.warning("CleanupOnExit '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_CLEANUP_ON_EXIT)
            self.set("CleanupOnExit", "yes" if config.FALLBACK_CLEANUP_ON_EXIT else "no")

        # check module cleanup on exit
        value = self.get("CleanupModulesOnExit")
        if not value or value.lower() not in [ "no", "false", "yes", "true" ]:
            if value is not None:
                log.warning("CleanupModulesOnExit '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_CLEANUP_MODULES_ON_EXIT)
            self.set("CleanupModulesOnExit", "yes" if config.FALLBACK_CLEANUP_MODULES_ON_EXIT else "no")

        # check lockdown
        value = self.get("Lockdown")
        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
            if value is not None:
                log.warning("Lockdown '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_LOCKDOWN)
            self.set("Lockdown", "yes" if config.FALLBACK_LOCKDOWN else "no")

        # check ipv6_rpfilter
        value = self.get("IPv6_rpfilter")
        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
            if value is not None:
                log.warning("IPv6_rpfilter '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_IPV6_RPFILTER)
            self.set("IPv6_rpfilter","yes" if config.FALLBACK_IPV6_RPFILTER else "no")

        # check individual calls
        value = self.get("IndividualCalls")
        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
            if value is not None:
                log.warning("IndividualCalls '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_INDIVIDUAL_CALLS)
            self.set("IndividualCalls", "yes" if config.FALLBACK_INDIVIDUAL_CALLS else "no")

        # check log denied
        value = self.get("LogDenied")
        if not value or value not in config.LOG_DENIED_VALUES:
            if value is not None:
                log.warning("LogDenied '%s' is invalid, using default value '%s'",
                            value, config.FALLBACK_LOG_DENIED)
            self.set("LogDenied", str(config.FALLBACK_LOG_DENIED))

        # check automatic helpers
        value = self.get("AutomaticHelpers")
        if not value or value.lower() not in config.AUTOMATIC_HELPERS_VALUES:
            if value is not None:
                log.warning("AutomaticHelpers '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_AUTOMATIC_HELPERS)
            self.set("AutomaticHelpers", str(config.FALLBACK_AUTOMATIC_HELPERS))

        value = self.get("FirewallBackend")
        if not value or value.lower() not in config.FIREWALL_BACKEND_VALUES:
            if value is not None:
                log.warning("FirewallBackend '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_FIREWALL_BACKEND)
            self.set("FirewallBackend", str(config.FALLBACK_FIREWALL_BACKEND))

        value = self.get("FlushAllOnReload")
        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
            if value is not None:
                log.warning("FlushAllOnReload '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_FLUSH_ALL_ON_RELOAD)
            self.set("FlushAllOnReload", str(config.FALLBACK_FLUSH_ALL_ON_RELOAD))

        value = self.get("RFC3964_IPv4")
        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
            if value is not None:
                log.warning("RFC3964_IPv4 '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_RFC3964_IPV4)
            self.set("RFC3964_IPv4", str(config.FALLBACK_RFC3964_IPV4))

        value = self.get("AllowZoneDrifting")
        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
            if value is not None:
                log.warning("AllowZoneDrifting '%s' is not valid, using default "
                            "value %s", value if value else '',
                            config.FALLBACK_ALLOW_ZONE_DRIFTING)
            self.set("AllowZoneDrifting", str(config.FALLBACK_ALLOW_ZONE_DRIFTING))

    # save to self.filename if there are key/value changes
    def write(self):
        if len(self._config) < 1:
            # no changes: nothing to do
            return

        # handled keys
        done = [ ]

        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)

        try:
            temp_file = tempfile.NamedTemporaryFile(mode='wt',
                             prefix="%s." % os.path.basename(self.filename),
                             dir=os.path.dirname(self.filename), delete=False)
        except Exception as msg:
            log.error("Failed to open temporary file: %s" % msg)
            raise

        modified = False
        empty = False
        try:
            f= io.open(self.filename, mode='rt', encoding='UTF-8')
        except Exception as msg:
            if os.path.exists(self.filename):
                log.error("Failed to open '%s': %s" % (self.filename, msg))
                raise
            else:
                f = None
        else:
            for line in f:
                if not line:
                    break
                # remove newline
                line = line.strip("\n")

                if len(line) < 1:
                    if not empty:
                        temp_file.write(u"\n")
                        empty = True
                elif line[0] == '#':
                    empty = False
                    temp_file.write(line)
                    temp_file.write(u"\n")
                else:
                    p = line.split("=")
                    if len(p) != 2:
                        empty = False
                        temp_file.write(line+u"\n")
                        continue
                    key = p[0].strip()
                    value = p[1].strip()
                    # check for modified key/value pairs
                    if key not in done:
                        if (key in self._config and \
                                self._config[key] != value):
                            empty = False
                            temp_file.write(u'%s=%s\n' %
                                            (key, self._config[key]))
                            modified = True
                        elif key in self._deleted:
                            modified = True
                        else:
                            empty = False
                            temp_file.write(line+u"\n")
                        done.append(key)
                    else:
                        modified = True

        # write remaining key/value pairs
        if len(self._config) > 0:
            for (key,value) in self._config.items():
                if key in done:
                    continue
                if key in ["MinimalMark", "AutomaticHelpers"]: # omit deprecated from new config
                    continue
                if not empty:
                    temp_file.write(u"\n")
                    empty = True
                temp_file.write(u'%s=%s\n' % (key, value))
                modified = True

        if f:
            f.close()
        temp_file.close()

        if not modified: # not modified: remove tempfile
            os.remove(temp_file.name)
            return
        # make backup
        if os.path.exists(self.filename):
            try:
                shutil.copy2(self.filename, "%s.old" % self.filename)
            except Exception as msg:
                os.remove(temp_file.name)
                raise IOError("Backup of '%s' failed: %s" % (self.filename, msg))

        # copy tempfile
        try:
            shutil.move(temp_file.name, self.filename)
        except Exception as msg:
            os.remove(temp_file.name)
            raise IOError("Failed to create '%s': %s" % (self.filename, msg))
        else:
            os.chmod(self.filename, 0o600)
io/ifcfg.py000064400000014345151731527120006616 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""ifcfg file parser"""

__all__ = [ "ifcfg" ]

import os.path
import io
import tempfile
import shutil

from firewall.core.logger import log
from firewall.functions import b2u, u2b, PY2

class ifcfg(object):
    def __init__(self, filename):
        self._config = { }
        self._deleted = [ ]
        self.filename = filename
        self.clear()

    def clear(self):
        self._config = { }
        self._deleted = [ ]

    def cleanup(self):
        self._config.clear()

    def get(self, key):
        return self._config.get(key.strip())

    def set(self, key, value):
        _key = b2u(key.strip())
        self._config[_key] = b2u(value.strip())
        if _key in self._deleted:
            self._deleted.remove(_key)

    def __str__(self):
        s = ""
        for (key, value) in self._config.items():
            if s:
                s += '\n'
            s += '%s=%s' % (key, value)
        return u2b(s) if PY2 else s

    # load self.filename
    def read(self):
        self.clear()
        try:
            f = open(self.filename, "r")
        except Exception as msg:
            log.error("Failed to load '%s': %s", self.filename, msg)
            raise

        for line in f:
            if not line:
                break
            line = line.strip()
            if len(line) < 1 or line[0] in ['#', ';']:
                continue
            # get key/value pair
            pair = [ x.strip() for x in line.split("=", 1) ]
            if len(pair) != 2:
                continue
            if len(pair[1]) >= 2 and \
               pair[1].startswith('"') and pair[1].endswith('"'):
                pair[1] = pair[1][1:-1]
            if pair[1] == '':
                continue
            elif self._config.get(pair[0]) is not None:
                log.warning("%s: Duplicate option definition: '%s'", self.filename, line.strip())
                continue
            self._config[pair[0]] = pair[1]
        f.close()

    def write(self):
        if len(self._config) < 1:
            # no changes: nothing to do
            return

        # handled keys
        done = [ ]

        try:
            temp_file = tempfile.NamedTemporaryFile(
                mode='wt',
                prefix="%s." % os.path.basename(self.filename),
                dir=os.path.dirname(self.filename), delete=False)
        except Exception as msg:
            log.error("Failed to open temporary file: %s" % msg)
            raise

        modified = False
        empty = False
        try:
            f = io.open(self.filename, mode='rt', encoding='UTF-8')
        except Exception as msg:
            if os.path.exists(self.filename):
                log.error("Failed to open '%s': %s" % (self.filename, msg))
                raise
            else:
                f = None
        else:
            for line in f:
                if not line:
                    break
                # remove newline
                line = line.strip("\n")

                if len(line) < 1:
                    if not empty:
                        temp_file.write(u"\n")
                        empty = True
                elif line[0] == '#':
                    empty = False
                    temp_file.write(line)
                    temp_file.write(u"\n")
                else:
                    p = line.split("=", 1)
                    if len(p) != 2:
                        empty = False
                        temp_file.write(line+u"\n")
                        continue
                    key = p[0].strip()
                    value = p[1].strip()
                    if len(value) >= 2 and \
                       value.startswith('"') and value.endswith('"'):
                        value = value[1:-1]
                    # check for modified key/value pairs
                    if key not in done:
                        if key in self._config and self._config[key] != value:
                            empty = False
                            temp_file.write(u'%s=%s\n' % (key,
                                                          self._config[key]))
                            modified = True
                        elif key in self._deleted:
                            modified = True
                        else:
                            empty = False
                            temp_file.write(line+u"\n")
                        done.append(key)
                    else:
                        modified = True

        # write remaining key/value pairs
        if len(self._config) > 0:
            for (key, value) in self._config.items():
                if key in done:
                    continue
                if not empty:
                    empty = True
                temp_file.write(u'%s=%s\n' % (key, value))
                modified = True

        if f:
            f.close()
        temp_file.close()

        if not modified: # not modified: remove tempfile
            os.remove(temp_file.name)
            return
        # make backup
        if os.path.exists(self.filename):
            try:
                shutil.copy2(self.filename, "%s.bak" % self.filename)
            except Exception as msg:
                os.remove(temp_file.name)
                raise IOError("Backup of '%s' failed: %s" % (self.filename, msg))

        # copy tempfile
        try:
            shutil.move(temp_file.name, self.filename)
        except Exception as msg:
            os.remove(temp_file.name)
            raise IOError("Failed to create '%s': %s" % (self.filename, msg))
        else:
            os.chmod(self.filename, 0o600)
io/zone.py000064400000046600151731527120006512 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "Zone", "zone_reader", "zone_writer" ]

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.functions import checkIPnMask, checkIP6nMask, checkInterface, uniqify, max_zone_name_len, u2b_if_py2, check_mac
from firewall.core.base import DEFAULT_ZONE_TARGET, ZONE_TARGETS
from firewall.core.io.io_object import PY2, IO_Object, \
    IO_Object_ContentHandler, IO_Object_XMLGenerator
from firewall.core.io.policy import common_startElement, common_endElement, common_check_config, common_writer
from firewall.core import rich
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class Zone(IO_Object):
    """ Zone class """

    IMPORT_EXPORT_STRUCTURE = (
        ( "version",  "" ),                            # s
        ( "short", "" ),                               # s
        ( "description", "" ),                         # s
        ( "UNUSED", False ),                           # b
        ( "target", "" ),                              # s
        ( "services", [ "", ], ),                      # as
        ( "ports", [ ( "", "" ), ], ),                 # a(ss)
        ( "icmp_blocks", [ "", ], ),                   # as
        ( "masquerade", False ),                       # b
        ( "forward_ports", [ ( "", "", "", "" ), ], ), # a(ssss)
        ( "interfaces", [ "" ] ),                      # as
        ( "sources", [ "" ] ),                         # as
        ( "rules_str", [ "" ] ),                       # as
        ( "protocols", [ "", ], ),                     # as
        ( "source_ports", [ ( "", "" ), ], ),          # a(ss)
        ( "icmp_block_inversion", False ),             # b
        ( "forward", False ),                          # b
        )
    ADDITIONAL_ALNUM_CHARS = [ "_", "-", "/" ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "short": None,
        "description": None,
        "zone": None,
        "service": [ "name" ],
        "port": [ "port", "protocol" ],
        "icmp-block": [ "name" ],
        "icmp-type": [ "name" ],
        "forward": None,
        "forward-port": [ "port", "protocol" ],
        "interface": [ "name" ],
        "rule": None,
        "source": None,
        "destination": None,
        "protocol": [ "value" ],
        "source-port": [ "port", "protocol" ],
        "log":  None,
        "audit": None,
        "accept": None,
        "reject": None,
        "drop": None,
        "mark": [ "set" ],
        "limit": [ "value" ],
        "icmp-block-inversion": None,
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "zone": [ "name", "immutable", "target", "version" ],
        "masquerade": [ "enabled" ],
        "forward-port": [ "to-port", "to-addr" ],
        "rule": [ "family", "priority" ],
        "source": [ "address", "mac", "invert", "family", "ipset" ],
        "destination": [ "address", "invert", "ipset" ],
        "log": [ "prefix", "level" ],
        "reject": [ "type" ],
        "limit": ["burst"],
        }

    @staticmethod
    def index_of(element):
        for i, (el, dummy) in enumerate(Zone.IMPORT_EXPORT_STRUCTURE):
            if el == element:
                return i
        raise FirewallError(errors.UNKNOWN_ERROR, "index_of()")

    def __init__(self):
        super(Zone, self).__init__()
        self.version = ""
        self.short = ""
        self.description = ""
        self.UNUSED = False
        self.target = DEFAULT_ZONE_TARGET
        self.services = [ ]
        self.ports = [ ]
        self.protocols = [ ]
        self.icmp_blocks = [ ]
        self.forward = False
        self.masquerade = False
        self.forward_ports = [ ]
        self.source_ports = [ ]
        self.interfaces = [ ]
        self.sources = [ ]
        self.fw_config = None # to be able to check services and a icmp_blocks
        self.rules = [ ]
        self.rules_str = [ ]
        self.icmp_block_inversion = False
        self.combined = False
        self.applied = False

    def cleanup(self):
        self.version = ""
        self.short = ""
        self.description = ""
        self.UNUSED = False
        self.target = DEFAULT_ZONE_TARGET
        del self.services[:]
        del self.ports[:]
        del self.protocols[:]
        del self.icmp_blocks[:]
        self.forward = False
        self.masquerade = False
        del self.forward_ports[:]
        del self.source_ports[:]
        del self.interfaces[:]
        del self.sources[:]
        self.fw_config = None # to be able to check services and a icmp_blocks
        del self.rules[:]
        del self.rules_str[:]
        self.icmp_block_inversion = False
        self.combined = False
        self.applied = False

    def encode_strings(self):
        """ HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support."""
        self.version = u2b_if_py2(self.version)
        self.short = u2b_if_py2(self.short)
        self.description = u2b_if_py2(self.description)
        self.target = u2b_if_py2(self.target)
        self.services = [u2b_if_py2(s) for s in self.services]
        self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports]
        self.protocols = [u2b_if_py2(pr) for pr in self.protocols]
        self.icmp_blocks = [u2b_if_py2(i) for i in self.icmp_blocks]
        self.forward_ports = [(u2b_if_py2(p1),u2b_if_py2(p2),u2b_if_py2(p3),u2b_if_py2(p4)) for (p1,p2,p3,p4) in self.forward_ports]
        self.source_ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr)
                             in self.source_ports]
        self.interfaces = [u2b_if_py2(i) for i in self.interfaces]
        self.sources = [u2b_if_py2(s) for s in self.sources]
        self.rules = [u2b_if_py2(s) for s in self.rules]
        self.rules_str = [u2b_if_py2(s) for s in self.rules_str]

    def __setattr__(self, name, value):
        if name == "rules_str":
            self.rules = [rich.Rich_Rule(rule_str=s) for s in value]
            # must convert back to string to get the canonical string.
            super(Zone, self).__setattr__(name, [str(s) for s in self.rules])
        else:
            super(Zone, self).__setattr__(name, value)

    def export_config_dict(self):
        conf = super(Zone, self).export_config_dict()
        del conf["UNUSED"]
        return conf

    def _check_config(self, config, item, all_config):
        common_check_config(self, config, item, all_config)

        if item == "target":
            if config not in ZONE_TARGETS:
                raise FirewallError(errors.INVALID_TARGET, config)
        elif item == "interfaces":
            for interface in config:
                if not checkInterface(interface):
                    raise FirewallError(errors.INVALID_INTERFACE, interface)
                if self.fw_config:
                    for zone in self.fw_config.get_zones():
                        if zone == self.name:
                            continue
                        if interface in self.fw_config.get_zone(zone).interfaces:
                            raise FirewallError(errors.INVALID_INTERFACE,
                                    "interface '{}' already bound to zone '{}'".format(interface, zone))
        elif item == "sources":
            for source in config:
                if not checkIPnMask(source) and not checkIP6nMask(source) and \
                   not check_mac(source) and not source.startswith("ipset:"):
                    raise FirewallError(errors.INVALID_ADDR, source)
                if self.fw_config:
                    for zone in self.fw_config.get_zones():
                        if zone == self.name:
                            continue
                        if source in self.fw_config.get_zone(zone).sources:
                            raise FirewallError(errors.INVALID_ADDR,
                                    "source '{}' already bound to zone '{}'".format(source, zone))


    def check_name(self, name):
        super(Zone, self).check_name(name)
        if name.startswith('/'):
            raise FirewallError(errors.INVALID_NAME,
                                "'%s' can't start with '/'" % name)
        elif name.endswith('/'):
            raise FirewallError(errors.INVALID_NAME,
                                "'%s' can't end with '/'" % name)
        elif name.count('/') > 1:
            raise FirewallError(errors.INVALID_NAME,
                                "more than one '/' in '%s'" % name)
        else:
            if "/" in name:
                checked_name = name[:name.find('/')]
            else:
                checked_name = name
            if len(checked_name) > max_zone_name_len():
                raise FirewallError(errors.INVALID_NAME,
                                    "Zone of '%s' has %d chars, max is %d %s" % (
                                    name, len(checked_name),
                                    max_zone_name_len(),
                                    self.combined))
            if self.fw_config:
                if checked_name in self.fw_config.get_policy_objects():
                    raise FirewallError(errors.NAME_CONFLICT, "Zones can't have the same name as a policy.")

    def combine(self, zone):
        self.combined = True
        self.filename = None
        self.version = ""
        self.short = ""
        self.description = ""

        for interface in zone.interfaces:
            if interface not in self.interfaces:
                self.interfaces.append(interface)
        for source in zone.sources:
            if source not in self.sources:
                self.sources.append(source)
        for service in zone.services:
            if service not in self.services:
                self.services.append(service)
        for port in zone.ports:
            if port not in self.ports:
                self.ports.append(port)
        for proto in zone.protocols:
            if proto not in self.protocols:
                self.protocols.append(proto)
        for icmp in zone.icmp_blocks:
            if icmp not in self.icmp_blocks:
                self.icmp_blocks.append(icmp)
        if zone.forward:
            self.forward = True
        if zone.masquerade:
            self.masquerade = True
        for forward in zone.forward_ports:
            if forward not in self.forward_ports:
                self.forward_ports.append(forward)
        for port in zone.source_ports:
            if port not in self.source_ports:
                self.source_ports.append(port)
        for rule in zone.rules:
            self.rules.append(rule)
            self.rules_str.append(str(rule))
        if zone.icmp_block_inversion:
            self.icmp_block_inversion = True

# PARSER

class zone_ContentHandler(IO_Object_ContentHandler):
    def __init__(self, item):
        IO_Object_ContentHandler.__init__(self, item)
        self._rule = None
        self._rule_error = False
        self._limit_ok = None

    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        if self._rule_error:
            return

        self.item.parser_check_element_attrs(name, attrs)

        if common_startElement(self, name, attrs):
            return

        elif name == "zone":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'",
                            attrs["name"])
            if "version" in attrs:
                self.item.version = attrs["version"]
            if "immutable" in attrs:
                log.warning("Ignoring deprecated attribute immutable='%s'",
                            attrs["immutable"])
            if "target" in attrs:
                target = attrs["target"]
                if target not in ZONE_TARGETS:
                    raise FirewallError(errors.INVALID_TARGET, target)
                if target != "" and target != DEFAULT_ZONE_TARGET:
                    self.item.target = target

        elif name == "forward":
            if self.item.forward:
                log.warning("Forward already set, ignoring.")
            else:
                self.item.forward = True

        elif name == "interface":
            if self._rule:
                log.warning('Invalid rule: interface use in rule.')
                self._rule_error = True
                return
            # zone bound to interface
            if "name" not in attrs:
                log.warning('Invalid interface: Name missing.')
                self._rule_error = True
                return
            if attrs["name"] not in self.item.interfaces:
                self.item.interfaces.append(attrs["name"])
            else:
                log.warning("Interface '%s' already set, ignoring.",
                            attrs["name"])

        elif name == "source":
            if self._rule:
                if self._rule.source:
                    log.warning("Invalid rule: More than one source in rule '%s', ignoring.",
                                str(self._rule))
                    self._rule_error = True
                    return
                invert = False
                if "invert" in attrs and \
                        attrs["invert"].lower() in [ "yes", "true" ]:
                    invert = True
                addr = mac = ipset = None
                if "address" in attrs:
                    addr = attrs["address"]
                if "mac" in attrs:
                    mac = attrs["mac"]
                if "ipset" in attrs:
                    ipset = attrs["ipset"]
                self._rule.source = rich.Rich_Source(addr, mac, ipset,
                                                     invert=invert)
                return
            # zone bound to source
            if "address" not in attrs and "ipset" not in attrs:
                log.warning('Invalid source: No address no ipset.')
                return
            if "address" in attrs and "ipset" in attrs:
                log.warning('Invalid source: Address and ipset.')
                return
            if "family" in attrs:
                log.warning("Ignoring deprecated attribute family='%s'",
                            attrs["family"])
            if "invert" in attrs:
                log.warning('Invalid source: Invertion not allowed here.')
                return
            if "address" in attrs:
                if not checkIPnMask(attrs["address"]) and \
                   not checkIP6nMask(attrs["address"]) and \
                   not check_mac(attrs["address"]):
                    raise FirewallError(errors.INVALID_ADDR, attrs["address"])
            if "ipset" in attrs:
                entry = "ipset:%s" % attrs["ipset"]
                if entry not in self.item.sources:
                    self.item.sources.append(entry)
                else:
                    log.warning("Source '%s' already set, ignoring.",
                                attrs["address"])
            if "address" in attrs:
                entry = attrs["address"]
                if entry not in self.item.sources:
                    self.item.sources.append(entry)
                else:
                    log.warning("Source '%s' already set, ignoring.",
                                attrs["address"])

        elif name == "icmp-block-inversion":
            if self.item.icmp_block_inversion:
                log.warning("Icmp-Block-Inversion already set, ignoring.")
            else:
                self.item.icmp_block_inversion = True

        else:
            log.warning("Unknown XML element '%s'", name)
            return

    def endElement(self, name):
        IO_Object_ContentHandler.endElement(self, name)

        common_endElement(self, name)

def zone_reader(filename, path, no_check_name=False):
    zone = Zone()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    zone.name = filename[:-4]
    if not no_check_name:
        zone.check_name(zone.name)
    zone.filename = filename
    zone.path = path
    zone.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    zone.default = zone.builtin
    handler = zone_ContentHandler(zone)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_ZONE,
                                "not a valid zone file: %s" % \
                                msg.getException())
    del handler
    del parser
    if PY2:
        zone.encode_strings()
    return zone

def zone_writer(zone, path=None):
    _path = path if path else zone.path

    if zone.filename:
        name = "%s/%s" % (_path, zone.filename)
    else:
        name = "%s/%s.xml" % (_path, zone.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)

    dirpath = os.path.dirname(name)
    if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start zone element
    attrs = {}
    if zone.version and zone.version != "":
        attrs["version"] = zone.version
    if zone.target != DEFAULT_ZONE_TARGET:
        attrs["target"] = zone.target
    handler.startElement("zone", attrs)
    handler.ignorableWhitespace("\n")

    common_writer(zone, handler)

    # interfaces
    for interface in uniqify(zone.interfaces):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("interface", { "name": interface })
        handler.ignorableWhitespace("\n")

    # source
    for source in uniqify(zone.sources):
        handler.ignorableWhitespace("  ")
        if "ipset:" in source:
            handler.simpleElement("source", { "ipset": source[6:] })
        else:
            handler.simpleElement("source", { "address": source })
        handler.ignorableWhitespace("\n")

    # icmp-block-inversion
    if zone.icmp_block_inversion:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("icmp-block-inversion", { })
        handler.ignorableWhitespace("\n")

    # forward
    if zone.forward:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("forward", { })
        handler.ignorableWhitespace("\n")

    # end zone element
    handler.endElement("zone")
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
io/helper.py000064400000020263151731527120007013 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "Helper", "helper_reader", "helper_writer" ]

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.functions import u2b_if_py2
from firewall.core.io.io_object import PY2, IO_Object, \
    IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \
    check_tcpudp
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class Helper(IO_Object):
    IMPORT_EXPORT_STRUCTURE = (
        ( "version",  "" ),                   # s
        ( "short", "" ),                      # s
        ( "description", "" ),                # s
        ( "family", "", ),                    # s
        ( "module", "", ),                    # s
        ( "ports", [ ( "", "" ), ], ),        # a(ss)
        )
    DBUS_SIGNATURE = '(sssssa(ss))'
    ADDITIONAL_ALNUM_CHARS = [ "-", "." ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "short": None,
        "description": None,
        "helper": [ "module" ],
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "helper": [ "name", "version", "family" ],
        "port": [ "port", "protocol" ],
        }

    def __init__(self):
        super(Helper, self).__init__()
        self.version = ""
        self.short = ""
        self.description = ""
        self.module = ""
        self.family = ""
        self.ports = [ ]

    def cleanup(self):
        self.version = ""
        self.short = ""
        self.description = ""
        self.module = ""
        self.family = ""
        del self.ports[:]

    def encode_strings(self):
        """ HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support."""
        self.version = u2b_if_py2(self.version)
        self.short = u2b_if_py2(self.short)
        self.description = u2b_if_py2(self.description)
        self.module = u2b_if_py2(self.module)
        self.family = u2b_if_py2(self.family)
        self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports]

    def check_ipv(self, ipv):
        ipvs = [ 'ipv4', 'ipv6' ]
        if ipv not in ipvs:
            raise FirewallError(errors.INVALID_IPV,
                                "'%s' not in '%s'" % (ipv, ipvs))

    def _check_config(self, config, item, all_config):
        if item == "ports":
            for port in config:
                check_port(port[0])
                check_tcpudp(port[1])
        elif item == "module":
            if not config.startswith("nf_conntrack_"):
                raise FirewallError(
                    errors.INVALID_MODULE,
                    "'%s' does not start with 'nf_conntrack_'" % config)
            if len(config.replace("nf_conntrack_", "")) < 1:
                raise FirewallError(errors.INVALID_MODULE,
                                    "Module name '%s' too short" % config)

# PARSER

class helper_ContentHandler(IO_Object_ContentHandler):
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)
        if name == "helper":
            if "version" in attrs:
                self.item.version = attrs["version"]
            if "family" in attrs:
                self.item.check_ipv(attrs["family"])
                self.item.family = attrs["family"]
            if "module" in attrs:
                if not attrs["module"].startswith("nf_conntrack_"):
                    raise FirewallError(
                        errors.INVALID_MODULE,
                        "'%s' does not start with 'nf_conntrack_'" % \
                        attrs["module"])
                if len(attrs["module"].replace("nf_conntrack_", "")) < 1:
                    raise FirewallError(
                        errors.INVALID_MODULE,
                        "Module name '%s' too short" % attrs["module"])
                self.item.module = attrs["module"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "port":
            check_port(attrs["port"])
            check_tcpudp(attrs["protocol"])
            entry = (attrs["port"], attrs["protocol"])
            if entry not in self.item.ports:
                self.item.ports.append(entry)
            else:
                log.warning("Port '%s/%s' already set, ignoring.",
                            attrs["port"], attrs["protocol"])

def helper_reader(filename, path):
    helper = Helper()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    helper.name = filename[:-4]
    helper.check_name(helper.name)
    helper.filename = filename
    helper.path = path
    helper.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    helper.default = helper.builtin
    handler = helper_ContentHandler(helper)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_HELPER,
                                "not a valid helper file: %s" % \
                                msg.getException())
    del handler
    del parser
    if PY2:
        helper.encode_strings()
    return helper

def helper_writer(helper, path=None):
    _path = path if path else helper.path

    if helper.filename:
        name = "%s/%s" % (_path, helper.filename)
    else:
        name = "%s/%s.xml" % (_path, helper.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)

    dirpath = os.path.dirname(name)
    if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start helper element
    attrs = {}
    attrs["module"] = helper.module
    if helper.version and helper.version != "":
        attrs["version"] = helper.version
    if helper.family and helper.family != "":
        attrs["family"] = helper.family
    handler.startElement("helper", attrs)
    handler.ignorableWhitespace("\n")

    # short
    if helper.short and helper.short != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("short", { })
        handler.characters(helper.short)
        handler.endElement("short")
        handler.ignorableWhitespace("\n")

    # description
    if helper.description and helper.description != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("description", { })
        handler.characters(helper.description)
        handler.endElement("description")
        handler.ignorableWhitespace("\n")

    # ports
    for port in helper.ports:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("port", { "port": port[0], "protocol": port[1] })
        handler.ignorableWhitespace("\n")

    # end helper element
    handler.endElement('helper')
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
io/ipset.py000064400000051205151731527120006660 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2015-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""ipset io XML handler, reader, writer"""

__all__ = [ "IPSet", "ipset_reader", "ipset_writer" ]

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.functions import checkIP, checkIP6, checkIPnMask, \
    checkIP6nMask, u2b_if_py2, check_mac, check_port, checkInterface, \
    checkProtocol
from firewall.core.io.io_object import PY2, IO_Object, \
    IO_Object_ContentHandler, IO_Object_XMLGenerator
from firewall.core.ipset import IPSET_TYPES, IPSET_CREATE_OPTIONS
from firewall.core.icmp import check_icmp_name, check_icmp_type, \
    check_icmpv6_name, check_icmpv6_type
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class IPSet(IO_Object):
    IMPORT_EXPORT_STRUCTURE = (
        ( "version",  "" ),              # s
        ( "short", "" ),                 # s
        ( "description", "" ),           # s
        ( "type", "" ),                  # s
        ( "options", { "": "", }, ),     # a{ss}
        ( "entries", [ "" ], ),          # as
    )
    DBUS_SIGNATURE = '(ssssa{ss}as)'
    ADDITIONAL_ALNUM_CHARS = [ "_", "-", ":", "." ]
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "short": None,
        "description": None,
        "ipset": [ "type" ],
        "option": [ "name" ],
        "entry": None,
    }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        "ipset": [ "version" ],
        "option": [ "value" ],
    }

    def __init__(self):
        super(IPSet, self).__init__()
        self.version = ""
        self.short = ""
        self.description = ""
        self.type = ""
        self.entries = [ ]
        self.options = { }
        self.applied = False

    def cleanup(self):
        self.version = ""
        self.short = ""
        self.description = ""
        self.type = ""
        del self.entries[:]
        self.options.clear()
        self.applied = False

    def encode_strings(self):
        """ HACK. I haven't been able to make sax parser return
            strings encoded (because of python 2) instead of in unicode.
            Get rid of it once we throw out python 2 support."""
        self.version = u2b_if_py2(self.version)
        self.short = u2b_if_py2(self.short)
        self.description = u2b_if_py2(self.description)
        self.type = u2b_if_py2(self.type)
        self.options = { u2b_if_py2(k):u2b_if_py2(v)
                         for k, v in self.options.items() }
        self.entries = [ u2b_if_py2(e) for e in self.entries ]

    @staticmethod
    def check_entry(entry, options, ipset_type):
        family = "ipv4"
        if "family" in options:
            if options["family"] == "inet6":
                family = "ipv6"

        if not ipset_type.startswith("hash:"):
            raise FirewallError(errors.INVALID_IPSET,
                                "ipset type '%s' not usable" % ipset_type)
        flags = ipset_type[5:].split(",")
        items = entry.split(",")

        if len(flags) != len(items) or len(flags) < 1:
            raise FirewallError(
                errors.INVALID_ENTRY,
                "entry '%s' does not match ipset type '%s'" % \
                (entry, ipset_type))

        for i in range(len(flags)):
            flag = flags[i]
            item = items[i]

            if flag == "ip":
                if "-" in item and family == "ipv4":
                    # IP ranges only with plain IPs, no masks
                    if i > 1:
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address '%s' in '%s'[%d]" % \
                            (item, entry, i))
                    splits = item.split("-")
                    if len(splits) != 2:
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address range '%s' in '%s' for %s (%s)" % \
                            (item, entry, ipset_type, family))
                    for _split in splits:
                        if (family == "ipv4" and not checkIP(_split)) or \
                           (family == "ipv6" and not checkIP6(_split)):
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid address '%s' in '%s' for %s (%s)" % \
                                (_split, entry, ipset_type, family))
                else:
                    # IPs with mask only allowed in the first
                    # position of the type
                    if family == "ipv4":
                        if item == "0.0.0.0":
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid address '%s' in '%s' for %s (%s)" % \
                                (item, entry, ipset_type, family))
                        if i == 0:
                            ip_check = checkIPnMask
                        else:
                            ip_check = checkIP
                    else:
                        ip_check = checkIP6
                    if not ip_check(item):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address '%s' in '%s' for %s (%s)" % \
                            (item, entry, ipset_type, family))
            elif flag == "net":
                if "-" in item:
                    # IP ranges only with plain IPs, no masks
                    splits = item.split("-")
                    if len(splits) != 2:
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address range '%s' in '%s' for %s (%s)" % \
                            (item, entry, ipset_type, family))
                    # First part can only be a plain IP
                    if (family == "ipv4" and not checkIP(splits[0])) or \
                       (family == "ipv6" and not checkIP6(splits[0])):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address '%s' in '%s' for %s (%s)" % \
                            (splits[0], entry, ipset_type, family))
                    # Second part can also have a mask
                    if (family == "ipv4" and not checkIPnMask(splits[1])) or \
                       (family == "ipv6" and not checkIP6nMask(splits[1])):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address '%s' in '%s' for %s (%s)" % \
                            (splits[1], entry, ipset_type, family))
                else:
                    # IPs with mask allowed in all positions, but no /0
                    if item.endswith("/0"):
                        if not (family == "ipv6" and i == 0 and
                                ipset_type == "hash:net,iface"):
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid address '%s' in '%s' for %s (%s)" % \
                                (item, entry, ipset_type, family))
                    if (family == "ipv4" and not checkIPnMask(item)) or \
                       (family == "ipv6" and not checkIP6nMask(item)):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid address '%s' in '%s' for %s (%s)" % \
                            (item, entry, ipset_type, family))
            elif flag == "mac":
                # ipset does not allow to add 00:00:00:00:00:00
                if not check_mac(item) or item == "00:00:00:00:00:00":
                    raise FirewallError(
                        errors.INVALID_ENTRY,
                        "invalid mac address '%s' in '%s'" % (item, entry))
            elif flag == "port":
                if ":" in item:
                    splits = item.split(":")
                    if len(splits) != 2:
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid port '%s'" % (item))
                    if splits[0] == "icmp":
                        if family != "ipv4":
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid protocol for family '%s' in '%s'" % \
                                (family, entry))
                        if not check_icmp_name(splits[1]) and not \
                           check_icmp_type(splits[1]):
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid icmp type '%s' in '%s'" % \
                                (splits[1], entry))
                    elif splits[0] in [ "icmpv6", "ipv6-icmp" ]:
                        if family != "ipv6":
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid protocol for family '%s' in '%s'" % \
                                (family, entry))
                        if not check_icmpv6_name(splits[1]) and not \
                           check_icmpv6_type(splits[1]):
                            raise FirewallError(
                                errors.INVALID_ENTRY,
                                "invalid icmpv6 type '%s' in '%s'" % \
                                (splits[1], entry))
                    elif splits[0] not in [ "tcp", "sctp", "udp", "udplite" ] \
                       and not checkProtocol(splits[0]):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid protocol '%s' in '%s'" % (splits[0],
                                                               entry))
                    elif not check_port(splits[1]):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid port '%s'in '%s'" % (splits[1], entry))
                else:
                    if not check_port(item):
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid port '%s' in '%s'" % (item, entry))
            elif flag == "mark":
                if item.startswith("0x"):
                    try:
                        int_val = int(item, 16)
                    except ValueError:
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid mark '%s' in '%s'" % (item, entry))
                else:
                    try:
                        int_val = int(item)
                    except ValueError:
                        raise FirewallError(
                            errors.INVALID_ENTRY,
                            "invalid mark '%s' in '%s'" % (item, entry))
                if int_val < 0 or int_val > 4294967295:
                    raise FirewallError(
                        errors.INVALID_ENTRY,
                        "invalid mark '%s' in '%s'" % (item, entry))
            elif flag == "iface":
                if not checkInterface(item) or len(item) > 15:
                    raise FirewallError(
                        errors.INVALID_ENTRY,
                        "invalid interface '%s' in '%s'" % (item, entry))
            else:
                raise FirewallError(errors.INVALID_IPSET,
                                    "ipset type '%s' not usable" % ipset_type)

    def _check_config(self, config, item, all_config):
        if item == "type":
            if config not in IPSET_TYPES:
                raise FirewallError(errors.INVALID_TYPE,
                                    "'%s' is not valid ipset type" % config)
        if item == "options":
            for key in config.keys():
                if key not in IPSET_CREATE_OPTIONS:
                    raise FirewallError(errors.INVALID_IPSET,
                                        "ipset invalid option '%s'" % key)
                if key in [ "timeout", "hashsize", "maxelem" ]:
                    try:
                        int_value = int(config[key])
                    except ValueError:
                        raise FirewallError(
                            errors.INVALID_VALUE,
                            "Option '%s': Value '%s' is not an integer" % \
                            (key, config[key]))
                    if int_value < 0:
                        raise FirewallError(
                            errors.INVALID_VALUE,
                            "Option '%s': Value '%s' is negative" % \
                            (key, config[key]))
                elif key == "family" and \
                     config[key] not in [ "inet", "inet6" ]:
                    raise FirewallError(errors.INVALID_FAMILY, config[key])

    def import_config(self, config):
        if "timeout" in config[4] and config[4]["timeout"] != "0":
            if len(config[5]) != 0:
                raise FirewallError(errors.IPSET_WITH_TIMEOUT)
        for entry in config[5]:
            IPSet.check_entry(entry, config[4], config[3])
        super(IPSet, self).import_config(config)

# PARSER

class ipset_ContentHandler(IO_Object_ContentHandler):
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)
        if name == "ipset":
            if "type" in attrs:
                if attrs["type"] not in IPSET_TYPES:
                    raise FirewallError(errors.INVALID_TYPE, "%s" % attrs["type"])
                self.item.type = attrs["type"]
            if "version" in attrs:
                self.item.version = attrs["version"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "option":
            value = ""
            if "value" in attrs:
                value = attrs["value"]

            if attrs["name"] not in \
               [ "family", "timeout", "hashsize", "maxelem" ]:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Unknown option '%s'" % attrs["name"])
            if self.item.type == "hash:mac" and attrs["name"] in [ "family" ]:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Unsupported option '%s' for type '%s'" % \
                    (attrs["name"], self.item.type))
            if attrs["name"] in [ "family", "timeout", "hashsize", "maxelem" ] \
               and not value:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Missing mandatory value of option '%s'" % attrs["name"])
            if attrs["name"] in [ "timeout", "hashsize", "maxelem" ]:
                try:
                    int_value = int(value)
                except ValueError:
                    raise FirewallError(
                        errors.INVALID_VALUE,
                        "Option '%s': Value '%s' is not an integer" % \
                        (attrs["name"], value))
                if int_value < 0:
                    raise FirewallError(
                        errors.INVALID_VALUE,
                        "Option '%s': Value '%s' is negative" % \
                        (attrs["name"], value))
            if attrs["name"] == "family" and value not in [ "inet", "inet6" ]:
                raise FirewallError(errors.INVALID_FAMILY, value)
            if attrs["name"] not in self.item.options:
                self.item.options[attrs["name"]] = value
            else:
                log.warning("Option %s already set, ignoring.", attrs["name"])
        # nothing to do for entry and entries here

    def endElement(self, name):
        IO_Object_ContentHandler.endElement(self, name)
        if name == "entry":
            self.item.entries.append(self._element)

def ipset_reader(filename, path):
    ipset = IPSet()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    ipset.name = filename[:-4]
    ipset.check_name(ipset.name)
    ipset.filename = filename
    ipset.path = path
    ipset.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    ipset.default = ipset.builtin
    handler = ipset_ContentHandler(ipset)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_IPSET,
                                "not a valid ipset file: %s" % \
                                msg.getException())
    del handler
    del parser
    if "timeout" in ipset.options and ipset.options["timeout"] != "0" and \
       len(ipset.entries) > 0:
        # no entries visible for ipsets with timeout
        log.warning("ipset '%s': timeout option is set, entries are ignored",
                    ipset.name)
        del ipset.entries[:]
    i = 0
    entries_set = set()
    while i < len(ipset.entries):
        if ipset.entries[i] in entries_set:
            log.warning("Entry %s already set, ignoring.", ipset.entries[i])
            ipset.entries.pop(i)
        else:
            try:
                ipset.check_entry(ipset.entries[i], ipset.options, ipset.type)
            except FirewallError as e:
                log.warning("%s, ignoring.", e)
                ipset.entries.pop(i)
            else:
                entries_set.add(ipset.entries[i])
                i += 1
    del entries_set
    if PY2:
        ipset.encode_strings()

    return ipset

def ipset_writer(ipset, path=None):
    _path = path if path else ipset.path

    if ipset.filename:
        name = "%s/%s" % (_path, ipset.filename)
    else:
        name = "%s/%s.xml" % (_path, ipset.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)

    dirpath = os.path.dirname(name)
    if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start ipset element
    attrs = { "type": ipset.type }
    if ipset.version and ipset.version != "":
        attrs["version"] = ipset.version
    handler.startElement("ipset", attrs)
    handler.ignorableWhitespace("\n")

    # short
    if ipset.short and ipset.short != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("short", { })
        handler.characters(ipset.short)
        handler.endElement("short")
        handler.ignorableWhitespace("\n")

    # description
    if ipset.description and ipset.description != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("description", { })
        handler.characters(ipset.description)
        handler.endElement("description")
        handler.ignorableWhitespace("\n")

    # options
    for key,value in ipset.options.items():
        handler.ignorableWhitespace("  ")
        if value != "":
            handler.simpleElement("option", { "name": key, "value": value })
        else:
            handler.simpleElement("option", { "name": key })
        handler.ignorableWhitespace("\n")

    # entries
    for entry in ipset.entries:
        handler.ignorableWhitespace("  ")
        handler.startElement("entry", { })
        handler.characters(entry)
        handler.endElement("entry")
        handler.ignorableWhitespace("\n")

    # end ipset element
    handler.endElement('ipset')
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
io/direct.py000064400000036740151731527130007016 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import xml.sax as sax
import os
import io
import shutil

from firewall import config
from firewall.fw_types import LastUpdatedOrderedDict
from firewall.functions import splitArgs, joinArgs, u2b_if_py2
from firewall.core.io.io_object import IO_Object, IO_Object_ContentHandler, \
    IO_Object_XMLGenerator
from firewall.core.logger import log
from firewall.core import ipXtables
from firewall.core import ebtables
from firewall import errors
from firewall.errors import FirewallError


class direct_ContentHandler(IO_Object_ContentHandler):
    def __init__(self, item):
        IO_Object_ContentHandler.__init__(self, item)
        self.direct = False

    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)

        if name == "direct":
            if self.direct:
                raise FirewallError(errors.PARSE_ERROR,
                                    "More than one direct tag.")
            self.direct = True

        elif name == "chain":
            if not self.direct:
                log.error("Parse Error: chain outside of direct")
                return
            ipv = attrs["ipv"]
            table = attrs["table"]
            chain = attrs["chain"]
            self.item.add_chain(u2b_if_py2(ipv), u2b_if_py2(table),
                                u2b_if_py2(chain))

        elif name == "rule":
            if not self.direct:
                log.error("Parse Error: rule outside of direct")
                return
            ipv = attrs["ipv"]
            if ipv not in [ "ipv4", "ipv6", "eb" ]:
                raise FirewallError(errors.INVALID_IPV,
                                    "'%s' not from {'ipv4'|'ipv6'|'eb'}" % ipv)
            table = attrs["table"]
            chain = attrs["chain"]
            try:
                priority = int(attrs["priority"])
            except ValueError:
                log.error("Parse Error: %s is not a valid priority" %
                          attrs["priority"])
                return
            self._rule = [ u2b_if_py2(ipv), u2b_if_py2(table),
                           u2b_if_py2(chain), priority ]

        elif name == "passthrough":
            if not self.direct:
                log.error("Parse Error: command outside of direct")
                return
            ipv = attrs["ipv"]
            self._passthrough = [ u2b_if_py2(ipv) ]

        else:
            log.error('Unknown XML element %s' % name)
            return

    def endElement(self, name):
        IO_Object_ContentHandler.endElement(self, name)

        if name == "rule":
            if self._element:
                # add arguments
                self._rule.append([ u2b_if_py2(x)
                                    for x in splitArgs(self._element) ])
                self.item.add_rule(*self._rule)
            else:
                log.error("Error: rule does not have any arguments, ignoring.")
            self._rule = None
        elif name == "passthrough":
            if self._element:
                # add arguments
                self._passthrough.append([ u2b_if_py2(x)
                                           for x in splitArgs(self._element) ])
                self.item.add_passthrough(*self._passthrough)
            else:
                log.error("Error: passthrough does not have any arguments, " +
                          "ignoring.")
            self._passthrough = None

class Direct(IO_Object):
    """ Direct class """

    IMPORT_EXPORT_STRUCTURE = (
        # chain: [ ipv, table, [ chain ] ]
        ( "chains", [ ( "", "", "" ), ], ),                   # a(sss)
        # rule: [ ipv, table, chain, [ priority, [ arg ] ] ]
        ( "rules", [ ( "", "", "", 0, [ "" ] ), ], ),         # a(sssias)
        # passthrough: [ ipv, [ [ arg ] ] ]
        ( "passthroughs", [ ( "", [ "" ]), ], ),              # a(sas)
        )
    DBUS_SIGNATURE = '(a(sss)a(sssias)a(sas))'
    PARSER_REQUIRED_ELEMENT_ATTRS = {
        "direct": None,
        "chain": [ "ipv", "table", "chain" ],
        "rule": [ "ipv", "table", "chain", "priority" ],
        "passthrough": [ "ipv" ]
        }
    PARSER_OPTIONAL_ELEMENT_ATTRS = {
        }

    def __init__(self, filename):
        super(Direct, self).__init__()
        self.filename = filename
        self.chains = LastUpdatedOrderedDict()
        self.rules = LastUpdatedOrderedDict()
        self.passthroughs = LastUpdatedOrderedDict()

    def _check_config(self, conf, item, all_conf):
        pass
        # check arg lists

    def export_config(self):
        ret = [ ]
        x = [ ]
        for key in self.chains:
            for chain in self.chains[key]:
                x.append(tuple(list(key) + list([chain])))
        ret.append(x)
        x = [ ]
        for key in self.rules:
            for rule in self.rules[key]:
                x.append(tuple((key[0], key[1], key[2], rule[0],
                                list(rule[1]))))
        ret.append(x)
        x = [ ]
        for key in self.passthroughs:
            for rule in self.passthroughs[key]:
                x.append(tuple((key, list(rule))))
        ret.append(x)
        return tuple(ret)

    def import_config(self, conf):
        self.cleanup()
        self.check_config(conf)
        for i,(element,dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
            if element == "chains":
                for x in conf[i]:
                    self.add_chain(*x)
            if element == "rules":
                for x in conf[i]:
                    self.add_rule(*x)
            if element == "passthroughs":
                for x in conf[i]:
                    self.add_passthrough(*x)

    def cleanup(self):
        self.chains.clear()
        self.rules.clear()
        self.passthroughs.clear()

    def output(self):
        print("chains")
        for key in self.chains:
            print("  (%s, %s): %s" % (key[0], key[1],
                                      ",".join(self.chains[key])))
        print("rules")
        for key in self.rules:
            print("  (%s, %s, %s):" % (key[0], key[1], key[2]))
            for (priority,args) in self.rules[key]:
                print("    (%d, ('%s'))" % (priority, "','".join(args)))
        print("passthroughs")
        for key in self.passthroughs:
            print("  %s:" % (key))
            for args in self.passthroughs[key]:
                print("    ('%s')" % ("','".join(args)))

    def _check_ipv(self, ipv):
        ipvs = ['ipv4', 'ipv6', 'eb']
        if ipv not in ipvs:
            raise FirewallError(errors.INVALID_IPV,
                                "'%s' not in '%s'" % (ipv, ipvs))

    def _check_ipv_table(self, ipv, table):
        self._check_ipv(ipv)

        tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in ['ipv4', 'ipv6'] \
                                         else ebtables.BUILT_IN_CHAINS.keys()
        if table not in tables:
            raise FirewallError(errors.INVALID_TABLE,
                                "'%s' not in '%s'" % (table, tables))

    # chains

    def add_chain(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        key = (ipv, table)
        if key not in self.chains:
            self.chains[key] = [ ]
        if chain not in self.chains[key]:
            self.chains[key].append(chain)
        else:
            log.warning("Chain '%s' for table '%s' with ipv '%s' " % \
                        (chain, table, ipv) + "already in list, ignoring")

    def remove_chain(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        key = (ipv, table)
        if key in self.chains and chain in self.chains[key]:
            self.chains[key].remove(chain)
            if len(self.chains[key]) == 0:
                del self.chains[key]
        else:
            raise ValueError( \
                "Chain '%s' with table '%s' with ipv '%s' not in list" % \
                (chain, table, ipv))

    def query_chain(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        key = (ipv, table)
        return (key in self.chains and chain in self.chains[key])

    def get_chains(self, ipv, table):
        self._check_ipv_table(ipv, table)
        key = (ipv, table)
        if key in self.chains:
            return self.chains[key]
        else:
            raise ValueError("No chains for table '%s' with ipv '%s'" % \
                             (table, ipv))

    def get_all_chains(self):
        return self.chains

    # rules

    def add_rule(self, ipv, table, chain, priority, args):
        self._check_ipv_table(ipv, table)
        key = (ipv, table, chain)
        if key not in self.rules:
            self.rules[key] = LastUpdatedOrderedDict()
        value = (priority, tuple(args))
        if value not in self.rules[key]:
            self.rules[key][value] = priority
        else:
            log.warning("Rule '%s' for table '%s' and chain '%s' " % \
                        ("',".join(args), table, chain) +
                        "with ipv '%s' and priority %d " % (ipv, priority) +
                        "already in list, ignoring")

    def remove_rule(self, ipv, table, chain, priority, args):
        self._check_ipv_table(ipv, table)
        key = (ipv, table, chain)
        value = (priority, tuple(args))
        if key in self.rules and value in self.rules[key]:
            del self.rules[key][value]
            if len(self.rules[key]) == 0:
                del self.rules[key]
        else:
            raise ValueError("Rule '%s' for table '%s' and chain '%s' " % \
                ("',".join(args), table, chain) + \
                "with ipv '%s' and priority %d not in list" % (ipv, priority))

    def remove_rules(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        key = (ipv, table, chain)
        if key in self.rules:
            for value in self.rules[key].keys():
                del self.rules[key][value]
            if len(self.rules[key]) == 0:
                del self.rules[key]

    def query_rule(self, ipv, table, chain, priority, args):
        self._check_ipv_table(ipv, table)
        key = (ipv, table, chain)
        value = (priority, tuple(args))
        return (key in self.rules and value in self.rules[key])

    def get_rules(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        key = (ipv, table, chain)
        if key in self.rules:
            return self.rules[key]
        else:
            raise ValueError("No rules for table '%s' and chain '%s' " %\
                             (table, chain) + "with ipv '%s'" % (ipv))

    def get_all_rules(self):
        return self.rules

#    # passthrough
#
    def add_passthrough(self, ipv, args):
        self._check_ipv(ipv)
        if ipv not in self.passthroughs:
            self.passthroughs[ipv] = [ ]
        if args not in self.passthroughs[ipv]:
            self.passthroughs[ipv].append(args)
        else:
            log.warning("Passthrough '%s' for ipv '%s'" % \
                        ("',".join(args), ipv) + "already in list, ignoring")

    def remove_passthrough(self, ipv, args):
        self._check_ipv(ipv)
        if ipv in self.passthroughs and args in self.passthroughs[ipv]:
            self.passthroughs[ipv].remove(args)
            if len(self.passthroughs[ipv]) == 0:
                del self.passthroughs[ipv]
        else:
            raise ValueError("Passthrough '%s' for ipv '%s'" % \
                             ("',".join(args), ipv) + "not in list")

    def query_passthrough(self, ipv, args):
        self._check_ipv(ipv)
        return ipv in self.passthroughs and args in self.passthroughs[ipv]

    def get_passthroughs(self, ipv):
        self._check_ipv(ipv)
        if ipv in self.passthroughs:
            return self.passthroughs[ipv]
        else:
            raise ValueError("No passthroughs for ipv '%s'" % (ipv))

    def get_all_passthroughs(self):
        return self.passthroughs

    # read

    def read(self):
        self.cleanup()
        if not self.filename.endswith(".xml"):
            raise FirewallError(errors.INVALID_NAME,
                                "'%s' is missing .xml suffix" % self.filename)
        handler = direct_ContentHandler(self)
        parser = sax.make_parser()
        parser.setContentHandler(handler)
        with open(self.filename, "rb") as f:
            source = sax.InputSource(None)
            source.setByteStream(f)
            try:
                parser.parse(source)
            except sax.SAXParseException as msg:
                raise FirewallError(errors.INVALID_TYPE,
                                    "Not a valid file: %s" % \
                                    msg.getException())

    def write(self):
        if os.path.exists(self.filename):
            try:
                shutil.copy2(self.filename, "%s.old" % self.filename)
            except Exception as msg:
                raise IOError("Backup of '%s' failed: %s" % (self.filename, msg))

        if not os.path.exists(config.ETC_FIREWALLD):
            os.mkdir(config.ETC_FIREWALLD, 0o750)

        f = io.open(self.filename, mode='wt', encoding='UTF-8')
        handler = IO_Object_XMLGenerator(f)
        handler.startDocument()

        # start whitelist element
        handler.startElement("direct", { })
        handler.ignorableWhitespace("\n")

        # chains
        for key in self.chains:
            (ipv, table) = key
            for chain in self.chains[key]:
                handler.ignorableWhitespace("  ")
                handler.simpleElement("chain", { "ipv": ipv, "table": table,
                                                 "chain": chain })
                handler.ignorableWhitespace("\n")

        # rules
        for key in self.rules:
            (ipv, table, chain) = key
            for (priority, args) in self.rules[key]:
                if len(args) < 1:
                    continue
                handler.ignorableWhitespace("  ")
                handler.startElement("rule", { "ipv": ipv, "table": table,
                                               "chain": chain,
                                               "priority": "%d" % priority })
                handler.ignorableWhitespace(sax.saxutils.escape(joinArgs(args)))
                handler.endElement("rule")
                handler.ignorableWhitespace("\n")

        # passthroughs
        for ipv in self.passthroughs:
            for args in self.passthroughs[ipv]:
                if len(args) < 1:
                    continue
                handler.ignorableWhitespace("  ")
                handler.startElement("passthrough", { "ipv": ipv })
                handler.ignorableWhitespace(sax.saxutils.escape(joinArgs(args)))
                handler.endElement("passthrough")
                handler.ignorableWhitespace("\n")

        # end zone element
        handler.endElement("direct")
        handler.ignorableWhitespace("\n")
        handler.endDocument()
        f.close()
        del handler
ebtables.py000064400000022256151731527130006713 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "ebtables" ]

import os.path
from firewall.core.prog import runProg
from firewall.core.logger import log
from firewall.functions import tempFile, readfile, splitArgs
from firewall.config import COMMANDS
from firewall.core import ipXtables # some common stuff lives there
from firewall.errors import FirewallError, INVALID_IPV
import string

BUILT_IN_CHAINS = {
    "broute": [ "BROUTING" ],
    "nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ],
    "filter": [ "INPUT", "OUTPUT", "FORWARD" ],
}

DEFAULT_RULES = { }
LOG_RULES = { }
OUR_CHAINS = {}  # chains created by firewalld

for table in BUILT_IN_CHAINS.keys():
    DEFAULT_RULES[table] = [ ]
    OUR_CHAINS[table] = set()
    for chain in BUILT_IN_CHAINS[table]:
        DEFAULT_RULES[table].append("-N %s_direct" % chain)
        DEFAULT_RULES[table].append("-I %s 1 -j %s_direct" % (chain, chain))
        DEFAULT_RULES[table].append("-I %s_direct 1 -j RETURN" % chain)
        OUR_CHAINS[table].add("%s_direct" % chain)

class ebtables(object):
    ipv = "eb"
    name = "ebtables"
    policies_supported = False # ebtables only supported with direct interface

    def __init__(self):
        self._command = COMMANDS[self.ipv]
        self._restore_command = COMMANDS["%s-restore" % self.ipv]
        self.restore_noflush_option = self._detect_restore_noflush_option()
        self.concurrent_option = self._detect_concurrent_option()
        self.fill_exists()
        self.available_tables = []

    def fill_exists(self):
        self.command_exists = os.path.exists(self._command)
        self.restore_command_exists = os.path.exists(self._restore_command)

    def _detect_concurrent_option(self):
        # Do not change any rules, just try to use the --concurrent option
        # with -L
        concurrent_option = ""
        ret = runProg(self._command, ["--concurrent", "-L"])
        if ret[0] == 0:
            concurrent_option = "--concurrent"  # concurrent for ebtables lock

        return concurrent_option

    def _detect_restore_noflush_option(self):
        # Do not change any rules, just try to use the restore command
        # with --noflush
        rules = [ ]
        try:
            self.set_rules(rules, "off")
        except ValueError:
            return False
        return True

    def __run(self, args):
        # convert to string list
        _args = [ ]
        if self.concurrent_option and self.concurrent_option not in args:
            _args.append(self.concurrent_option)
        _args += ["%s" % item for item in args]
        log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args))
        (status, ret) = runProg(self._command, _args)
        if status != 0:
            raise ValueError("'%s %s' failed: %s" % (self._command,
                                                     " ".join(args), ret))
        return ret

    def _rule_validate(self, rule):
        for str in ["%%REJECT%%", "%%ICMP%%", "%%LOGTYPE%%"]:
            if str in rule:
                raise FirewallError(INVALID_IPV,
                        "'%s' invalid for ebtables" % str)

    def is_chain_builtin(self, ipv, table, chain):
        return table in BUILT_IN_CHAINS and \
               chain in BUILT_IN_CHAINS[table]

    def build_chain_rules(self, add, table, chain):
        rules = []

        if add:
            rules.append([ "-t", table, "-N", chain ])
            rules.append([ "-t", table, "-I", chain, "1", "-j", "RETURN" ])
        else:
            rules.append([ "-t", table, "-X", chain ])

        return rules

    def build_rule(self, add, table, chain, index, args):
        rule = [ "-t", table ]
        if add:
            rule += [ "-I", chain, str(index) ]
        else:
            rule += [ "-D", chain ]
        rule += args
        return rule

    def reverse_rule(self, args):
        return ipXtables.common_reverse_rule(args)

    def check_passthrough(self, args):
        ipXtables.common_check_passthrough(args)

    def reverse_passthrough(self, args):
        return ipXtables.common_reverse_passthrough(args)

    def set_rules(self, rules, log_denied):
        temp_file = tempFile()

        table = "filter"
        table_rules = { }
        for _rule in rules:
            rule = _rule[:]

            self._rule_validate(rule)

            # get table form rule
            for opt in [ "-t", "--table" ]:
                try:
                    i = rule.index(opt)
                except ValueError:
                    pass
                else:
                    if len(rule) >= i+1:
                        rule.pop(i)
                        table = rule.pop(i)

            # we can not use joinArgs here, because it would use "'" instead
            # of '"' for the start and end of the string, this breaks
            # iptables-restore
            for i in range(len(rule)):
                for c in string.whitespace:
                    if c in rule[i] and not (rule[i].startswith('"') and
                                             rule[i].endswith('"')):
                        rule[i] = '"%s"' % rule[i]

            table_rules.setdefault(table, []).append(rule)

        for table in table_rules:
            temp_file.write("*%s\n" % table)
            for rule in table_rules[table]:
                temp_file.write(" ".join(rule) + "\n")

        temp_file.close()

        stat = os.stat(temp_file.name)
        log.debug2("%s: %s %s", self.__class__, self._restore_command,
                   "%s: %d" % (temp_file.name, stat.st_size))
        args = [ ]
        args.append("--noflush")

        (status, ret) = runProg(self._restore_command, args,
                                stdin=temp_file.name)

        if log.getDebugLogLevel() > 2:
            lines = readfile(temp_file.name)
            if lines is not None:
                i = 1
                for line in lines:
                    log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0)
                    if not line.endswith("\n"):
                        log.debug3("", nofmt=1)
                    i += 1

        os.unlink(temp_file.name)

        if status != 0:
            raise ValueError("'%s %s' failed: %s" % (self._restore_command,
                                                     " ".join(args), ret))

    def set_rule(self, rule, log_denied):
        self._rule_validate(rule)
        return self.__run(rule)

    def get_available_tables(self, table=None):
        ret = []
        tables = [ table ] if table else BUILT_IN_CHAINS.keys()
        for table in tables:
            if table in self.available_tables:
                ret.append(table)
            else:
                try:
                    self.__run(["-t", table, "-L"])
                    self.available_tables.append(table)
                    ret.append(table)
                except ValueError:
                    log.debug1("ebtables table '%s' does not exist." % table)

        return ret

    def get_zone_table_chains(self, table):
        return {}

    def build_flush_rules(self):
        rules = []
        for table in BUILT_IN_CHAINS.keys():
            if table not in self.get_available_tables():
                continue
            # Flush firewall rules: -F
            # Delete firewall chains: -X
            # Set counter to zero: -Z
            for flag in [ "-F", "-X", "-Z" ]:
                rules.append(["-t", table, flag])
        return rules

    def build_set_policy_rules(self, policy):
        rules = []
        _policy = "DROP" if policy == "PANIC" else policy
        for table in BUILT_IN_CHAINS.keys():
            if table not in self.get_available_tables():
                continue
            for chain in BUILT_IN_CHAINS[table]:
                rules.append(["-t", table, "-P", chain, _policy])
        return rules

    def build_default_tables(self):
        # nothing to do, they always exist
        return []

    def build_default_rules(self, log_denied="off"):
        default_rules = []
        for table in DEFAULT_RULES:
            if table not in self.get_available_tables():
                continue
            _default_rules = DEFAULT_RULES[table][:]
            if log_denied != "off" and table in LOG_RULES:
                _default_rules.extend(LOG_RULES[table])
            prefix = [ "-t", table ]
            for rule in _default_rules:
                if type(rule) == list:
                    default_rules.append(prefix + rule)
                else:
                    default_rules.append(prefix + splitArgs(rule))
        return default_rules

    def is_ipv_supported(self, ipv):
        return ipv == self.ipv
fw_config.py000064400000136430151731527130007073 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "FirewallConfig" ]

import copy
import os
import os.path
import shutil
from firewall import config
from firewall.core.logger import log
from firewall.core.io.icmptype import IcmpType, icmptype_reader, icmptype_writer
from firewall.core.io.service import Service, service_reader, service_writer
from firewall.core.io.zone import Zone, zone_reader, zone_writer
from firewall.core.io.ipset import IPSet, ipset_reader, ipset_writer
from firewall.core.io.helper import Helper, helper_reader, helper_writer
from firewall.core.io.policy import Policy, policy_reader, policy_writer
from firewall import errors
from firewall.errors import FirewallError

class FirewallConfig(object):
    def __init__(self, fw):
        self._fw = fw
        self.__init_vars()

    def __repr__(self):
        return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \
            (self.__class__,
             self._ipsets, self._icmptypes, self._services, self._zones,
             self._helpers, self.policy_objects,
             self._builtin_ipsets, self._builtin_icmptypes,
             self._builtin_services, self._builtin_zones, self._builtin_helpers,
             self._builtin_policy_objects,
             self._firewalld_conf, self._policies, self._direct)

    def __init_vars(self):
        self._ipsets = { }
        self._icmptypes = { }
        self._services = { }
        self._zones = { }
        self._helpers = { }
        self._policy_objects = { }
        self._builtin_ipsets = { }
        self._builtin_icmptypes = { }
        self._builtin_services = { }
        self._builtin_zones = { }
        self._builtin_helpers = { }
        self._builtin_policy_objects = { }
        self._firewalld_conf = None
        self._policies = None
        self._direct = None

    def cleanup(self):
        for x in list(self._builtin_ipsets.keys()):
            self._builtin_ipsets[x].cleanup()
            del self._builtin_ipsets[x]
        for x in list(self._ipsets.keys()):
            self._ipsets[x].cleanup()
            del self._ipsets[x]

        for x in list(self._builtin_icmptypes.keys()):
            self._builtin_icmptypes[x].cleanup()
            del self._builtin_icmptypes[x]
        for x in list(self._icmptypes.keys()):
            self._icmptypes[x].cleanup()
            del self._icmptypes[x]

        for x in list(self._builtin_services.keys()):
            self._builtin_services[x].cleanup()
            del self._builtin_services[x]
        for x in list(self._services.keys()):
            self._services[x].cleanup()
            del self._services[x]

        for x in list(self._builtin_zones.keys()):
            self._builtin_zones[x].cleanup()
            del self._builtin_zones[x]
        for x in list(self._zones.keys()):
            self._zones[x].cleanup()
            del self._zones[x]

        for x in list(self._builtin_helpers.keys()):
            self._builtin_helpers[x].cleanup()
            del self._builtin_helpers[x]
        for x in list(self._helpers.keys()):
            self._helpers[x].cleanup()
            del self._helpers[x]

        if self._firewalld_conf:
            self._firewalld_conf.cleanup()
            del self._firewalld_conf
            self._firewalld_conf = None

        if self._policies:
            self._policies.cleanup()
            del self._policies
            self._policies = None

        if self._direct:
            self._direct.cleanup()
            del self._direct
            self._direct = None

        self.__init_vars()

    # access check

    def lockdown_enabled(self):
        return self._fw.policies.query_lockdown()

    def access_check(self, key, value):
        return self._fw.policies.access_check(key, value)

    # firewalld_conf

    def set_firewalld_conf(self, conf):
        self._firewalld_conf = conf

    def get_firewalld_conf(self):
        return self._firewalld_conf

    def update_firewalld_conf(self):
        if not os.path.exists(config.FIREWALLD_CONF):
            self._firewalld_conf.clear()
        else:
            self._firewalld_conf.read()

    # policies

    def set_policies(self, policies):
        self._policies = policies

    def get_policies(self):
        return self._policies

    def update_lockdown_whitelist(self):
        if not os.path.exists(config.LOCKDOWN_WHITELIST):
            self._policies.lockdown_whitelist.cleanup()
        else:
            self._policies.lockdown_whitelist.read()

    # direct

    def set_direct(self, direct):
        self._direct = direct

    def get_direct(self):
        return self._direct

    def update_direct(self):
        if not os.path.exists(config.FIREWALLD_DIRECT):
            self._direct.cleanup()
        else:
            self._direct.read()

    # ipset

    def get_ipsets(self):
        return sorted(set(list(self._ipsets.keys()) + \
                          list(self._builtin_ipsets.keys())))

    def add_ipset(self, obj):
        if obj.builtin:
            self._builtin_ipsets[obj.name] = obj
        else:
            self._ipsets[obj.name] = obj

    def get_ipset(self, name):
        if name in self._ipsets:
            return self._ipsets[name]
        elif name in self._builtin_ipsets:
            return self._builtin_ipsets[name]
        raise FirewallError(errors.INVALID_IPSET, name)

    def load_ipset_defaults(self, obj):
        if obj.name not in self._ipsets:
            raise FirewallError(errors.NO_DEFAULTS, obj.name)
        elif self._ipsets[obj.name] != obj:
            raise FirewallError(errors.NO_DEFAULTS,
                                "self._ipsets[%s] != obj" % obj.name)
        elif obj.name not in self._builtin_ipsets:
            raise FirewallError(errors.NO_DEFAULTS,
                            "'%s' not a built-in ipset" % obj.name)
        self._remove_ipset(obj)
        return self._builtin_ipsets[obj.name]

    def get_ipset_config(self, obj):
        return obj.export_config()

    def set_ipset_config(self, obj, conf):
        if obj.builtin:
            x = copy.copy(obj)
            x.import_config(conf)
            x.path = config.ETC_FIREWALLD_IPSETS
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_ipset(x)
            ipset_writer(x)
            return x
        else:
            obj.import_config(conf)
            ipset_writer(obj)
            return obj

    def new_ipset(self, name, conf):
        if name in self._ipsets or name in self._builtin_ipsets:
            raise FirewallError(errors.NAME_CONFLICT,
                                "new_ipset(): '%s'" % name)

        x = IPSet()
        x.check_name(name)
        x.import_config(conf)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_IPSETS
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        ipset_writer(x)
        self.add_ipset(x)
        return x

    def update_ipset_from_path(self, name):
        filename = os.path.basename(name)
        path = os.path.dirname(name)

        if not os.path.exists(name):
            # removed file

            if path == config.ETC_FIREWALLD_IPSETS:
                # removed custom ipset
                for x in self._ipsets.keys():
                    obj = self._ipsets[x]
                    if obj.filename == filename:
                        del self._ipsets[x]
                        if obj.name in self._builtin_ipsets:
                            return ("update", self._builtin_ipsets[obj.name])
                        return ("remove", obj)
            else:
                # removed builtin ipset
                for x in self._builtin_ipsets.keys():
                    obj = self._builtin_ipsets[x]
                    if obj.filename == filename:
                        del self._builtin_ipsets[x]
                        if obj.name not in self._ipsets:
                            # update dbus ipset
                            return ("remove", obj)
                        else:
                            # builtin hidden, no update needed
                            return (None, None)

            # ipset not known to firewalld, yet (timeout, ..)
            return (None, None)

        # new or updated file

        log.debug1("Loading ipset file '%s'", name)
        try:
            obj = ipset_reader(filename, path)
        except Exception as msg:
            log.error("Failed to load ipset file '%s': %s", filename, msg)
            return (None, None)

        # new ipset
        if obj.name not in self._builtin_ipsets and obj.name not in self._ipsets:
            self.add_ipset(obj)
            return ("new", obj)

        # updated ipset
        if path == config.ETC_FIREWALLD_IPSETS:
            # custom ipset update
            if obj.name in self._ipsets:
                obj.default = self._ipsets[obj.name].default
                self._ipsets[obj.name] = obj
            return ("update", obj)
        else:
            if obj.name in self._builtin_ipsets:
                # builtin ipset update
                del self._builtin_ipsets[obj.name]
                self._builtin_ipsets[obj.name] = obj

                if obj.name not in self._ipsets:
                    # update dbus ipset
                    return ("update", obj)
                else:
                    # builtin hidden, no update needed
                    return (None, None)

        # ipset not known to firewalld, yet (timeout, ..)
        return (None, None)

    def _remove_ipset(self, obj):
        if obj.name not in self._ipsets:
            raise FirewallError(errors.INVALID_IPSET, obj.name)
        if obj.path != config.ETC_FIREWALLD_IPSETS:
            raise FirewallError(errors.INVALID_DIRECTORY,
                                "'%s' != '%s'" % (obj.path,
                                                  config.ETC_FIREWALLD_IPSETS))

        name = "%s/%s.xml" % (obj.path, obj.name)
        try:
            shutil.move(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)
            os.remove(name)

        del self._ipsets[obj.name]

    def check_builtin_ipset(self, obj):
        if obj.builtin or not obj.default:
            raise FirewallError(errors.BUILTIN_IPSET,
                                "'%s' is built-in ipset" % obj.name)

    def remove_ipset(self, obj):
        self.check_builtin_ipset(obj)
        self._remove_ipset(obj)

    def rename_ipset(self, obj, name):
        self.check_builtin_ipset(obj)
        new_ipset = self._copy_ipset(obj, name)
        self._remove_ipset(obj)
        return new_ipset

    def _copy_ipset(self, obj, name):
        return self.new_ipset(name, obj.export_config())

    # icmptypes

    def get_icmptypes(self):
        return sorted(set(list(self._icmptypes.keys()) + \
                          list(self._builtin_icmptypes.keys())))

    def add_icmptype(self, obj):
        if obj.builtin:
            self._builtin_icmptypes[obj.name] = obj
        else:
            self._icmptypes[obj.name] = obj

    def get_icmptype(self, name):
        if name in self._icmptypes:
            return self._icmptypes[name]
        elif name in self._builtin_icmptypes:
            return self._builtin_icmptypes[name]
        raise FirewallError(errors.INVALID_ICMPTYPE, name)

    def load_icmptype_defaults(self, obj):
        if obj.name not in self._icmptypes:
            raise FirewallError(errors.NO_DEFAULTS, obj.name)
        elif self._icmptypes[obj.name] != obj:
            raise FirewallError(errors.NO_DEFAULTS,
                                "self._icmptypes[%s] != obj" % obj.name)
        elif obj.name not in self._builtin_icmptypes:
            raise FirewallError(errors.NO_DEFAULTS,
                                "'%s' not a built-in icmptype" % obj.name)
        self._remove_icmptype(obj)
        return self._builtin_icmptypes[obj.name]

    def get_icmptype_config(self, obj):
        return obj.export_config()

    def set_icmptype_config(self, obj, conf):
        if obj.builtin:
            x = copy.copy(obj)
            x.import_config(conf)
            x.path = config.ETC_FIREWALLD_ICMPTYPES
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_icmptype(x)
            icmptype_writer(x)
            return x
        else:
            obj.import_config(conf)
            icmptype_writer(obj)
            return obj

    def new_icmptype(self, name, conf):
        if name in self._icmptypes or name in self._builtin_icmptypes:
            raise FirewallError(errors.NAME_CONFLICT,
                                "new_icmptype(): '%s'" % name)

        x = IcmpType()
        x.check_name(name)
        x.import_config(conf)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_ICMPTYPES
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        icmptype_writer(x)
        self.add_icmptype(x)
        return x

    def update_icmptype_from_path(self, name):
        filename = os.path.basename(name)
        path = os.path.dirname(name)

        if not os.path.exists(name):
            # removed file

            if path == config.ETC_FIREWALLD_ICMPTYPES:
                # removed custom icmptype
                for x in self._icmptypes.keys():
                    obj = self._icmptypes[x]
                    if obj.filename == filename:
                        del self._icmptypes[x]
                        if obj.name in self._builtin_icmptypes:
                            return ("update", self._builtin_icmptypes[obj.name])
                        return ("remove", obj)
            else:
                # removed builtin icmptype
                for x in self._builtin_icmptypes.keys():
                    obj = self._builtin_icmptypes[x]
                    if obj.filename == filename:
                        del self._builtin_icmptypes[x]
                        if obj.name not in self._icmptypes:
                            # update dbus icmptype
                            return ("remove", obj)
                        else:
                            # builtin hidden, no update needed
                            return (None, None)

            # icmptype not known to firewalld, yet (timeout, ..)
            return (None, None)

        # new or updated file

        log.debug1("Loading icmptype file '%s'", name)
        try:
            obj = icmptype_reader(filename, path)
        except Exception as msg:
            log.error("Failed to load icmptype file '%s': %s", filename, msg)
            return (None, None)

        # new icmptype
        if obj.name not in self._builtin_icmptypes and obj.name not in self._icmptypes:
            self.add_icmptype(obj)
            return ("new", obj)

        # updated icmptype
        if path == config.ETC_FIREWALLD_ICMPTYPES:
            # custom icmptype update
            if obj.name in self._icmptypes:
                obj.default = self._icmptypes[obj.name].default
                self._icmptypes[obj.name] = obj
            return ("update", obj)
        else:
            if obj.name in self._builtin_icmptypes:
                # builtin icmptype update
                del self._builtin_icmptypes[obj.name]
                self._builtin_icmptypes[obj.name] = obj

                if obj.name not in self._icmptypes:
                    # update dbus icmptype
                    return ("update", obj)
                else:
                    # builtin hidden, no update needed
                    return (None, None)
            
        # icmptype not known to firewalld, yet (timeout, ..)
        return (None, None)

    def _remove_icmptype(self, obj):
        if obj.name not in self._icmptypes:
            raise FirewallError(errors.INVALID_ICMPTYPE, obj.name)
        if obj.path != config.ETC_FIREWALLD_ICMPTYPES:
            raise FirewallError(errors.INVALID_DIRECTORY,
                                "'%s' != '%s'" % \
                                (obj.path, config.ETC_FIREWALLD_ICMPTYPES))

        name = "%s/%s.xml" % (obj.path, obj.name)
        try:
            shutil.move(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)
            os.remove(name)

        del self._icmptypes[obj.name]

    def check_builtin_icmptype(self, obj):
        if obj.builtin or not obj.default:
            raise FirewallError(errors.BUILTIN_ICMPTYPE,
                                "'%s' is built-in icmp type" % obj.name)

    def remove_icmptype(self, obj):
        self.check_builtin_icmptype(obj)
        self._remove_icmptype(obj)

    def rename_icmptype(self, obj, name):
        self.check_builtin_icmptype(obj)
        new_icmptype = self._copy_icmptype(obj, name)
        self._remove_icmptype(obj)
        return new_icmptype

    def _copy_icmptype(self, obj, name):
        return self.new_icmptype(name, obj.export_config())

    # services

    def get_services(self):
        return sorted(set(list(self._services.keys()) + \
                          list(self._builtin_services.keys())))

    def add_service(self, obj):
        if obj.builtin:
            self._builtin_services[obj.name] = obj
        else:
            self._services[obj.name] = obj

    def get_service(self, name):
        if name in self._services:
            return self._services[name]
        elif name in self._builtin_services:
            return self._builtin_services[name]
        raise FirewallError(errors.INVALID_SERVICE, "get_service(): '%s'" % name)

    def load_service_defaults(self, obj):
        if obj.name not in self._services:
            raise FirewallError(errors.NO_DEFAULTS, obj.name)
        elif self._services[obj.name] != obj:
            raise FirewallError(errors.NO_DEFAULTS,
                                "self._services[%s] != obj" % obj.name)
        elif obj.name not in self._builtin_services:
            raise FirewallError(errors.NO_DEFAULTS,
                                "'%s' not a built-in service" % obj.name)
        self._remove_service(obj)
        return self._builtin_services[obj.name]

    def get_service_config(self, obj):
        conf_dict = obj.export_config_dict()
        conf_list = []
        for i in range(8): # tuple based dbus API has 8 elements
            if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict:
                # old API needs the empty elements as well. Grab it from the
                # object otherwise we don't know the type.
                conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0])))
            else:
                conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]])
        return tuple(conf_list)

    def get_service_config_dict(self, obj):
        return obj.export_config_dict()

    def set_service_config(self, obj, conf):
        conf_dict = {}
        for i,value in enumerate(conf):
            conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]] = value

        if obj.builtin:
            x = copy.copy(obj)
            x.import_config_dict(conf_dict)
            x.path = config.ETC_FIREWALLD_SERVICES
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_service(x)
            service_writer(x)
            return x
        else:
            obj.import_config_dict(conf_dict)
            service_writer(obj)
            return obj

    def set_service_config_dict(self, obj, conf):
        if obj.builtin:
            x = copy.copy(obj)
            x.import_config_dict(conf)
            x.path = config.ETC_FIREWALLD_SERVICES
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_service(x)
            service_writer(x)
            return x
        else:
            obj.import_config_dict(conf)
            service_writer(obj)
            return obj

    def new_service(self, name, conf):
        if name in self._services or name in self._builtin_services:
            raise FirewallError(errors.NAME_CONFLICT,
                                "new_service(): '%s'" % name)

        conf_dict = {}
        for i,value in enumerate(conf):
            conf_dict[Service.IMPORT_EXPORT_STRUCTURE[i][0]] = value

        x = Service()
        x.check_name(name)
        x.import_config_dict(conf_dict)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_SERVICES
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        service_writer(x)
        self.add_service(x)
        return x

    def new_service_dict(self, name, conf):
        if name in self._services or name in self._builtin_services:
            raise FirewallError(errors.NAME_CONFLICT,
                                "new_service(): '%s'" % name)

        x = Service()
        x.check_name(name)
        x.import_config_dict(conf)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_SERVICES
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        service_writer(x)
        self.add_service(x)
        return x

    def update_service_from_path(self, name):
        filename = os.path.basename(name)
        path = os.path.dirname(name)

        if not os.path.exists(name):
            # removed file

            if path == config.ETC_FIREWALLD_SERVICES:
                # removed custom service
                for x in self._services.keys():
                    obj = self._services[x]
                    if obj.filename == filename:
                        del self._services[x]
                        if obj.name in self._builtin_services:
                            return ("update", self._builtin_services[obj.name])
                        return ("remove", obj)
            else:
                # removed builtin service
                for x in self._builtin_services.keys():
                    obj = self._builtin_services[x]
                    if obj.filename == filename:
                        del self._builtin_services[x]
                        if obj.name not in self._services:
                            # update dbus service
                            return ("remove", obj)
                        else:
                            # builtin hidden, no update needed
                            return (None, None)

            # service not known to firewalld, yet (timeout, ..)
            return (None, None)

        # new or updated file

        log.debug1("Loading service file '%s'", name)
        try:
            obj = service_reader(filename, path)
        except Exception as msg:
            log.error("Failed to load service file '%s': %s", filename, msg)
            return (None, None)

        # new service
        if obj.name not in self._builtin_services and obj.name not in self._services:
            self.add_service(obj)
            return ("new", obj)

        # updated service
        if path == config.ETC_FIREWALLD_SERVICES:
            # custom service update
            if obj.name in self._services:
                obj.default = self._services[obj.name].default
                self._services[obj.name] = obj
            return ("update", obj)
        else:
            if obj.name in self._builtin_services:
                # builtin service update
                del self._builtin_services[obj.name]
                self._builtin_services[obj.name] = obj

                if obj.name not in self._services:
                    # update dbus service
                    return ("update", obj)
                else:
                    # builtin hidden, no update needed
                    return (None, None)
            
        # service not known to firewalld, yet (timeout, ..)
        return (None, None)

    def _remove_service(self, obj):
        if obj.name not in self._services:
            raise FirewallError(errors.INVALID_SERVICE, obj.name)
        if obj.path != config.ETC_FIREWALLD_SERVICES:
            raise FirewallError(errors.INVALID_DIRECTORY,
                                "'%s' != '%s'" % \
                                (obj.path, config.ETC_FIREWALLD_SERVICES))

        name = "%s/%s.xml" % (obj.path, obj.name)
        try:
            shutil.move(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)
            os.remove(name)

        del self._services[obj.name]

    def check_builtin_service(self, obj):
        if obj.builtin or not obj.default:
            raise FirewallError(errors.BUILTIN_SERVICE,
                                "'%s' is built-in service" % obj.name)

    def remove_service(self, obj):
        self.check_builtin_service(obj)
        self._remove_service(obj)

    def rename_service(self, obj, name):
        self.check_builtin_service(obj)
        new_service = self._copy_service(obj, name)
        self._remove_service(obj)
        return new_service

    def _copy_service(self, obj, name):
        return self.new_service_dict(name, obj.export_config_dict())

    # zones

    def get_zones(self):
        return sorted(set(list(self._zones.keys()) + \
                          list(self._builtin_zones.keys())))

    def add_zone(self, obj):
        if obj.builtin:
            self._builtin_zones[obj.name] = obj
        else:
            self._zones[obj.name] = obj

    def forget_zone(self, name):
        if name in self._builtin_zones:
            del self._builtin_zones[name]
        if name in self._zones:
            del self._zones[name]

    def get_zone(self, name):
        if name in self._zones:
            return self._zones[name]
        elif name in self._builtin_zones:
            return self._builtin_zones[name]
        raise FirewallError(errors.INVALID_ZONE, "get_zone(): %s" % name)

    def load_zone_defaults(self, obj):
        if obj.name not in self._zones:
            raise FirewallError(errors.NO_DEFAULTS, obj.name)
        elif self._zones[obj.name] != obj:
            raise FirewallError(errors.NO_DEFAULTS,
                                "self._zones[%s] != obj" % obj.name)
        elif obj.name not in self._builtin_zones:
            raise FirewallError(errors.NO_DEFAULTS,
                                "'%s' not a built-in zone" % obj.name)
        self._remove_zone(obj)
        return self._builtin_zones[obj.name]

    def get_zone_config(self, obj):
        conf_dict = obj.export_config_dict()
        conf_list = []
        for i in range(16): # tuple based dbus API has 16 elements
            if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict:
                # old API needs the empty elements as well. Grab it from the
                # object otherwise we don't know the type.
                conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0])))
            else:
                conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]])
        return tuple(conf_list)

    def get_zone_config_dict(self, obj):
        return obj.export_config_dict()

    def set_zone_config(self, obj, conf):
        conf_dict = {}
        for i,value in enumerate(conf):
            conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]] = value

        if obj.builtin:
            x = copy.copy(obj)
            x.fw_config = self
            x.import_config_dict(conf_dict)
            x.path = config.ETC_FIREWALLD_ZONES
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_zone(x)
            zone_writer(x)
            return x
        else:
            obj.fw_config = self
            obj.import_config_dict(conf_dict)
            zone_writer(obj)
            return obj

    def set_zone_config_dict(self, obj, conf):
        if obj.builtin:
            x = copy.copy(obj)
            x.fw_config = self
            x.import_config_dict(conf)
            x.path = config.ETC_FIREWALLD_ZONES
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_zone(x)
            zone_writer(x)
            return x
        else:
            obj.fw_config = self
            obj.import_config_dict(conf)
            zone_writer(obj)
            return obj

    def new_zone(self, name, conf):
        if name in self._zones or name in self._builtin_zones:
            raise FirewallError(errors.NAME_CONFLICT, "new_zone(): '%s'" % name)

        conf_dict = {}
        for i,value in enumerate(conf):
            conf_dict[Zone.IMPORT_EXPORT_STRUCTURE[i][0]] = value

        x = Zone()
        x.fw_config = self
        x.check_name(name)
        x.import_config_dict(conf_dict)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_ZONES
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        zone_writer(x)
        self.add_zone(x)
        return x

    def new_zone_dict(self, name, conf):
        if name in self._zones or name in self._builtin_zones:
            raise FirewallError(errors.NAME_CONFLICT, "new_zone(): '%s'" % name)

        x = Zone()
        x.fw_config = self
        x.check_name(name)
        x.import_config_dict(conf)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_ZONES
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        zone_writer(x)
        self.add_zone(x)
        return x

    def update_zone_from_path(self, name):
        filename = os.path.basename(name)
        path = os.path.dirname(name)

        if not os.path.exists(name):
            # removed file

            if path.startswith(config.ETC_FIREWALLD_ZONES):
                # removed custom zone
                for x in self._zones.keys():
                    obj = self._zones[x]
                    if obj.filename == filename:
                        del self._zones[x]
                        if obj.name in self._builtin_zones:
                            return ("update", self._builtin_zones[obj.name])
                        return ("remove", obj)
            else:
                # removed builtin zone
                for x in self._builtin_zones.keys():
                    obj = self._builtin_zones[x]
                    if obj.filename == filename:
                        del self._builtin_zones[x]
                        if obj.name not in self._zones:
                            # update dbus zone
                            return ("remove", obj)
                        else:
                            # builtin hidden, no update needed
                            return (None, None)

            # zone not known to firewalld, yet (timeout, ..)
            return (None, None)

        # new or updated file

        log.debug1("Loading zone file '%s'", name)
        try:
            obj = zone_reader(filename, path)
        except Exception as msg:
            log.error("Failed to load zone file '%s': %s", filename, msg)
            return (None, None)

        obj.fw_config = self

        if path.startswith(config.ETC_FIREWALLD_ZONES) and \
           len(path) > len(config.ETC_FIREWALLD_ZONES):
            # custom combined zone part
            obj.name = "%s/%s" % (os.path.basename(path),
                                  os.path.basename(filename)[0:-4])

        # new zone
        if obj.name not in self._builtin_zones and obj.name not in self._zones:
            self.add_zone(obj)
            return ("new", obj)

        # updated zone
        if path.startswith(config.ETC_FIREWALLD_ZONES):
            # custom zone update
            if obj.name in self._zones:
                obj.default = self._zones[obj.name].default
                self._zones[obj.name] = obj
            return ("update", obj)
        else:
            if obj.name in self._builtin_zones:
                # builtin zone update
                del self._builtin_zones[obj.name]
                self._builtin_zones[obj.name] = obj

                if obj.name not in self._zones:
                    # update dbus zone
                    return ("update", obj)
                else:
                    # builtin hidden, no update needed
                    return (None, None)
            
        # zone not known to firewalld, yet (timeout, ..)
        return (None, None)

    def _remove_zone(self, obj):
        if obj.name not in self._zones:
            raise FirewallError(errors.INVALID_ZONE, obj.name)
        if not obj.path.startswith(config.ETC_FIREWALLD_ZONES):
            raise FirewallError(errors.INVALID_DIRECTORY,
                                "'%s' doesn't start with '%s'" % \
                                (obj.path, config.ETC_FIREWALLD_ZONES))

        name = "%s/%s.xml" % (obj.path, obj.name)
        try:
            shutil.move(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)
            os.remove(name)

        del self._zones[obj.name]

    def check_builtin_zone(self, obj):
        if obj.builtin or not obj.default:
            raise FirewallError(errors.BUILTIN_ZONE,
                                "'%s' is built-in zone" % obj.name)

    def remove_zone(self, obj):
        self.check_builtin_zone(obj)
        self._remove_zone(obj)

    def rename_zone(self, obj, name):
        self.check_builtin_zone(obj)
        obj_conf = obj.export_config_dict()
        self._remove_zone(obj)
        try:
            new_zone = self.new_zone_dict(name, obj_conf)
        except:
            # re-add original if rename failed
            self.new_zone_dict(obj.name, obj_conf)
            raise
        return new_zone

    # policy objects

    def get_policy_objects(self):
        return sorted(set(list(self._policy_objects.keys()) + \
                          list(self._builtin_policy_objects.keys())))

    def add_policy_object(self, obj):
        if obj.builtin:
            self._builtin_policy_objects[obj.name] = obj
        else:
            self._policy_objects[obj.name] = obj

    def get_policy_object(self, name):
        if name in self._policy_objects:
            return self._policy_objects[name]
        elif name in self._builtin_policy_objects:
            return self._builtin_policy_objects[name]
        raise FirewallError(errors.INVALID_POLICY, "get_policy_object(): %s" % name)

    def load_policy_object_defaults(self, obj):
        if obj.name not in self._policy_objects:
            raise FirewallError(errors.NO_DEFAULTS, obj.name)
        elif self._policy_objects[obj.name] != obj:
            raise FirewallError(errors.NO_DEFAULTS,
                                "self._policy_objects[%s] != obj" % obj.name)
        elif obj.name not in self._builtin_policy_objects:
            raise FirewallError(errors.NO_DEFAULTS,
                                "'%s' not a built-in policy" % obj.name)
        self._remove_policy_object(obj)
        return self._builtin_policy_objects[obj.name]

    def get_policy_object_config_dict(self, obj):
        return obj.export_config_dict()

    def set_policy_object_config_dict(self, obj, conf):
        if obj.builtin:
            x = copy.copy(obj)
            x.fw_config = self
            x.import_config_dict(conf)
            x.path = config.ETC_FIREWALLD_POLICIES
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_policy_object(x)
            policy_writer(x)
            return x
        else:
            obj.fw_config = self
            obj.import_config_dict(conf)
            policy_writer(obj)
            return obj

    def new_policy_object_dict(self, name, conf):
        if name in self._policy_objects or name in self._builtin_policy_objects:
            raise FirewallError(errors.NAME_CONFLICT, "new_policy_object(): '%s'" % name)

        x = Policy()
        x.fw_config = self
        x.check_name(name)
        x.import_config_dict(conf)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_POLICIES
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        policy_writer(x)
        self.add_policy_object(x)
        return x

    def update_policy_object_from_path(self, name):
        filename = os.path.basename(name)
        path = os.path.dirname(name)

        if not os.path.exists(name):
            # removed file

            if path.startswith(config.ETC_FIREWALLD_POLICIES):
                # removed custom policy_object
                for x in self._policy_objects.keys():
                    obj = self._policy_objects[x]
                    if obj.filename == filename:
                        del self._policy_objects[x]
                        if obj.name in self._builtin_policy_objects:
                            return ("update", self._builtin_policy_objects[obj.name])
                        return ("remove", obj)
            else:
                # removed builtin policy_object
                for x in self._builtin_policy_objects.keys():
                    obj = self._builtin_policy_objects[x]
                    if obj.filename == filename:
                        del self._builtin_policy_objects[x]
                        if obj.name not in self._policy_objects:
                            # update dbus policy_object
                            return ("remove", obj)
                        else:
                            # builtin hidden, no update needed
                            return (None, None)

            # policy_object not known to firewalld, yet (timeout, ..)
            return (None, None)

        # new or updated file

        log.debug1("Loading policy file '%s'", name)
        try:
            obj = policy_reader(filename, path)
        except Exception as msg:
            log.error("Failed to load policy file '%s': %s", filename, msg)
            return (None, None)

        obj.fw_config = self

        if path.startswith(config.ETC_FIREWALLD_POLICIES) and \
           len(path) > len(config.ETC_FIREWALLD_POLICIES):
            # custom combined policy_object part
            obj.name = "%s/%s" % (os.path.basename(path),
                                  os.path.basename(filename)[0:-4])

        # new policy_object
        if obj.name not in self._builtin_policy_objects and obj.name not in self._policy_objects:
            self.add_policy_object(obj)
            return ("new", obj)

        # updated policy_object
        if path.startswith(config.ETC_FIREWALLD_POLICIES):
            # custom policy_object update
            if obj.name in self._policy_objects:
                obj.default = self._policy_objects[obj.name].default
                self._policy_objects[obj.name] = obj
            return ("update", obj)
        else:
            if obj.name in self._builtin_policy_objects:
                # builtin policy_object update
                del self._builtin_policy_objects[obj.name]
                self._builtin_policy_objects[obj.name] = obj

                if obj.name not in self._policy_objects:
                    # update dbus policy_object
                    return ("update", obj)
                else:
                    # builtin hidden, no update needed
                    return (None, None)

        # policy_object not known to firewalld, yet (timeout, ..)
        return (None, None)

    def _remove_policy_object(self, obj):
        if obj.name not in self._policy_objects:
            raise FirewallError(errors.INVALID_POLICY, obj.name)
        if not obj.path.startswith(config.ETC_FIREWALLD_POLICIES):
            raise FirewallError(errors.INVALID_DIRECTORY,
                                "'%s' doesn't start with '%s'" % \
                                (obj.path, config.ETC_FIREWALLD_POLICIES))

        name = "%s/%s.xml" % (obj.path, obj.name)
        try:
            shutil.move(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)
            os.remove(name)

        del self._policy_objects[obj.name]

    def check_builtin_policy_object(self, obj):
        if obj.builtin or not obj.default:
            raise FirewallError(errors.BUILTIN_POLICY,
                                "'%s' is built-in policy" % obj.name)

    def remove_policy_object(self, obj):
        self.check_builtin_policy_object(obj)
        self._remove_policy_object(obj)

    def rename_policy_object(self, obj, name):
        self.check_builtin_policy_object(obj)
        new_policy_object = self._copy_policy_object(obj, name)
        self._remove_policy_object(obj)
        return new_policy_object

    def _copy_policy_object(self, obj, name):
        return self.new_policy_object_dict(name, obj.export_config_dict())

    # helper

    def get_helpers(self):
        return sorted(set(list(self._helpers.keys()) + \
                          list(self._builtin_helpers.keys())))

    def add_helper(self, obj):
        if obj.builtin:
            self._builtin_helpers[obj.name] = obj
        else:
            self._helpers[obj.name] = obj

    def get_helper(self, name):
        if name in self._helpers:
            return self._helpers[name]
        elif name in self._builtin_helpers:
            return self._builtin_helpers[name]
        raise FirewallError(errors.INVALID_HELPER, name)

    def load_helper_defaults(self, obj):
        if obj.name not in self._helpers:
            raise FirewallError(errors.NO_DEFAULTS, obj.name)
        elif self._helpers[obj.name] != obj:
            raise FirewallError(errors.NO_DEFAULTS,
                                "self._helpers[%s] != obj" % obj.name)
        elif obj.name not in self._builtin_helpers:
            raise FirewallError(errors.NO_DEFAULTS,
                            "'%s' not a built-in helper" % obj.name)
        self._remove_helper(obj)
        return self._builtin_helpers[obj.name]

    def get_helper_config(self, obj):
        return obj.export_config()

    def set_helper_config(self, obj, conf):
        if obj.builtin:
            x = copy.copy(obj)
            x.import_config(conf)
            x.path = config.ETC_FIREWALLD_HELPERS
            x.builtin = False
            if obj.path != x.path:
                x.default = False
            self.add_helper(x)
            helper_writer(x)
            return x
        else:
            obj.import_config(conf)
            helper_writer(obj)
            return obj

    def new_helper(self, name, conf):
        if name in self._helpers or name in self._builtin_helpers:
            raise FirewallError(errors.NAME_CONFLICT,
                                "new_helper(): '%s'" % name)

        x = Helper()
        x.check_name(name)
        x.import_config(conf)
        x.name = name
        x.filename = "%s.xml" % name
        x.path = config.ETC_FIREWALLD_HELPERS
        # It is not possible to add a new one with a name of a buitin
        x.builtin = False
        x.default = True

        helper_writer(x)
        self.add_helper(x)
        return x

    def update_helper_from_path(self, name):
        filename = os.path.basename(name)
        path = os.path.dirname(name)

        if not os.path.exists(name):
            # removed file

            if path == config.ETC_FIREWALLD_HELPERS:
                # removed custom helper
                for x in self._helpers.keys():
                    obj = self._helpers[x]
                    if obj.filename == filename:
                        del self._helpers[x]
                        if obj.name in self._builtin_helpers:
                            return ("update", self._builtin_helpers[obj.name])
                        return ("remove", obj)
            else:
                # removed builtin helper
                for x in self._builtin_helpers.keys():
                    obj = self._builtin_helpers[x]
                    if obj.filename == filename:
                        del self._builtin_helpers[x]
                        if obj.name not in self._helpers:
                            # update dbus helper
                            return ("remove", obj)
                        else:
                            # builtin hidden, no update needed
                            return (None, None)

            # helper not known to firewalld, yet (timeout, ..)
            return (None, None)

        # new or updated file

        log.debug1("Loading helper file '%s'", name)
        try:
            obj = helper_reader(filename, path)
        except Exception as msg:
            log.error("Failed to load helper file '%s': %s", filename, msg)
            return (None, None)

        # new helper
        if obj.name not in self._builtin_helpers and obj.name not in self._helpers:
            self.add_helper(obj)
            return ("new", obj)

        # updated helper
        if path == config.ETC_FIREWALLD_HELPERS:
            # custom helper update
            if obj.name in self._helpers:
                obj.default = self._helpers[obj.name].default
                self._helpers[obj.name] = obj
            return ("update", obj)
        else:
            if obj.name in self._builtin_helpers:
                # builtin helper update
                del self._builtin_helpers[obj.name]
                self._builtin_helpers[obj.name] = obj

                if obj.name not in self._helpers:
                    # update dbus helper
                    return ("update", obj)
                else:
                    # builtin hidden, no update needed
                    return (None, None)

        # helper not known to firewalld, yet (timeout, ..)
        return (None, None)

    def _remove_helper(self, obj):
        if obj.name not in self._helpers:
            raise FirewallError(errors.INVALID_HELPER, obj.name)
        if obj.path != config.ETC_FIREWALLD_HELPERS:
            raise FirewallError(errors.INVALID_DIRECTORY,
                                "'%s' != '%s'" % (obj.path,
                                                  config.ETC_FIREWALLD_HELPERS))

        name = "%s/%s.xml" % (obj.path, obj.name)
        try:
            shutil.move(name, "%s.old" % name)
        except Exception as msg:
            log.error("Backup of file '%s' failed: %s", name, msg)
            os.remove(name)

        del self._helpers[obj.name]

    def check_builtin_helper(self, obj):
        if obj.builtin or not obj.default:
            raise FirewallError(errors.BUILTIN_HELPER,
                                "'%s' is built-in helper" % obj.name)

    def remove_helper(self, obj):
        self.check_builtin_helper(obj)
        self._remove_helper(obj)

    def rename_helper(self, obj, name):
        self.check_builtin_helper(obj)
        new_helper = self._copy_helper(obj, name)
        self._remove_helper(obj)
        return new_helper

    def _copy_helper(self, obj, name):
        return self.new_helper(name, obj.export_config())
__init__.py000064400000000000151731527130006650 0ustar00watcher.py000064400000006234151731527130006565 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2012-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "Watcher" ]

from gi.repository import Gio, GLib

class Watcher(object):
    def __init__(self, callback, timeout):
        self._callback = callback
        self._timeout = timeout
        self._monitors = { }
        self._timeouts = { }
        self._blocked = [ ]

    def add_watch_dir(self, directory):
        gfile = Gio.File.new_for_path(directory)
        self._monitors[directory] = gfile.monitor_directory(\
            Gio.FileMonitorFlags.NONE, None)
        self._monitors[directory].connect("changed", self._file_changed_cb)

    def add_watch_file(self, filename):
        gfile = Gio.File.new_for_path(filename)
        self._monitors[filename] = gfile.monitor_file(\
            Gio.FileMonitorFlags.NONE, None)
        self._monitors[filename].connect("changed", self._file_changed_cb)

    def get_watches(self):
        return self._monitors.keys()
        
    def has_watch(self, filename):
        return filename in self._monitors

    def remove_watch(self, filename):
        del self._monitors[filename]

    def block_source(self, filename):
        if filename not in self._blocked:
            self._blocked.append(filename)

    def unblock_source(self, filename):
        if filename in self._blocked:
            self._blocked.remove(filename)

    def clear_timeouts(self):
        for filename in list(self._timeouts.keys()):
            GLib.source_remove(self._timeouts[filename])
            del self._timeouts[filename]

    def _call_callback(self, filename):
        if filename not in self._blocked:
            self._callback(filename)
        del self._timeouts[filename]

    def _file_changed_cb(self, monitor, gio_file, gio_other_file, event):
        filename = gio_file.get_parse_name()
        if filename in self._blocked:
            if filename in self._timeouts:
                GLib.source_remove(self._timeouts[filename])
                del self._timeouts[filename]
            return

        if event == Gio.FileMonitorEvent.CHANGED or \
                event == Gio.FileMonitorEvent.CREATED or \
                event == Gio.FileMonitorEvent.DELETED or \
                event == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED:
            if filename in self._timeouts:
                GLib.source_remove(self._timeouts[filename])
                del self._timeouts[filename]
            self._timeouts[filename] = GLib.timeout_add_seconds(\
                self._timeout, self._call_callback, filename)
fw.py000064400000142345151731527130005550 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "Firewall" ]

import os.path
import sys
import copy
import time
import traceback
from firewall import config
from firewall import functions
from firewall.core import ipXtables
from firewall.core import ebtables
from firewall.core import nftables
from firewall.core import ipset
from firewall.core import modules
from firewall.core.fw_icmptype import FirewallIcmpType
from firewall.core.fw_service import FirewallService
from firewall.core.fw_zone import FirewallZone
from firewall.core.fw_direct import FirewallDirect
from firewall.core.fw_config import FirewallConfig
from firewall.core.fw_policies import FirewallPolicies
from firewall.core.fw_ipset import FirewallIPSet
from firewall.core.fw_transaction import FirewallTransaction
from firewall.core.fw_helper import FirewallHelper
from firewall.core.fw_policy import FirewallPolicy
from firewall.core.fw_nm import nm_get_bus_name, nm_get_interfaces_in_zone
from firewall.core.logger import log
from firewall.core.io.firewalld_conf import firewalld_conf
from firewall.core.io.direct import Direct
from firewall.core.io.service import service_reader
from firewall.core.io.icmptype import icmptype_reader
from firewall.core.io.zone import zone_reader, Zone
from firewall.core.io.ipset import ipset_reader
from firewall.core.ipset import IPSET_TYPES
from firewall.core.io.helper import helper_reader
from firewall.core.io.policy import policy_reader
from firewall import errors
from firewall.errors import FirewallError

############################################################################
#
# class Firewall
#
############################################################################

class Firewall(object):
    def __init__(self, offline=False):
        self._firewalld_conf = firewalld_conf(config.FIREWALLD_CONF)
        self._offline = offline

        if self._offline:
            self.ip4tables_enabled = False
            self.ip6tables_enabled = False
            self.ebtables_enabled = False
            self.ipset_enabled = False
            self.ipset_supported_types = IPSET_TYPES
            self.nftables_enabled = False
        else:
            self.ip4tables_backend = ipXtables.ip4tables(self)
            self.ip4tables_enabled = True
            self.ipv4_supported_icmp_types = [ ]
            self.ip6tables_backend = ipXtables.ip6tables(self)
            self.ip6tables_enabled = True
            self.ipv6_supported_icmp_types = [ ]
            self.ebtables_backend = ebtables.ebtables()
            self.ebtables_enabled = True
            self.ipset_backend = ipset.ipset()
            self.ipset_enabled = True
            self.ipset_supported_types = [ ]
            self.nftables_backend = nftables.nftables(self)
            self.nftables_enabled = True

            self.modules_backend = modules.modules()

        self.icmptype = FirewallIcmpType(self)
        self.service = FirewallService(self)
        self.zone = FirewallZone(self)
        self.direct = FirewallDirect(self)
        self.config = FirewallConfig(self)
        self.policies = FirewallPolicies()
        self.ipset = FirewallIPSet(self)
        self.helper = FirewallHelper(self)
        self.policy = FirewallPolicy(self)

        self.__init_vars()

    def __repr__(self):
        return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \
            (self.__class__, self.ip4tables_enabled, self.ip6tables_enabled,
             self.ebtables_enabled, self._state, self._panic,
             self._default_zone, self._module_refcount, self._marks,
             self.cleanup_on_exit, self.cleanup_modules_on_exit,
             self.ipv6_rpfilter_enabled, self.ipset_enabled,
             self._individual_calls, self._log_denied)

    def __init_vars(self):
        self._state = "INIT"
        self._panic = False
        self._default_zone = ""
        self._module_refcount = { }
        self._marks = [ ]
        # fallback settings will be overloaded by firewalld.conf
        self.cleanup_on_exit = config.FALLBACK_CLEANUP_ON_EXIT
        self.cleanup_modules_on_exit = config.FALLBACK_CLEANUP_MODULES_ON_EXIT
        self.ipv6_rpfilter_enabled = config.FALLBACK_IPV6_RPFILTER
        self._individual_calls = config.FALLBACK_INDIVIDUAL_CALLS
        self._log_denied = config.FALLBACK_LOG_DENIED
        self._firewall_backend = config.FALLBACK_FIREWALL_BACKEND
        self._flush_all_on_reload = config.FALLBACK_FLUSH_ALL_ON_RELOAD
        self._rfc3964_ipv4 = config.FALLBACK_RFC3964_IPV4
        self._allow_zone_drifting = config.FALLBACK_ALLOW_ZONE_DRIFTING

    def _check_tables(self):
        # check if iptables, ip6tables and ebtables are usable, else disable
        if self.ip4tables_enabled and \
           "filter" not in self.ip4tables_backend.get_available_tables():
            log.info1("iptables is not usable.")
            self.ip4tables_enabled = False

        if self.ip6tables_enabled and \
           "filter" not in self.ip6tables_backend.get_available_tables():
            log.info1("ip6tables is not usable.")
            self.ip6tables_enabled = False

        if self.ebtables_enabled and \
           "filter" not in self.ebtables_backend.get_available_tables():
            log.info1("ebtables is not usable.")
            self.ebtables_enabled = False

        # is there at least support for ipv4 or ipv6
        if not self.ip4tables_enabled and not self.ip6tables_enabled \
           and not self.nftables_enabled:
            log.fatal("No IPv4 and IPv6 firewall.")
            sys.exit(1)

    def _start_check(self):
        try:
            self.ipset_backend.set_list()
        except ValueError:
            log.warning("ipset not usable, disabling ipset usage in firewall.")
            # ipset is not usable, no supported types
            self.ipset_enabled = False
            self.ipset_supported_types = [ ]
        else:
            # ipset is usable, get all supported types
            self.ipset_supported_types = self.ipset_backend.set_supported_types()

        self.ip4tables_backend.fill_exists()
        if not self.ip4tables_backend.restore_command_exists:
            if self.ip4tables_backend.command_exists:
                log.warning("iptables-restore is missing, using "
                            "individual calls for IPv4 firewall.")
            else:
                log.warning("iptables-restore and iptables are missing, "
                            "disabling IPv4 firewall.")
                self.ip4tables_enabled = False
        if self.nftables_enabled:
            self.ipv4_supported_icmp_types = self.nftables_backend.supported_icmp_types("ipv4")
        else:
            if self.ip4tables_enabled:
                self.ipv4_supported_icmp_types = self.ip4tables_backend.supported_icmp_types()
            else:
                self.ipv4_supported_icmp_types = [ ]
        self.ip6tables_backend.fill_exists()
        if not self.ip6tables_backend.restore_command_exists:
            if self.ip6tables_backend.command_exists:
                log.warning("ip6tables-restore is missing, using "
                            "individual calls for IPv6 firewall.")
            else:
                log.warning("ip6tables-restore and ip6tables are missing, "
                            "disabling IPv6 firewall.")
                self.ip6tables_enabled = False
        if self.nftables_enabled:
            self.ipv6_supported_icmp_types = self.nftables_backend.supported_icmp_types("ipv6")
        else:
            if self.ip6tables_enabled:
                self.ipv6_supported_icmp_types = self.ip6tables_backend.supported_icmp_types()
            else:
                self.ipv6_supported_icmp_types = [ ]
        self.ebtables_backend.fill_exists()
        if not self.ebtables_backend.restore_command_exists:
            if self.ebtables_backend.command_exists:
                log.warning("ebtables-restore is missing, using "
                            "individual calls for bridge firewall.")
            else:
                log.warning("ebtables-restore and ebtables are missing, "
                            "disabling bridge firewall.")
                self.ebtables_enabled = False

        if self.ebtables_enabled and not self._individual_calls and \
           not self.ebtables_backend.restore_noflush_option:
            log.debug1("ebtables-restore is not supporting the --noflush "
                       "option, will therefore not be used")

    def _start(self, reload=False, complete_reload=False):
        # initialize firewall
        default_zone = config.FALLBACK_ZONE

        # load firewalld config
        log.debug1("Loading firewalld config file '%s'", config.FIREWALLD_CONF)
        try:
            self._firewalld_conf.read()
        except Exception as msg:
            log.warning(msg)
            log.warning("Using fallback firewalld configuration settings.")
        else:
            if self._firewalld_conf.get("DefaultZone"):
                default_zone = self._firewalld_conf.get("DefaultZone")

            if self._firewalld_conf.get("CleanupOnExit"):
                value = self._firewalld_conf.get("CleanupOnExit")
                if value is not None and value.lower() in [ "no", "false" ]:
                    self.cleanup_on_exit = False
                log.debug1("CleanupOnExit is set to '%s'",
                           self.cleanup_on_exit)

            if self._firewalld_conf.get("CleanupModulesOnExit"):
                value = self._firewalld_conf.get("CleanupModulesOnExit")
                if value is not None and value.lower() in [ "yes", "true" ]:
                    self.cleanup_modules_on_exit = True
                if value is not None and value.lower() in [ "no", "false" ]:
                    self.cleanup_modules_on_exit = False
                log.debug1("CleanupModulesOnExit is set to '%s'",
                           self.cleanup_modules_on_exit)

            if self._firewalld_conf.get("Lockdown"):
                value = self._firewalld_conf.get("Lockdown")
                if value is not None and value.lower() in [ "yes", "true" ]:
                    log.debug1("Lockdown is enabled")
                    try:
                        self.policies.enable_lockdown()
                    except FirewallError:
                        # already enabled, this is probably reload
                        pass

            if self._firewalld_conf.get("IPv6_rpfilter"):
                value = self._firewalld_conf.get("IPv6_rpfilter")
                if value is not None:
                    if value.lower() in [ "no", "false" ]:
                        self.ipv6_rpfilter_enabled = False
                    if value.lower() in [ "yes", "true" ]:
                        self.ipv6_rpfilter_enabled = True
            if self.ipv6_rpfilter_enabled:
                log.debug1("IPv6 rpfilter is enabled")
            else:
                log.debug1("IPV6 rpfilter is disabled")

            if self._firewalld_conf.get("IndividualCalls"):
                value = self._firewalld_conf.get("IndividualCalls")
                if value is not None and value.lower() in [ "yes", "true" ]:
                    log.debug1("IndividualCalls is enabled")
                    self._individual_calls = True

            if self._firewalld_conf.get("LogDenied"):
                value = self._firewalld_conf.get("LogDenied")
                if value is None or value.lower() == "no":
                    self._log_denied = "off"
                else:
                    self._log_denied = value.lower()
                    log.debug1("LogDenied is set to '%s'", self._log_denied)

            if self._firewalld_conf.get("FirewallBackend"):
                self._firewall_backend = self._firewalld_conf.get("FirewallBackend")
                log.debug1("FirewallBackend is set to '%s'",
                           self._firewall_backend)

            if self._firewalld_conf.get("FlushAllOnReload"):
                value = self._firewalld_conf.get("FlushAllOnReload")
                if value.lower() in [ "no", "false" ]:
                    self._flush_all_on_reload = False
                else:
                    self._flush_all_on_reload = True
                log.debug1("FlushAllOnReload is set to '%s'",
                           self._flush_all_on_reload)

            if self._firewalld_conf.get("RFC3964_IPv4"):
                value = self._firewalld_conf.get("RFC3964_IPv4")
                if value.lower() in [ "no", "false" ]:
                    self._rfc3964_ipv4 = False
                else:
                    self._rfc3964_ipv4 = True
                log.debug1("RFC3964_IPv4 is set to '%s'",
                           self._rfc3964_ipv4)

            if self._firewalld_conf.get("AllowZoneDrifting"):
                value = self._firewalld_conf.get("AllowZoneDrifting")
                if value.lower() in [ "no", "false" ]:
                    self._allow_zone_drifting = False
                else:
                    self._allow_zone_drifting = True
                    if not self._offline:
                        log.warning("AllowZoneDrifting is enabled. This is considered "
                                    "an insecure configuration option. It will be "
                                    "removed in a future release. Please consider "
                                    "disabling it now.")
                log.debug1("AllowZoneDrifting is set to '%s'",
                           self._allow_zone_drifting)

        self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf))

        self._select_firewall_backend(self._firewall_backend)

        if not self._offline:
            self._start_check()

        # load lockdown whitelist
        log.debug1("Loading lockdown whitelist")
        try:
            self.policies.lockdown_whitelist.read()
        except Exception as msg:
            if self.policies.query_lockdown():
                log.error("Failed to load lockdown whitelist '%s': %s",
                          self.policies.lockdown_whitelist.filename, msg)
            else:
                log.debug1("Failed to load lockdown whitelist '%s': %s",
                           self.policies.lockdown_whitelist.filename, msg)

        # copy policies to config interface
        self.config.set_policies(copy.deepcopy(self.policies))

        # load ipset files
        self._loader(config.FIREWALLD_IPSETS, "ipset")
        self._loader(config.ETC_FIREWALLD_IPSETS, "ipset")

        # load icmptype files
        self._loader(config.FIREWALLD_ICMPTYPES, "icmptype")
        self._loader(config.ETC_FIREWALLD_ICMPTYPES, "icmptype")

        if len(self.icmptype.get_icmptypes()) == 0:
            log.error("No icmptypes found.")

        # load helper files
        self._loader(config.FIREWALLD_HELPERS, "helper")
        self._loader(config.ETC_FIREWALLD_HELPERS, "helper")

        # load service files
        self._loader(config.FIREWALLD_SERVICES, "service")
        self._loader(config.ETC_FIREWALLD_SERVICES, "service")

        if len(self.service.get_services()) == 0:
            log.error("No services found.")

        # load zone files
        self._loader(config.FIREWALLD_ZONES, "zone")
        self._loader(config.ETC_FIREWALLD_ZONES, "zone")

        if len(self.zone.get_zones()) == 0:
            log.fatal("No zones found.")
            sys.exit(1)

        # load policy files
        self._loader(config.FIREWALLD_POLICIES, "policy")
        self._loader(config.ETC_FIREWALLD_POLICIES, "policy")

        # check minimum required zones
        error = False
        for z in [ "block", "drop", "trusted" ]:
            if z not in self.zone.get_zones():
                log.fatal("Zone '%s' is not available.", z)
                error = True
        if error:
            sys.exit(1)

        # check if default_zone is a valid zone
        if default_zone not in self.zone.get_zones():
            if "public" in self.zone.get_zones():
                zone = "public"
            elif "external" in self.zone.get_zones():
                zone = "external"
            else:
                zone = "block" # block is a base zone, therefore it has to exist

            log.error("Default zone '%s' is not valid. Using '%s'.",
                      default_zone, zone)
            default_zone = zone
        else:
            log.debug1("Using default zone '%s'", default_zone)

        # load direct rules
        obj = Direct(config.FIREWALLD_DIRECT)
        if os.path.exists(config.FIREWALLD_DIRECT):
            log.debug1("Loading direct rules file '%s'" % \
                       config.FIREWALLD_DIRECT)
            try:
                obj.read()
            except Exception as msg:
                log.error("Failed to load direct rules file '%s': %s",
                          config.FIREWALLD_DIRECT, msg)
        self.direct.set_permanent_config(obj)
        self.config.set_direct(copy.deepcopy(obj))

        self._default_zone = self.check_zone(default_zone)

        if self._offline:
            return

        # check if needed tables are there
        self._check_tables()

        if log.getDebugLogLevel() > 0:
            # get time before flushing and applying
            tm1 = time.time()

        # Start transaction
        transaction = FirewallTransaction(self)

        # flush rules
        if not reload:
            self.flush(use_transaction=transaction)

        # If modules need to be unloaded in complete reload or if there are
        # ipsets to get applied, limit the transaction to flush.
        #
        # Future optimization for the ipset case in reload: The transaction
        # only needs to be split here if there are conflicting ipset types in
        # exsting ipsets and the configuration in firewalld.
        if (reload and complete_reload) or \
           (self.ipset_enabled and self.ipset.has_ipsets()):
            transaction.execute(True)
            transaction.clear()

        # complete reload: unload modules also
        if reload and complete_reload:
            log.debug1("Unloading firewall modules")
            self.modules_backend.unload_firewall_modules()

        self.apply_default_tables(use_transaction=transaction)
        transaction.execute(True)
        transaction.clear()

        # apply settings for loaded ipsets while reloading here
        if self.ipset_enabled and self.ipset.has_ipsets():
            log.debug1("Applying ipsets")
            self.ipset.apply_ipsets()

        # Start or continue with transaction

        # apply default rules
        log.debug1("Applying default rule set")
        self.apply_default_rules(use_transaction=transaction)

        # apply settings for loaded zones
        log.debug1("Applying used zones")
        self.zone.apply_zones(use_transaction=transaction)

        self.zone.change_default_zone(None, self._default_zone,
                                      use_transaction=transaction)

        # apply policies
        log.debug1("Applying used policies")
        self.policy.apply_policies(use_transaction=transaction)

        # Execute transaction
        transaction.execute(True)

        # Start new transaction for direct rules
        transaction.clear()

        # apply direct chains, rules and passthrough rules
        if self.direct.has_configuration():
            log.debug1("Applying direct chains rules and passthrough rules")
            self.direct.apply_direct(transaction)

            # since direct rules are easy to make syntax errors lets highlight
            # the cause if the transaction fails.
            try:
                transaction.execute(True)
                transaction.clear()
            except FirewallError as e:
                raise FirewallError(e.code, "Direct: %s" % (e.msg if e.msg else ""))
            except Exception:
                raise

        del transaction

        if log.getDebugLogLevel() > 1:
            # get time after flushing and applying
            tm2 = time.time()
            log.debug2("Flushing and applying took %f seconds" % (tm2 - tm1))

    def start(self):
        try:
            self._start()
        except Exception:
            self._state = "FAILED"
            self.set_policy("ACCEPT")
            raise
        else:
            self._state = "RUNNING"
            self.set_policy("ACCEPT")

    def _loader(self, path, reader_type, combine=False):
        # combine: several zone files are getting combined into one obj
        if not os.path.isdir(path):
            return

        if combine:
            if path.startswith(config.ETC_FIREWALLD) and reader_type == "zone":
                combined_zone = Zone()
                combined_zone.name = os.path.basename(path)
                combined_zone.check_name(combined_zone.name)
                combined_zone.path = path
                combined_zone.default = False
            else:
                combine = False

        for filename in sorted(os.listdir(path)):
            if not filename.endswith(".xml"):
                if path.startswith(config.ETC_FIREWALLD) and \
                        reader_type == "zone" and \
                        os.path.isdir("%s/%s" % (path, filename)):
                    self._loader("%s/%s" % (path, filename), reader_type,
                                 combine=True)
                continue

            name = "%s/%s" % (path, filename)
            log.debug1("Loading %s file '%s'", reader_type, name)
            try:
                if reader_type == "icmptype":
                    obj = icmptype_reader(filename, path)
                    if obj.name in self.icmptype.get_icmptypes():
                        orig_obj = self.icmptype.get_icmptype(obj.name)
                        log.debug1("  Overloads %s '%s' ('%s/%s')", reader_type,
                                   orig_obj.name, orig_obj.path,
                                   orig_obj.filename)
                        self.icmptype.remove_icmptype(orig_obj.name)
                    elif obj.path.startswith(config.ETC_FIREWALLD):
                        obj.default = True
                    try:
                        self.icmptype.add_icmptype(obj)
                    except FirewallError as error:
                        log.info1("%s: %s, ignoring for run-time." % \
                                    (obj.name, str(error)))
                    # add a deep copy to the configuration interface
                    self.config.add_icmptype(copy.deepcopy(obj))
                elif reader_type == "service":
                    obj = service_reader(filename, path)
                    if obj.name in self.service.get_services():
                        orig_obj = self.service.get_service(obj.name)
                        log.debug1("  Overloads %s '%s' ('%s/%s')", reader_type,
                                   orig_obj.name, orig_obj.path,
                                   orig_obj.filename)
                        self.service.remove_service(orig_obj.name)
                    elif obj.path.startswith(config.ETC_FIREWALLD):
                        obj.default = True
                    self.service.add_service(obj)
                    # add a deep copy to the configuration interface
                    self.config.add_service(copy.deepcopy(obj))
                elif reader_type == "zone":
                    obj = zone_reader(filename, path, no_check_name=combine)
                    if combine:
                        # Change name for permanent configuration
                        obj.name = "%s/%s" % (
                            os.path.basename(path),
                            os.path.basename(filename)[0:-4])
                        obj.check_name(obj.name)
                    # Copy object before combine
                    config_obj = copy.deepcopy(obj)
                    if obj.name in self.zone.get_zones():
                        orig_obj = self.zone.get_zone(obj.name)
                        self.zone.remove_zone(orig_obj.name)
                        if orig_obj.combined:
                            log.debug1("  Combining %s '%s' ('%s/%s')",
                                        reader_type, obj.name,
                                        path, filename)
                            obj.combine(orig_obj)
                        else:
                            log.debug1("  Overloads %s '%s' ('%s/%s')",
                                       reader_type,
                                       orig_obj.name, orig_obj.path,
                                       orig_obj.filename)
                    elif obj.path.startswith(config.ETC_FIREWALLD):
                        obj.default = True
                        config_obj.default = True
                    self.config.add_zone(config_obj)
                    if combine:
                        log.debug1("  Combining %s '%s' ('%s/%s')",
                                   reader_type, combined_zone.name,
                                   path, filename)
                        combined_zone.combine(obj)
                    else:
                        self.zone.add_zone(obj)
                elif reader_type == "ipset":
                    obj = ipset_reader(filename, path)
                    if obj.name in self.ipset.get_ipsets():
                        orig_obj = self.ipset.get_ipset(obj.name)
                        log.debug1("  Overloads %s '%s' ('%s/%s')", reader_type,
                                   orig_obj.name, orig_obj.path,
                                   orig_obj.filename)
                        self.ipset.remove_ipset(orig_obj.name)
                    elif obj.path.startswith(config.ETC_FIREWALLD):
                        obj.default = True
                    try:
                        self.ipset.add_ipset(obj)
                    except FirewallError as error:
                        log.warning("%s: %s, ignoring for run-time." % \
                                    (obj.name, str(error)))
                    # add a deep copy to the configuration interface
                    self.config.add_ipset(copy.deepcopy(obj))
                elif reader_type == "helper":
                    obj = helper_reader(filename, path)
                    if obj.name in self.helper.get_helpers():
                        orig_obj = self.helper.get_helper(obj.name)
                        log.debug1("  Overloads %s '%s' ('%s/%s')", reader_type,
                                   orig_obj.name, orig_obj.path,
                                   orig_obj.filename)
                        self.helper.remove_helper(orig_obj.name)
                    elif obj.path.startswith(config.ETC_FIREWALLD):
                        obj.default = True
                    self.helper.add_helper(obj)
                    # add a deep copy to the configuration interface
                    self.config.add_helper(copy.deepcopy(obj))
                elif reader_type == "policy":
                    obj = policy_reader(filename, path)
                    if obj.name in self.policy.get_policies():
                        orig_obj = self.policy.get_policy(obj.name)
                        log.debug1("  Overloads %s '%s' ('%s/%s')", reader_type,
                                   orig_obj.name, orig_obj.path,
                                   orig_obj.filename)
                        self.policy.remove_policy(orig_obj.name)
                    elif obj.path.startswith(config.ETC_FIREWALLD):
                        obj.default = True
                    self.policy.add_policy(obj)
                    # add a deep copy to the configuration interface
                    self.config.add_policy_object(copy.deepcopy(obj))
                else:
                    log.fatal("Unknown reader type %s", reader_type)
            except FirewallError as msg:
                log.error("Failed to load %s file '%s': %s", reader_type,
                          name, msg)
            except Exception:
                log.error("Failed to load %s file '%s':", reader_type, name)
                log.exception()

        if combine and combined_zone.combined:
            if combined_zone.name in self.zone.get_zones():
                orig_obj = self.zone.get_zone(combined_zone.name)
                log.debug1("  Overloading and deactivating %s '%s' ('%s/%s')",
                           reader_type, orig_obj.name, orig_obj.path,
                           orig_obj.filename)
                try:
                    self.zone.remove_zone(combined_zone.name)
                except Exception:
                    pass
                self.config.forget_zone(combined_zone.name)
            self.zone.add_zone(combined_zone)

    def cleanup(self):
        self.icmptype.cleanup()
        self.service.cleanup()
        self.zone.cleanup()
        self.ipset.cleanup()
        self.helper.cleanup()
        self.config.cleanup()
        self.direct.cleanup()
        self.policies.cleanup()
        self.policy.cleanup()
        self._firewalld_conf.cleanup()
        self.__init_vars()

    def stop(self):
        if not self._offline:
            if self.cleanup_on_exit:
                self.flush()
                self.ipset.flush()
                self.set_policy("ACCEPT")

            if self.cleanup_modules_on_exit:
                log.debug1('Unloading firewall kernel modules')
                self.modules_backend.unload_firewall_modules()

        self.cleanup()

    # handle modules

    def handle_modules(self, _modules, enable):
        num_failed = 0
        error_msgs = ""
        for i,module in enumerate(_modules):
            if enable:
                (status, msg) = self.modules_backend.load_module(module)
            else:
                if self._module_refcount[module] > 1:
                    status = 0 # module referenced more then one, do not unload
                else:
                    (status, msg) = self.modules_backend.unload_module(module)
            if status != 0:
                num_failed += 1
                error_msgs += msg
                continue

            if enable:
                self._module_refcount.setdefault(module, 0)
                self._module_refcount[module] += 1
            else:
                if module in self._module_refcount:
                    self._module_refcount[module] -= 1
                    if self._module_refcount[module] == 0:
                        del self._module_refcount[module]
        return (num_failed, error_msgs)

    def _select_firewall_backend(self, backend):
        if backend != "nftables":
            self.nftables_enabled = False
        # even if using nftables, the other backends are enabled for use with
        # the direct interface. nftables is used for the firewalld primitives.

    def get_backend_by_name(self, name):
        for backend in self.all_backends():
            if backend.name == name:
                return backend
        raise FirewallError(errors.UNKNOWN_ERROR,
                            "'%s' backend does not exist" % name)

    def get_backend_by_ipv(self, ipv):
        if self.nftables_enabled:
            return self.nftables_backend
        if ipv == "ipv4" and self.ip4tables_enabled:
            return self.ip4tables_backend
        elif ipv == "ipv6" and self.ip6tables_enabled:
            return self.ip6tables_backend
        elif ipv == "eb" and self.ebtables_enabled:
            return self.ebtables_backend
        raise FirewallError(errors.INVALID_IPV,
                            "'%s' is not a valid backend or is unavailable" % ipv)

    def get_direct_backend_by_ipv(self, ipv):
        if ipv == "ipv4" and self.ip4tables_enabled:
            return self.ip4tables_backend
        elif ipv == "ipv6" and self.ip6tables_enabled:
            return self.ip6tables_backend
        elif ipv == "eb" and self.ebtables_enabled:
            return self.ebtables_backend
        raise FirewallError(errors.INVALID_IPV,
                            "'%s' is not a valid backend or is unavailable" % ipv)

    def is_backend_enabled(self, name):
        if name == "ip4tables":
            return self.ip4tables_enabled
        elif name == "ip6tables":
            return self.ip6tables_enabled
        elif name == "ebtables":
            return self.ebtables_enabled
        elif name == "nftables":
            return self.nftables_enabled
        return False

    def is_ipv_enabled(self, ipv):
        if self.nftables_enabled:
            return True
        if ipv == "ipv4":
            return self.ip4tables_enabled
        elif ipv == "ipv6":
            return self.ip6tables_enabled
        elif ipv == "eb":
            return self.ebtables_enabled
        return False

    def enabled_backends(self):
        backends = []
        if self.nftables_enabled:
            backends.append(self.nftables_backend)
        else:
            if self.ip4tables_enabled:
                backends.append(self.ip4tables_backend)
            if self.ip6tables_enabled:
                backends.append(self.ip6tables_backend)
            if self.ebtables_enabled:
                backends.append(self.ebtables_backend)
        return backends

    def all_backends(self):
        backends = []
        if self.ip4tables_enabled:
            backends.append(self.ip4tables_backend)
        if self.ip6tables_enabled:
            backends.append(self.ip6tables_backend)
        if self.ebtables_enabled:
            backends.append(self.ebtables_backend)
        if self.nftables_enabled:
            backends.append(self.nftables_backend)
        return backends

    def apply_default_tables(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for backend in self.enabled_backends():
            transaction.add_rules(backend, backend.build_default_tables())

        if use_transaction is None:
            transaction.execute(True)

    def apply_default_rules(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for backend in self.enabled_backends():
            rules = backend.build_default_rules(self._log_denied)
            transaction.add_rules(backend, rules)

        if self.is_ipv_enabled("ipv6"):
            ipv6_backend = self.get_backend_by_ipv("ipv6")
            if "raw" in ipv6_backend.get_available_tables():
                if self.ipv6_rpfilter_enabled:
                    rules = ipv6_backend.build_rpfilter_rules(self._log_denied)
                    transaction.add_rules(ipv6_backend, rules)

        if self.is_ipv_enabled("ipv6") and self._rfc3964_ipv4:
            rules = ipv6_backend.build_rfc3964_ipv4_rules()
            transaction.add_rules(ipv6_backend, rules)

        if use_transaction is None:
            transaction.execute(True)

    def may_skip_flush_direct_backends(self):
        if self.nftables_enabled and not self.direct.has_runtime_configuration():
            return True

        return False

    def flush_direct_backends(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for backend in self.all_backends():
            if backend in self.enabled_backends():
                continue
            rules = backend.build_flush_rules()
            transaction.add_rules(backend, rules)

        if use_transaction is None:
            transaction.execute(True)

    def flush(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        log.debug1("Flushing rule set")

        if not self.may_skip_flush_direct_backends():
            self.flush_direct_backends(use_transaction=transaction)

        for backend in self.enabled_backends():
            rules = backend.build_flush_rules()
            transaction.add_rules(backend, rules)

        if use_transaction is None:
            transaction.execute(True)

    def set_policy(self, policy, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        log.debug1("Setting policy to '%s'", policy)

        for backend in self.enabled_backends():
            rules = backend.build_set_policy_rules(policy)
            transaction.add_rules(backend, rules)

        if use_transaction is None:
            transaction.execute(True)

    # rule function used in handle_ functions

    def rule(self, backend_name, rule):
        if not rule:
            return ""

        backend = self.get_backend_by_name(backend_name)
        if not backend:
            raise FirewallError(errors.INVALID_IPV,
                                "'%s' is not a valid backend" % backend_name)

        if not self.is_backend_enabled(backend_name):
            return ""

        return backend.set_rule(rule, self._log_denied)

    def rules(self, backend_name, rules):
        _rules = list(filter(None, rules))

        backend = self.get_backend_by_name(backend_name)
        if not backend:
            raise FirewallError(errors.INVALID_IPV,
                                "'%s' is not a valid backend" % backend_name)

        if not self.is_backend_enabled(backend_name):
            return

        if self._individual_calls or \
           not backend.restore_command_exists or \
           (backend_name == "ebtables" and not self.ebtables_backend.restore_noflush_option):
            for i,rule in enumerate(_rules):
                try:
                    backend.set_rule(rule, self._log_denied)
                except Exception as msg:
                    log.debug1(traceback.format_exc())
                    log.error(msg)
                    for rule in reversed(_rules[:i]):
                        try:
                            backend.set_rule(backend.reverse_rule(rule), self._log_denied)
                        except Exception:
                            # ignore errors here
                            pass
                    raise msg
        else:
            backend.set_rules(_rules, self._log_denied)

    # check functions

    def check_panic(self):
        if self._panic:
            raise FirewallError(errors.PANIC_MODE)

    def check_policy(self, policy):
        _policy = policy
        if _policy not in self.policy.get_policies():
            raise FirewallError(errors.INVALID_POLICY, _policy)
        return _policy

    def check_zone(self, zone):
        _zone = zone
        if not _zone or _zone == "":
            _zone = self.get_default_zone()
        if _zone not in self.zone.get_zones():
            raise FirewallError(errors.INVALID_ZONE, _zone)
        return _zone

    def check_interface(self, interface):
        if not functions.checkInterface(interface):
            raise FirewallError(errors.INVALID_INTERFACE, interface)

    def check_service(self, service):
        self.service.check_service(service)

    def check_port(self, port):
        if not functions.check_port(port):
            raise FirewallError(errors.INVALID_PORT, port)

    def check_tcpudp(self, protocol):
        if not protocol:
            raise FirewallError(errors.MISSING_PROTOCOL)
        if protocol not in [ "tcp", "udp", "sctp", "dccp" ]:
            raise FirewallError(errors.INVALID_PROTOCOL,
                                "'%s' not in {'tcp'|'udp'|'sctp'|'dccp'}" % \
                                protocol)

    def check_ip(self, ip):
        if not functions.checkIP(ip):
            raise FirewallError(errors.INVALID_ADDR, ip)

    def check_address(self, ipv, source):
        if ipv == "ipv4":
            if not functions.checkIPnMask(source):
                raise FirewallError(errors.INVALID_ADDR, source)
        elif ipv == "ipv6":
            if not functions.checkIP6nMask(source):
                raise FirewallError(errors.INVALID_ADDR, source)
        else:
            raise FirewallError(errors.INVALID_IPV,
                                "'%s' not in {'ipv4'|'ipv6'}")

    def check_icmptype(self, icmp):
        self.icmptype.check_icmptype(icmp)

    def check_timeout(self, timeout):
        if not isinstance(timeout, int):
            raise TypeError("%s is %s, expected int" % (timeout, type(timeout)))
        if int(timeout) < 0:
            raise FirewallError(errors.INVALID_VALUE,
                                "timeout '%d' is not positive number" % timeout)

    # RELOAD

    def reload(self, stop=False):
        _panic = self._panic

        # must stash this. The value may change after _start()
        flush_all = self._flush_all_on_reload

        if not flush_all:
            # save zone interfaces
            _zone_interfaces = { }
            for zone in self.zone.get_zones():
                _zone_interfaces[zone] = self.zone.get_settings(zone)["interfaces"]
            # save direct config
            _direct_config = self.direct.get_runtime_config()
            _old_dz = self.get_default_zone()

        _ipset_objs = []
        for _name in self.ipset.get_ipsets():
            _ipset_objs.append(self.ipset.get_ipset(_name))

        if not _panic:
            self.set_policy("DROP")

        self.flush()
        self.cleanup()

        start_exception = None
        try:
            self._start(reload=True, complete_reload=stop)
        except Exception as e:
            # save the exception for later, but continue restoring interfaces,
            # etc. We'll re-raise it at the end.
            start_exception = e

        # destroy ipsets no longer in the permanent configuration
        if flush_all:
            for obj in _ipset_objs:
                if not self.ipset.query_ipset(obj.name):
                    for backend in self.ipset.backends():
                        # nftables sets are part of the normal firewall ruleset.
                        if backend.name == "nftables":
                            continue
                        backend.set_destroy(obj.name)

        if not flush_all:
            # handle interfaces in the default zone and move them to the new
            # default zone if it changed
            _new_dz = self.get_default_zone()
            if _new_dz != _old_dz:
                # if_new_dz has been introduced with the reload, we need to add it
                # https://github.com/firewalld/firewalld/issues/53
                if _new_dz not in _zone_interfaces:
                    _zone_interfaces[_new_dz] = { }
                # default zone changed. Move interfaces from old default zone to
                # the new one.
                for iface, settings in list(_zone_interfaces[_old_dz].items()):
                    if settings["__default__"]:
                        # move only those that were added to default zone
                        # (not those that were added to specific zone same as
                        # default)
                        _zone_interfaces[_new_dz][iface] = \
                            _zone_interfaces[_old_dz][iface]
                        del _zone_interfaces[_old_dz][iface]

            # add interfaces to zones again
            for zone in self.zone.get_zones():
                if zone in _zone_interfaces:

                    for interface_id in _zone_interfaces[zone]:
                        self.zone.change_zone_of_interface(zone, interface_id,
                                                           _zone_interfaces[zone][interface_id]["sender"])

                    del _zone_interfaces[zone]
                else:
                    log.info1("New zone '%s'.", zone)
            if len(_zone_interfaces) > 0:
                for zone in list(_zone_interfaces.keys()):
                    log.info1("Lost zone '%s', zone interfaces dropped.", zone)
                    del _zone_interfaces[zone]
            del _zone_interfaces

            # restore runtime-only ipsets
            for obj in _ipset_objs:
                if self.ipset.query_ipset(obj.name):
                    for entry in obj.entries:
                        try:
                            self.ipset.add_entry(obj.name, entry)
                        except FirewallError as msg:
                            if msg.code != errors.ALREADY_ENABLED:
                                raise msg
                else:
                    self.ipset.add_ipset(obj)
                    self.ipset.apply_ipset(obj.name)

            # restore direct config
            self.direct.set_config(_direct_config)

        # Restore permanent interfaces from NetworkManager
        nm_bus_name = nm_get_bus_name()
        if nm_bus_name:
            for zone in self.zone.get_zones() + [""]:
                for interface in nm_get_interfaces_in_zone(zone):
                    self.zone.change_zone_of_interface(zone, interface, sender=nm_bus_name)

        self._panic = _panic
        if not self._panic:
            self.set_policy("ACCEPT")

        if start_exception:
            self._state = "FAILED"
            raise start_exception
        else:
            self._state = "RUNNING"

    # STATE

    def get_state(self):
        return self._state

    # PANIC MODE

    def enable_panic_mode(self):
        if self._panic:
            raise FirewallError(errors.ALREADY_ENABLED,
                                "panic mode already enabled")

        try:
            self.set_policy("PANIC")
        except Exception as msg:
            raise FirewallError(errors.COMMAND_FAILED, msg)
        self._panic = True

    def disable_panic_mode(self):
        if not self._panic:
            raise FirewallError(errors.NOT_ENABLED,
                                "panic mode is not enabled")

        try:
            self.set_policy("ACCEPT")
        except Exception as msg:
            raise FirewallError(errors.COMMAND_FAILED, msg)
        self._panic = False

    def query_panic_mode(self):
        return self._panic

    # LOG DENIED

    def get_log_denied(self):
        return self._log_denied

    def set_log_denied(self, value):
        if value not in config.LOG_DENIED_VALUES:
            raise FirewallError(errors.INVALID_VALUE,
                                "'%s', choose from '%s'" % \
                                (value, "','".join(config.LOG_DENIED_VALUES)))

        if value != self.get_log_denied():
            self._log_denied = value
            self._firewalld_conf.set("LogDenied", value)
            self._firewalld_conf.write()
        else:
            raise FirewallError(errors.ALREADY_SET, value)

    # DEFAULT ZONE

    def get_default_zone(self):
        return self._default_zone

    def set_default_zone(self, zone):
        _zone = self.check_zone(zone)
        if _zone != self._default_zone:
            _old_dz = self._default_zone
            self._default_zone = _zone
            self._firewalld_conf.set("DefaultZone", _zone)
            self._firewalld_conf.write()

            # remove old default zone from ZONES and add new default zone
            self.zone.change_default_zone(_old_dz, _zone)

            # Move interfaces from old default zone to the new one.
            _old_dz_settings = self.zone.get_settings(_old_dz)
            for iface, settings in list(_old_dz_settings["interfaces"].items()):
                if settings["__default__"]:
                    # move only those that were added to default zone
                    # (not those that were added to specific zone same as default)
                    self.zone.change_zone_of_interface("", iface)
        else:
            raise FirewallError(errors.ZONE_ALREADY_SET, _zone)

    def combine_runtime_with_permanent_settings(self, permanent, runtime):
        combined = permanent.copy()

        for key,value in runtime.items():
            # omit empty entries
            if value or isinstance(value, bool):
                combined[key] = value
            # make sure to remove values that were in permanent, but no
            # longer in runtime.
            elif key in combined:
                del combined[key]

        return combined

    def get_added_and_removed_settings(self, old_settings, new_settings):
        add_settings = {}
        remove_settings = {}
        for key in (set(old_settings.keys()) | set(new_settings.keys())):
            if key in new_settings:
                if isinstance(new_settings[key], list):
                    old = set(old_settings[key] if key in old_settings else [])
                    add_settings[key] = list(set(new_settings[key]) - old)
                    remove_settings[key] = list((old ^ set(new_settings[key])) & old)
                # check for bool or int because dbus.Boolean is a subclass of
                # int (because bool can't be subclassed).
                elif isinstance(new_settings[key], bool) or isinstance(new_settings[key], int):
                    if not old_settings[key] and new_settings[key]:
                        add_settings[key] = True
                    elif old_settings[key] and not new_settings[key]:
                        remove_settings[key] = False
                else:
                    raise FirewallError(errors.INVALID_SETTING, "Unhandled setting type {} key {}".format(type(new_settings[key]), key))

        return (add_settings, remove_settings)
base.py000064400000004066151731527130006043 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""Base firewall settings"""

DEFAULT_ZONE_TARGET = "{chain}_{zone}"
DEFAULT_POLICY_TARGET = "CONTINUE"
DEFAULT_POLICY_PRIORITY = -1

ZONE_TARGETS = [ "ACCEPT", "%%REJECT%%", "DROP", DEFAULT_ZONE_TARGET,
                 "default" ]

POLICY_TARGETS = [ "ACCEPT", "REJECT", "DROP", "CONTINUE" ]

SHORTCUTS = {
    "PREROUTING": "PRE",
    "POSTROUTING": "POST",
    "INPUT": "IN",
    "FORWARD_IN": "FWDI",
    "FORWARD_OUT": "FWDO",
    "OUTPUT": "OUT",
}

REJECT_TYPES = {
    "ipv4": [ "icmp-host-prohibited", "host-prohib", "icmp-net-unreachable",
              "net-unreach", "icmp-host-unreachable", "host-unreach",
              "icmp-port-unreachable", "port-unreach", "icmp-proto-unreachable",
              "proto-unreach", "icmp-net-prohibited", "net-prohib", "tcp-reset",
              "tcp-rst", "icmp-admin-prohibited", "admin-prohib" ],
    "ipv6": [ "icmp6-adm-prohibited", "adm-prohibited", "icmp6-no-route",
              "no-route", "icmp6-addr-unreachable", "addr-unreach",
              "icmp6-port-unreachable", "port-unreach", "tcp-reset" ]
}

# ipset types that can be used as a source in zones
# The match-set option will be src or src,src according to the
# dimension of the ipset.
SOURCE_IPSET_TYPES = [
    "hash:ip", "hash:ip,port", "hash:ip,mark",
    "hash:net", "hash:net,port", "hash:net,iface",
    "hash:mac"
]
fw_service.py000064400000003147151731527140007265 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "FirewallService" ]

from firewall import errors
from firewall.errors import FirewallError

class FirewallService(object):
    def __init__(self, fw):
        self._fw = fw
        self._services = { }

    def __repr__(self):
        return '%s(%r)' % (self.__class__, self._services)

    def cleanup(self):
        self._services.clear()

    # zones

    def get_services(self):
        return sorted(self._services.keys())

    def check_service(self, service):
        if service not in self._services:
            raise FirewallError(errors.INVALID_SERVICE, service)

    def get_service(self, service):
        self.check_service(service)
        return self._services[service]

    def add_service(self, obj):
        self._services[obj.name] = obj

    def remove_service(self, service):
        self.check_service(service)
        del self._services[service]
rich.py000064400000102070151731527140006051 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2013-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "Rich_Source", "Rich_Destination", "Rich_Service", "Rich_Port",
            "Rich_Protocol", "Rich_Masquerade", "Rich_IcmpBlock",
            "Rich_IcmpType",
            "Rich_SourcePort", "Rich_ForwardPort", "Rich_Log", "Rich_Audit",
            "Rich_Accept", "Rich_Reject", "Rich_Drop", "Rich_Mark",
            "Rich_Limit", "Rich_Rule" ]

from firewall import functions
from firewall.core.ipset import check_ipset_name
from firewall.core.base import REJECT_TYPES
from firewall import errors
from firewall.errors import FirewallError

class Rich_Source(object):
    def __init__(self, addr, mac, ipset, invert=False):
        self.addr = addr
        if self.addr == "":
            self.addr = None
        self.mac = mac
        if self.mac == "" or self.mac is None:
            self.mac = None
        elif self.mac is not None:
            self.mac = self.mac.upper()
        self.ipset = ipset
        if self.ipset == "":
            self.ipset = None
        self.invert = invert
        if self.addr is None and self.mac is None and self.ipset is None:
            raise FirewallError(errors.INVALID_RULE,
                                "no address, mac and ipset")

    def __str__(self):
        ret = 'source%s ' % (" NOT" if self.invert else "")
        if self.addr is not None:
            return ret + 'address="%s"' % self.addr
        elif self.mac is not None:
            return ret + 'mac="%s"' % self.mac
        elif self.ipset is not None:
            return ret + 'ipset="%s"' % self.ipset
        else:
            raise FirewallError(errors.INVALID_RULE,
                                "no address, mac and ipset")

class Rich_Destination(object):
    def __init__(self, addr, ipset, invert=False):
        self.addr = addr
        if self.addr == "":
            self.addr = None
        self.ipset = ipset
        if self.ipset == "":
            self.ipset = None
        self.invert = invert
        if self.addr is None and self.ipset is None:
            raise FirewallError(errors.INVALID_RULE,
                                "no address and ipset")

    def __str__(self):
        ret = 'destination%s ' % (" NOT" if self.invert else "")
        if self.addr is not None:
            return ret + 'address="%s"' % self.addr
        elif self.ipset is not None:
            return ret + 'ipset="%s"' % self.ipset
        else:
            raise FirewallError(errors.INVALID_RULE,
                                "no address and ipset")

class Rich_Service(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'service name="%s"' % (self.name)

class Rich_Port(object):
    def __init__(self, port, protocol):
        self.port = port
        self.protocol = protocol

    def __str__(self):
        return 'port port="%s" protocol="%s"' % (self.port, self.protocol)

class Rich_SourcePort(Rich_Port):
    def __str__(self):
        return 'source-port port="%s" protocol="%s"' % (self.port,
                                                        self.protocol)

class Rich_Protocol(object):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return 'protocol value="%s"' % (self.value)

class Rich_Masquerade(object):
    def __init__(self):
        pass

    def __str__(self):
        return 'masquerade'

class Rich_IcmpBlock(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'icmp-block name="%s"' % (self.name)

class Rich_IcmpType(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'icmp-type name="%s"' % (self.name)

class Rich_ForwardPort(object):
    def __init__(self, port, protocol, to_port, to_address):
        self.port = port
        self.protocol = protocol
        self.to_port = to_port
        self.to_address = to_address
        # replace None with "" in to_port and/or to_address
        if self.to_port is None:
            self.to_port = ""
        if self.to_address is None:
            self.to_address = ""

    def __str__(self):
        return 'forward-port port="%s" protocol="%s"%s%s' % \
            (self.port, self.protocol,
             ' to-port="%s"' % self.to_port if self.to_port != "" else '',
             ' to-addr="%s"' % self.to_address if self.to_address != "" else '')

class Rich_Log(object):
    def __init__(self, prefix=None, level=None, limit=None):
        #TODO check default level in iptables
        self.prefix = prefix
        self.level = level
        self.limit = limit

    def __str__(self):
        return 'log%s%s%s' % \
            (' prefix="%s"' % (self.prefix) if self.prefix else "",
             ' level="%s"' % (self.level) if self.level else "",
             " %s" % self.limit if self.limit else "")

class Rich_Audit(object):
    def __init__(self, limit=None):
        #TODO check default level in iptables
        self.limit = limit

    def __str__(self):
        return 'audit%s' % (" %s" % self.limit if self.limit else "")

class Rich_Accept(object):
    def __init__(self, limit=None):
        self.limit = limit

    def __str__(self):
        return "accept%s" % (" %s" % self.limit if self.limit else "")

class Rich_Reject(object):
    def __init__(self, _type=None, limit=None):
        self.type = _type
        self.limit = limit

    def __str__(self):
        return "reject%s%s" % (' type="%s"' % self.type if self.type else "",
                               " %s" % self.limit if self.limit else "")

    def check(self, family):
        if self.type:
            if not family:
                raise FirewallError(errors.INVALID_RULE, "When using reject type you must specify also rule family.")
            if family in ['ipv4', 'ipv6'] and \
               self.type not in REJECT_TYPES[family]:
                valid_types = ", ".join(REJECT_TYPES[family])
                raise FirewallError(errors.INVALID_RULE, "Wrong reject type %s.\nUse one of: %s." % (self.type, valid_types))

class Rich_Drop(Rich_Accept):
    def __str__(self):
        return "drop%s" % (" %s" % self.limit if self.limit else "")


class Rich_Mark(object):
    def __init__(self, _set, limit=None):
        self.set = _set
        self.limit = limit

    def __str__(self):
        return "mark set=%s%s" % (self.set,
                                  " %s" % self.limit if self.limit else "")

    def check(self):
        if self.set is not None:
            x = self.set
        else:
            raise FirewallError(errors.INVALID_MARK, "no value set")

        if "/" in x:
            splits = x.split("/")
            if len(splits) != 2:
                raise FirewallError(errors.INVALID_MARK, x)
            if not functions.checkUINT32(splits[0]) or \
               not functions.checkUINT32(splits[1]):
                # value and mask are uint32
                raise FirewallError(errors.INVALID_MARK, x)
        else:
            if not functions.checkUINT32(x):
                # value is uint32
                raise FirewallError(errors.INVALID_MARK, x)

DURATION_TO_MULT = {
    "s": 1,
    "m": 60,
    "h": 60 * 60,
    "d": 24 * 60 * 60,
}

class Rich_Limit(object):
    def __init__(self, value, burst=None):
        self.value = value
        self.burst = burst

    def check(self):
        self.value_parse()
        self.burst_parse()

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        if value is None:
            self._value = None
            return
        try:
            rate, duration = self._value_parse(value)
        except FirewallError:
            # The value is invalid. We cannot normalize it.
            v = value
        else:
            v = f"{rate}/{duration}"
        if getattr(self, "_value", None) != v:
            self._value = v

    @property
    def burst(self):
        return self._burst

    @burst.setter
    def burst(self, burst):
        if burst is None:
            self._burst = None
            return
        try:
            b = self._burst_parse(burst)
        except FirewallError:
            b = burst
        else:
            b = str(burst)
        if getattr(self, "_burst", None) != b:
            self._burst = b

    @staticmethod
    def _value_parse(value):
        splits = None
        if "/" in value:
            splits = value.split("/")
        if not splits or len(splits) != 2:
            raise FirewallError(errors.INVALID_LIMIT, value)
        (rate, duration) = splits
        try:
            rate = int(rate)
        except:
            raise FirewallError(errors.INVALID_LIMIT, value)

        if duration in ["second", "minute", "hour", "day"]:
            duration = duration[:1]

        if rate < 1 or duration not in ["s", "m", "h", "d"]:
            raise FirewallError(errors.INVALID_LIMIT, value)

        if 10000 * DURATION_TO_MULT[duration] // rate == 0:
            raise FirewallError(errors.INVALID_LIMIT, "%s too fast" % (value,))

        if rate == 1 and duration == "d":
            # iptables (v1.4.21) doesn't accept 1/d
            raise FirewallError(errors.INVALID_LIMIT, "%s too slow" % (value,))

        return rate, duration

    def value_parse(self):
        return self._value_parse(self._value)

    @staticmethod
    def _burst_parse(burst):
        if burst is None:
            return None
        try:
            b = int(burst)
        except:
            raise FirewallError(errors.INVALID_LIMIT, burst)

        if b < 1 or b > 10_000_000:
            raise FirewallError(errors.INVALID_LIMIT, burst)

        return b

    def burst_parse(self):
        return self._burst_parse(self._burst)

    def __str__(self):
        s = f'limit value="{self._value}"'
        if self._burst is not None:
            s += f" burst={self._burst}"
        return s

class Rich_Rule(object):
    priority_min = -32768
    priority_max =  32767

    def __init__(self, family=None, rule_str=None, priority=0):
        if family is not None:
            self.family = str(family)
        else:
            self.family = None

        self.priority = priority
        self.source = None
        self.destination = None
        self.element = None
        self.log = None
        self.audit = None
        self.action = None

        if rule_str:
            self._import_from_string(rule_str)

    def _lexer(self, rule_str):
        """ Lexical analysis """
        tokens = []

        for r in functions.splitArgs(rule_str):
            if "=" in r:
                attr = r.split('=')
                if len(attr) != 2 or not attr[0] or not attr[1]:
                    raise FirewallError(errors.INVALID_RULE,
                                        'internal error in _lexer(): %s' % r)
                tokens.append({'attr_name':attr[0], 'attr_value':attr[1]})
            else:
                tokens.append({'element':r})
        tokens.append({'element':'EOL'})

        return tokens

    def _import_from_string(self, rule_str):
        if not rule_str:
            raise FirewallError(errors.INVALID_RULE, 'empty rule')

        rule_str = functions.stripNonPrintableCharacters(rule_str)

        self.priority = 0
        self.family = None
        self.source = None
        self.destination = None
        self.element = None
        self.log = None
        self.audit = None
        self.action = None

        tokens = self._lexer(rule_str)
        if tokens and tokens[0].get('element')  == 'EOL':
            raise FirewallError(errors.INVALID_RULE, 'empty rule')

        attrs = {}       # attributes of elements
        in_elements = [] # stack with elements we are in
        index = 0        # index into tokens
        while not (tokens[index].get('element')  == 'EOL' and in_elements == ['rule']):
            element = tokens[index].get('element')
            attr_name = tokens[index].get('attr_name')
            attr_value = tokens[index].get('attr_value')
            #print ("in_elements: ", in_elements)
            #print ("index: %s, element: %s, attribute: %s=%s" % (index, element, attr_name, attr_value))
            if attr_name:     # attribute
                if attr_name not in ['priority', 'family', 'address', 'mac', 'ipset',
                                     'invert', 'value',
                                     'port', 'protocol', 'to-port', 'to-addr',
                                     'name', 'prefix', 'level', 'type',
                                     'set', 'burst']:
                    raise FirewallError(errors.INVALID_RULE, "bad attribute '%s'" % attr_name)
            else:             # element
                if element in ['rule', 'source', 'destination', 'protocol',
                               'service', 'port', 'icmp-block', 'icmp-type', 'masquerade',
                               'forward-port', 'source-port', 'log', 'audit',
                               'accept', 'drop', 'reject', 'mark', 'limit', 'not', 'NOT', 'EOL']:
                    if element == 'source' and self.source:
                        raise FirewallError(errors.INVALID_RULE, "more than one 'source' element")
                    elif element == 'destination' and self.destination:
                        raise FirewallError(errors.INVALID_RULE, "more than one 'destination' element")
                    elif element in ['protocol', 'service', 'port',
                                     'icmp-block', 'icmp-type',
                                     'masquerade', 'forward-port',
                                     'source-port'] and self.element:
                        raise FirewallError(errors.INVALID_RULE, "more than one element. There cannot be both '%s' and '%s' in one rule." % (element, self.element))
                    elif element == 'log' and self.log:
                        raise FirewallError(errors.INVALID_RULE, "more than one 'log' element")
                    elif element == 'audit' and self.audit:
                        raise FirewallError(errors.INVALID_RULE, "more than one 'audit' element")
                    elif element in ['accept', 'drop', 'reject', 'mark'] and self.action:
                        raise FirewallError(errors.INVALID_RULE, "more than one 'action' element. There cannot be both '%s' and '%s' in one rule." % (element, self.action))
                else:
                    raise FirewallError(errors.INVALID_RULE, "unknown element %s" % element)

            in_element = in_elements[len(in_elements)-1] if len(in_elements) > 0 else ''

            if in_element == '':
                if not element and attr_name:
                    if attr_name == 'family':
                        raise FirewallError(errors.INVALID_RULE, "'family' outside of rule. Use 'rule family=...'.")
                    elif attr_name == 'priority':
                        raise FirewallError(errors.INVALID_RULE, "'priority' outside of rule. Use 'rule priority=...'.")
                    else:
                        raise FirewallError(errors.INVALID_RULE, "'%s' outside of any element. Use 'rule <element> %s= ...'." % (attr_name, attr_name))
                elif 'rule' not in element:
                    raise FirewallError(errors.INVALID_RULE, "'%s' outside of rule. Use 'rule ... %s ...'." % (element, element))
                else:
                    in_elements.append('rule') # push into stack
            elif in_element == 'rule':
                if attr_name == 'family':
                    if attr_value not in ['ipv4', 'ipv6']:
                        raise FirewallError(errors.INVALID_RULE, "'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead." % attr_value)
                    self.family = attr_value
                elif attr_name == 'priority':
                    try:
                        self.priority = int(attr_value)
                    except ValueError:
                        raise FirewallError(errors.INVALID_PRIORITY, "invalid 'priority' attribute value '%s'." % attr_value)
                elif attr_name:
                    if attr_name == 'protocol':
                        err_msg = "wrong 'protocol' usage. Use either 'rule protocol value=...' or  'rule [forward-]port protocol=...'."
                    else:
                        err_msg = "attribute '%s' outside of any element. Use 'rule <element> %s= ...'." % (attr_name, attr_name)
                    raise FirewallError(errors.INVALID_RULE, err_msg)
                else:
                    in_elements.append(element) # push into stack
            elif in_element == 'source':
                if attr_name in ['address', 'mac', 'ipset', 'invert']:
                    attrs[attr_name] = attr_value
                elif element in ['not', 'NOT']:
                    attrs['invert'] = True
                else:
                    self.source = Rich_Source(attrs.get('address'), attrs.get('mac'), attrs.get('ipset'), attrs.get('invert', False))
                    in_elements.pop() # source
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'destination':
                if attr_name in ['address', 'ipset', 'invert']:
                    attrs[attr_name] = attr_value
                elif element in ['not', 'NOT']:
                    attrs['invert'] = True
                else:
                    self.destination = Rich_Destination(attrs.get('address'), attrs.get('ipset'), attrs.get('invert', False))
                    in_elements.pop() # destination
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'protocol':
                if attr_name == 'value':
                    self.element = Rich_Protocol(attr_value)
                    in_elements.pop() # protocol
                else:
                    raise FirewallError(errors.INVALID_RULE, "invalid 'protocol' element")
            elif in_element == 'service':
                if attr_name == 'name':
                    self.element = Rich_Service(attr_value)
                    in_elements.pop() # service
                else:
                    raise FirewallError(errors.INVALID_RULE, "invalid 'service' element")
            elif in_element == 'port':
                if attr_name in ['port', 'protocol']:
                    attrs[attr_name] = attr_value
                else:
                    self.element = Rich_Port(attrs.get('port'), attrs.get('protocol'))
                    in_elements.pop() # port
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'icmp-block':
                if attr_name == 'name':
                    self.element = Rich_IcmpBlock(attr_value)
                    in_elements.pop() # icmp-block
                else:
                    raise FirewallError(errors.INVALID_RULE, "invalid 'icmp-block' element")
            elif in_element == 'icmp-type':
                if attr_name == 'name':
                    self.element = Rich_IcmpType(attr_value)
                    in_elements.pop() # icmp-type
                else:
                    raise FirewallError(errors.INVALID_RULE, "invalid 'icmp-type' element")
            elif in_element == 'masquerade':
                self.element = Rich_Masquerade()
                in_elements.pop()
                attrs.clear()
                index = index -1 # return token to input
            elif in_element == 'forward-port':
                if attr_name in ['port', 'protocol', 'to-port', 'to-addr']:
                    attrs[attr_name] = attr_value
                else:
                    self.element = Rich_ForwardPort(attrs.get('port'), attrs.get('protocol'), attrs.get('to-port'), attrs.get('to-addr'))
                    in_elements.pop() # forward-port
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'source-port':
                if attr_name in ['port', 'protocol']:
                    attrs[attr_name] = attr_value
                else:
                    self.element = Rich_SourcePort(attrs.get('port'), attrs.get('protocol'))
                    in_elements.pop() # source-port
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'log':
                if attr_name in ['prefix', 'level']:
                    attrs[attr_name] = attr_value
                elif element == 'limit':
                    in_elements.append('limit')
                else:
                    self.log = Rich_Log(attrs.get('prefix'), attrs.get('level'), attrs.get('limit'))
                    in_elements.pop() # log
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'audit':
                if element == 'limit':
                    in_elements.append('limit')
                else:
                    self.audit = Rich_Audit(attrs.get('limit'))
                    in_elements.pop() # audit
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'accept':
                if element == 'limit':
                    in_elements.append('limit')
                else:
                    self.action = Rich_Accept(attrs.get('limit'))
                    in_elements.pop() # accept
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'drop':
                if element == 'limit':
                    in_elements.append('limit')
                else:
                    self.action = Rich_Drop(attrs.get('limit'))
                    in_elements.pop() # drop
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'reject':
                if attr_name == 'type':
                    attrs[attr_name] = attr_value
                elif element == 'limit':
                    in_elements.append('limit')
                else:
                    self.action = Rich_Reject(attrs.get('type'), attrs.get('limit'))
                    in_elements.pop() # accept
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'mark':
                if attr_name == 'set':
                    attrs[attr_name] = attr_value
                elif element == 'limit':
                    in_elements.append('limit')
                else:
                    self.action = Rich_Mark(attrs.get('set'),
                                            attrs.get('limit'))
                    in_elements.pop() # accept
                    attrs.clear()
                    index = index -1 # return token to input
            elif in_element == 'limit':
                if attr_name in ["value", "burst"]:
                    attrs[f"limit.{attr_name}"] = attr_value
                else:
                    if "limit.value" not in attrs:
                        raise FirewallError(
                            errors.INVALID_RULE, "invalid 'limit' element"
                        )
                    attrs["limit"] = Rich_Limit(
                        attrs["limit.value"], attrs.get("limit.burst")
                    )
                    attrs.pop("limit.value", None)
                    attrs.pop("limit.burst", None)
                    in_elements.pop()  # limit
                    index = index - 1  # return token to input

            index = index + 1

        self.check()

    def check(self):
        if self.family is not None and self.family not in [ "ipv4", "ipv6" ]:
            raise FirewallError(errors.INVALID_FAMILY, self.family)
        if self.family is None:
            if (self.source is not None and self.source.addr is not None) or \
               self.destination is not None:
                raise FirewallError(errors.MISSING_FAMILY)
            if type(self.element) == Rich_ForwardPort:
                raise FirewallError(errors.MISSING_FAMILY)

        if self.priority < self.priority_min or self.priority > self.priority_max:
            raise FirewallError(errors.INVALID_PRIORITY, "'priority' attribute must be between %d and %d." \
                                                         % (self.priority_min, self.priority_max))

        if self.element is None and \
           (self.log is None or (self.log is not None and self.priority == 0)):
            if self.action is None:
                raise FirewallError(errors.INVALID_RULE, "no element, no action")
            if self.source is None and self.destination is None and self.priority == 0:
                raise FirewallError(errors.INVALID_RULE, "no element, no source, no destination")

        if type(self.element) not in [ Rich_IcmpBlock,
                                       Rich_ForwardPort,
                                       Rich_Masquerade ]:
            if self.log is None and self.audit is None and \
                    self.action is None:
                raise FirewallError(errors.INVALID_RULE, "no action, no log, no audit")

        # source
        if self.source is not None:
            if self.source.addr is not None:
                if self.family is None:
                    raise FirewallError(errors.INVALID_FAMILY)
                if self.source.mac is not None:
                    raise FirewallError(errors.INVALID_RULE, "address and mac")
                if self.source.ipset is not None:
                    raise FirewallError(errors.INVALID_RULE, "address and ipset")
                if not functions.check_address(self.family, self.source.addr):
                    raise FirewallError(errors.INVALID_ADDR, str(self.source.addr))

            elif self.source.mac is not None:
                if self.source.ipset is not None:
                    raise FirewallError(errors.INVALID_RULE, "mac and ipset")
                if not functions.check_mac(self.source.mac):
                    raise FirewallError(errors.INVALID_MAC, str(self.source.mac))

            elif self.source.ipset is not None:
                if not check_ipset_name(self.source.ipset):
                    raise FirewallError(errors.INVALID_IPSET, str(self.source.ipset))

            else:
                raise FirewallError(errors.INVALID_RULE, "invalid source")

        # destination
        if self.destination is not None:
            if self.destination.addr is not None:
                if self.family is None:
                    raise FirewallError(errors.INVALID_FAMILY)
                if self.destination.ipset is not None:
                    raise FirewallError(errors.INVALID_DESTINATION, "address and ipset")
                if not functions.check_address(self.family, self.destination.addr):
                    raise FirewallError(errors.INVALID_ADDR, str(self.destination.addr))

            elif self.destination.ipset is not None:
                if not check_ipset_name(self.destination.ipset):
                    raise FirewallError(errors.INVALID_IPSET, str(self.destination.ipset))

            else:
                raise FirewallError(errors.INVALID_RULE, "invalid destination")

        # service
        if type(self.element) == Rich_Service:
            # service availability needs to be checked in Firewall, here is no
            # knowledge about this, therefore only simple check
            if self.element.name is None or len(self.element.name) < 1:
                raise FirewallError(errors.INVALID_SERVICE, str(self.element.name))

        # port
        elif type(self.element) == Rich_Port:
            if not functions.check_port(self.element.port):
                raise FirewallError(errors.INVALID_PORT, self.element.port)
            if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]:
                raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol)

        # protocol
        elif type(self.element) == Rich_Protocol:
            if not functions.checkProtocol(self.element.value):
                raise FirewallError(errors.INVALID_PROTOCOL, self.element.value)

        # masquerade
        elif type(self.element) == Rich_Masquerade:
            if self.action is not None:
                raise FirewallError(errors.INVALID_RULE, "masquerade and action")
            if self.source is not None and self.source.mac is not None:
                raise FirewallError(errors.INVALID_RULE, "masquerade and mac source")

        # icmp-block
        elif type(self.element) == Rich_IcmpBlock:
            # icmp type availability needs to be checked in Firewall, here is no
            # knowledge about this, therefore only simple check
            if self.element.name is None or len(self.element.name) < 1:
                raise FirewallError(errors.INVALID_ICMPTYPE, str(self.element.name))
            if self.action:
                raise FirewallError(errors.INVALID_RULE, "icmp-block and action")

        # icmp-type
        elif type(self.element) == Rich_IcmpType:
            # icmp type availability needs to be checked in Firewall, here is no
            # knowledge about this, therefore only simple check
            if self.element.name is None or len(self.element.name) < 1:
                raise FirewallError(errors.INVALID_ICMPTYPE, str(self.element.name))

        # forward-port
        elif type(self.element) == Rich_ForwardPort:
            if not functions.check_port(self.element.port):
                raise FirewallError(errors.INVALID_PORT, self.element.port)
            if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]:
                raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol)
            if self.element.to_port == "" and self.element.to_address == "":
                raise FirewallError(errors.INVALID_PORT, self.element.to_port)
            if self.element.to_port != "" and \
                    not functions.check_port(self.element.to_port):
                raise FirewallError(errors.INVALID_PORT, self.element.to_port)
            if self.element.to_address != "" and \
                    not functions.check_single_address(self.family,
                                                       self.element.to_address):
                raise FirewallError(errors.INVALID_ADDR, self.element.to_address)
            if self.family is None:
                raise FirewallError(errors.INVALID_FAMILY)
            if self.action is not None:
                raise FirewallError(errors.INVALID_RULE, "forward-port and action")

        # source-port
        elif type(self.element) == Rich_SourcePort:
            if not functions.check_port(self.element.port):
                raise FirewallError(errors.INVALID_PORT, self.element.port)
            if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]:
                raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol)

        # other element and not empty?
        elif self.element is not None:
            raise FirewallError(errors.INVALID_RULE, "Unknown element %s" % 
                                type(self.element))

        # log
        if self.log is not None:
            if self.log.level and \
               self.log.level not in [ "emerg", "alert", "crit", "error",
                                       "warning", "notice", "info", "debug" ]:
                raise FirewallError(errors.INVALID_LOG_LEVEL, self.log.level)

            if self.log.limit is not None:
                self.log.limit.check()

        # audit
        if self.audit is not None:
            if type(self.action) not in [ Rich_Accept, Rich_Reject, Rich_Drop ]:
                raise FirewallError(errors.INVALID_AUDIT_TYPE, type(self.action))

            if self.audit.limit is not None:
                self.audit.limit.check()

        # action
        if self.action is not None:
            if type(self.action) == Rich_Reject:
                self.action.check(self.family)
            elif type(self.action) == Rich_Mark:
                self.action.check()

            if self.action.limit is not None:
                self.action.limit.check()

    def __str__(self):
        ret = 'rule'
        if self.priority:
            ret += ' priority="%d"' % self.priority
        if self.family:
            ret += ' family="%s"' % self.family
        if self.source:
            ret += " %s" % self.source
        if self.destination:
            ret += " %s" % self.destination
        if self.element:
            ret += " %s" % self.element
        if self.log:
            ret += " %s" % self.log
        if self.audit:
            ret += " %s" % self.audit
        if self.action:
            ret += " %s" % self.action

        return (functions.u2b(ret)) if functions.PY2 else ret


#class Rich_RawRule(object):
#class Rich_RuleSet(object):
#class Rich_AddressList(object):
nftables.py000064400000305427151731527140006735 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 Red Hat, Inc.
#
# Authors:
# Eric Garver <e@erig.me>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import

import copy
import json
import ipaddress

from firewall.core.logger import log
from firewall.functions import check_mac, getPortRange, normalizeIP6, \
                               check_single_address, check_address
from firewall.errors import FirewallError, UNKNOWN_ERROR, INVALID_RULE, \
                            INVALID_ICMPTYPE, INVALID_TYPE, INVALID_ENTRY, \
                            INVALID_PORT
from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark, \
                               Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock
from nftables.nftables import Nftables

TABLE_NAME = "firewalld"
TABLE_NAME_POLICY = TABLE_NAME + "_" + "policy_drop"
POLICY_CHAIN_PREFIX = "policy_"

# Map iptables (table, chain) to hooks and priorities.
# These are well defined by NF_IP_PRI_* defines in netfilter.
#
# This is analogous to ipXtables.BUILT_IN_CHAINS, but we omit the chains that
# are only used for direct rules.
#
# Note: All hooks use their standard position + NFT_HOOK_OFFSET. This means
# iptables will have DROP precedence. It also means that even if iptables
# ACCEPTs a packet it may still be dropped later by firewalld's rules.
#
NFT_HOOK_OFFSET = 10
IPTABLES_TO_NFT_HOOK = {
    #"security": {
    #    "INPUT": ("input", 50 + NFT_HOOK_OFFSET),
    #    "OUTPUT": ("output", 50 + NFT_HOOK_OFFSET),
    #    "FORWARD": ("forward", 50 + NFT_HOOK_OFFSET),
    #},
    "raw": {
    #   "PREROUTING": ("prerouting", -300 + NFT_HOOK_OFFSET),
    #   "OUTPUT": ("output", -300 + NFT_HOOK_OFFSET),
    },
    "mangle": {
        "PREROUTING": ("prerouting", -150 + NFT_HOOK_OFFSET),
    #    "POSTROUTING": ("postrouting", -150 + NFT_HOOK_OFFSET),
    #    "INPUT": ("input", -150 + NFT_HOOK_OFFSET),
    #    "OUTPUT": ("output", -150 + NFT_HOOK_OFFSET),
    #    "FORWARD": ("forward", -150 + NFT_HOOK_OFFSET),
    },
    "nat": {
        "PREROUTING": ("prerouting", -100 + NFT_HOOK_OFFSET),
        "POSTROUTING": ("postrouting", 100 + NFT_HOOK_OFFSET),
    #    "INPUT": ("input", 100 + NFT_HOOK_OFFSET),
    #    "OUTPUT": ("output", -100 + NFT_HOOK_OFFSET),
    },
    "filter": {
        "PREROUTING": ("prerouting", 0 + NFT_HOOK_OFFSET),
        "INPUT": ("input", 0 + NFT_HOOK_OFFSET),
        "FORWARD": ("forward", 0 + NFT_HOOK_OFFSET),
        "OUTPUT": ("output", 0 + NFT_HOOK_OFFSET),
    },
}

def _icmp_types_fragments(protocol, type, code=None):
    fragments = [{"match": {"left": {"payload": {"protocol": protocol, "field": "type"}},
                            "op": "==",
                            "right": type}}]
    if code is not None:
        fragments.append({"match": {"left": {"payload": {"protocol": protocol, "field": "code"}},
                                    "op": "==",
                                    "right": code}})
    return fragments

# Most ICMP types are provided by nft, but for the codes we have to use numeric
# values.
#
ICMP_TYPES_FRAGMENTS = {
    "ipv4": {
        "communication-prohibited":     _icmp_types_fragments("icmp", "destination-unreachable", 13),
        "destination-unreachable":      _icmp_types_fragments("icmp", "destination-unreachable"),
        "echo-reply":                   _icmp_types_fragments("icmp", "echo-reply"),
        "echo-request":                 _icmp_types_fragments("icmp", "echo-request"),
        "fragmentation-needed":         _icmp_types_fragments("icmp", "destination-unreachable", 4),
        "host-precedence-violation":    _icmp_types_fragments("icmp", "destination-unreachable", 14),
        "host-prohibited":              _icmp_types_fragments("icmp", "destination-unreachable", 10),
        "host-redirect":                _icmp_types_fragments("icmp", "redirect", 1),
        "host-unknown":                 _icmp_types_fragments("icmp", "destination-unreachable", 7),
        "host-unreachable":             _icmp_types_fragments("icmp", "destination-unreachable", 1),
        "ip-header-bad":                _icmp_types_fragments("icmp", "parameter-problem", 1),
        "network-prohibited":           _icmp_types_fragments("icmp", "destination-unreachable", 8),
        "network-redirect":             _icmp_types_fragments("icmp", "redirect", 0),
        "network-unknown":              _icmp_types_fragments("icmp", "destination-unreachable", 6),
        "network-unreachable":          _icmp_types_fragments("icmp", "destination-unreachable", 0),
        "parameter-problem":            _icmp_types_fragments("icmp", "parameter-problem"),
        "port-unreachable":             _icmp_types_fragments("icmp", "destination-unreachable", 3),
        "precedence-cutoff":            _icmp_types_fragments("icmp", "destination-unreachable", 15),
        "protocol-unreachable":         _icmp_types_fragments("icmp", "destination-unreachable", 2),
        "redirect":                     _icmp_types_fragments("icmp", "redirect"),
        "required-option-missing":      _icmp_types_fragments("icmp", "parameter-problem", 1),
        "router-advertisement":         _icmp_types_fragments("icmp", "router-advertisement"),
        "router-solicitation":          _icmp_types_fragments("icmp", "router-solicitation"),
        "source-quench":                _icmp_types_fragments("icmp", "source-quench"),
        "source-route-failed":          _icmp_types_fragments("icmp", "destination-unreachable", 5),
        "time-exceeded":                _icmp_types_fragments("icmp", "time-exceeded"),
        "timestamp-reply":              _icmp_types_fragments("icmp", "timestamp-reply"),
        "timestamp-request":            _icmp_types_fragments("icmp", "timestamp-request"),
        "tos-host-redirect":            _icmp_types_fragments("icmp", "redirect", 3),
        "tos-host-unreachable":         _icmp_types_fragments("icmp", "destination-unreachable", 12),
        "tos-network-redirect":         _icmp_types_fragments("icmp", "redirect", 2),
        "tos-network-unreachable":      _icmp_types_fragments("icmp", "destination-unreachable", 11),
        "ttl-zero-during-reassembly":   _icmp_types_fragments("icmp", "time-exceeded", 1),
        "ttl-zero-during-transit":      _icmp_types_fragments("icmp", "time-exceeded", 0),
    },

    "ipv6": {
        "address-unreachable":          _icmp_types_fragments("icmpv6", "destination-unreachable", 3),
        "bad-header":                   _icmp_types_fragments("icmpv6", "parameter-problem", 0),
        "beyond-scope":                 _icmp_types_fragments("icmpv6", "destination-unreachable", 2),
        "communication-prohibited":     _icmp_types_fragments("icmpv6", "destination-unreachable", 1),
        "destination-unreachable":      _icmp_types_fragments("icmpv6", "destination-unreachable"),
        "echo-reply":                   _icmp_types_fragments("icmpv6", "echo-reply"),
        "echo-request":                 _icmp_types_fragments("icmpv6", "echo-request"),
        "failed-policy":                _icmp_types_fragments("icmpv6", "destination-unreachable", 5),
        "mld-listener-done":            _icmp_types_fragments("icmpv6", "mld-listener-done"),
        "mld-listener-query":           _icmp_types_fragments("icmpv6", "mld-listener-query"),
        "mld-listener-report":          _icmp_types_fragments("icmpv6", "mld-listener-report"),
        "mld2-listener-report":         _icmp_types_fragments("icmpv6", "mld2-listener-report"),
        "neighbour-advertisement":      _icmp_types_fragments("icmpv6", "nd-neighbor-advert"),
        "neighbour-solicitation":       _icmp_types_fragments("icmpv6", "nd-neighbor-solicit"),
        "no-route":                     _icmp_types_fragments("icmpv6", "destination-unreachable", 0),
        "packet-too-big":               _icmp_types_fragments("icmpv6", "packet-too-big"),
        "parameter-problem":            _icmp_types_fragments("icmpv6", "parameter-problem"),
        "port-unreachable":             _icmp_types_fragments("icmpv6", "destination-unreachable", 4),
        "redirect":                     _icmp_types_fragments("icmpv6", "nd-redirect"),
        "reject-route":                 _icmp_types_fragments("icmpv6", "destination-unreachable", 6),
        "router-advertisement":         _icmp_types_fragments("icmpv6", "nd-router-advert"),
        "router-solicitation":          _icmp_types_fragments("icmpv6", "nd-router-solicit"),
        "time-exceeded":                _icmp_types_fragments("icmpv6", "time-exceeded"),
        "ttl-zero-during-reassembly":   _icmp_types_fragments("icmpv6", "time-exceeded", 1),
        "ttl-zero-during-transit":      _icmp_types_fragments("icmpv6", "time-exceeded", 0),
        "unknown-header-type":          _icmp_types_fragments("icmpv6", "parameter-problem", 1),
        "unknown-option":               _icmp_types_fragments("icmpv6", "parameter-problem", 2),
    }
}

class nftables(object):
    name = "nftables"
    policies_supported = True

    def __init__(self, fw):
        self._fw = fw
        self.restore_command_exists = True
        self.available_tables = []
        self.rule_to_handle = {}
        self.rule_ref_count = {}
        self.rich_rule_priority_counts = {}
        self.policy_priority_counts = {}
        self.zone_source_index_cache = {}
        self.created_tables = {"inet": [], "ip": [], "ip6": []}

        self.nftables = Nftables()
        self.nftables.set_echo_output(True)
        self.nftables.set_handle_output(True)

    def _run_replace_zone_source(self, rule, zone_source_index_cache):
        for verb in ["add", "insert", "delete"]:
            if verb in rule:
                break

        if "%%ZONE_SOURCE%%" in rule[verb]["rule"]:
            zone_source = (rule[verb]["rule"]["%%ZONE_SOURCE%%"]["zone"],
                           rule[verb]["rule"]["%%ZONE_SOURCE%%"]["address"])
            del rule[verb]["rule"]["%%ZONE_SOURCE%%"]
        elif "%%ZONE_INTERFACE%%" in rule[verb]["rule"]:
            zone_source = None
            del rule[verb]["rule"]["%%ZONE_INTERFACE%%"]
        else:
            return

        family = rule[verb]["rule"]["family"]

        if zone_source and verb == "delete":
            if family in zone_source_index_cache and \
               zone_source in zone_source_index_cache[family]:
                zone_source_index_cache[family].remove(zone_source)
        elif verb != "delete":
            if family not in zone_source_index_cache:
                zone_source_index_cache[family] = []

            if zone_source:
                # order source based dispatch by zone name
                if zone_source not in zone_source_index_cache[family]:
                    zone_source_index_cache[family].append(zone_source)
                    zone_source_index_cache[family].sort(key=lambda x: x[0])

                index = zone_source_index_cache[family].index(zone_source)
            else:
                if self._fw._allow_zone_drifting:
                    index = 0
                else:
                    index = len(zone_source_index_cache[family])

            _verb_snippet = rule[verb]
            del rule[verb]
            if index == 0:
                rule["insert"] = _verb_snippet
            else:
                index -= 1 # point to the rule before insertion point
                rule["add"] = _verb_snippet
                rule["add"]["rule"]["index"] = index

    def reverse_rule(self, dict):
        if "insert" in dict:
            return {"delete": copy.deepcopy(dict["insert"])}
        elif "add" in dict:
            return {"delete": copy.deepcopy(dict["add"])}
        else:
            raise FirewallError(UNKNOWN_ERROR, "Failed to reverse rule")

    def _set_rule_replace_priority(self, rule, priority_counts, token):
        for verb in ["add", "insert", "delete"]:
            if verb in rule:
                break

        if token in rule[verb]["rule"]:
            priority = rule[verb]["rule"][token]
            del rule[verb]["rule"][token]
            if type(priority) != int:
                raise FirewallError(INVALID_RULE, "priority must be followed by a number")
            chain = (rule[verb]["rule"]["family"], rule[verb]["rule"]["chain"]) # family, chain
            # Add the rule to the priority counts. We don't need to store the
            # rule, just bump the ref count for the priority value.
            if verb == "delete":
                if chain not in priority_counts or \
                   priority not in priority_counts[chain] or \
                   priority_counts[chain][priority] <= 0:
                    raise FirewallError(UNKNOWN_ERROR, "nonexistent or underflow of priority count")

                priority_counts[chain][priority] -= 1
            else:
                if chain not in priority_counts:
                    priority_counts[chain] = {}
                if priority not in priority_counts[chain]:
                    priority_counts[chain][priority] = 0

                # calculate index of new rule
                index = 0
                for p in sorted(priority_counts[chain].keys()):
                    if p == priority and verb == "insert":
                        break
                    index += priority_counts[chain][p]
                    if p == priority and verb == "add":
                        break

                priority_counts[chain][priority] += 1

                _verb_snippet = rule[verb]
                del rule[verb]
                if index == 0:
                    rule["insert"] = _verb_snippet
                else:
                    index -= 1 # point to the rule before insertion point
                    rule["add"] = _verb_snippet
                    rule["add"]["rule"]["index"] = index

    def _get_rule_key(self, rule):
        for verb in ["add", "insert", "delete"]:
            if verb in rule and "rule" in rule[verb]:
                rule_key = copy.deepcopy(rule[verb]["rule"])
                for non_key in ["index", "handle", "position"]:
                    if non_key in rule_key:
                        del rule_key[non_key]
                # str(rule_key) is insufficient because dictionary order is
                # not stable.. so abuse the JSON library
                rule_key = json.dumps(rule_key, sort_keys=True)
                return rule_key
        # Not a rule (it's a table, chain, etc)
        return None

    def set_rules(self, rules, log_denied):
        _valid_verbs = ["add", "insert", "delete", "flush", "replace"]
        _valid_add_verbs = ["add", "insert", "replace"]
        _deduplicated_rules = []
        _executed_rules = []
        rich_rule_priority_counts = copy.deepcopy(self.rich_rule_priority_counts)
        policy_priority_counts = copy.deepcopy(self.policy_priority_counts)
        zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache)
        rule_ref_count = self.rule_ref_count.copy()
        for rule in rules:
            if type(rule) != dict:
                raise FirewallError(UNKNOWN_ERROR, "rule must be a dictionary, rule: %s" % (rule))

            for verb in _valid_verbs:
                if verb in rule:
                    break
            if verb not in rule:
                raise FirewallError(INVALID_RULE, "no valid verb found, rule: %s" % (rule))

            rule_key = self._get_rule_key(rule)

            # rule deduplication
            if rule_key in rule_ref_count:
                log.debug2("%s: prev rule ref cnt %d, %s", self.__class__,
                           rule_ref_count[rule_key], rule_key)
                if verb != "delete":
                    rule_ref_count[rule_key] += 1
                    continue
                elif rule_ref_count[rule_key] > 1:
                    rule_ref_count[rule_key] -= 1
                    continue
                elif rule_ref_count[rule_key] == 1:
                    rule_ref_count[rule_key] -= 1
                else:
                    raise FirewallError(UNKNOWN_ERROR, "rule ref count bug: rule_key '%s', cnt %d"
                                                       % (rule_key, rule_ref_count[rule_key]))
            elif rule_key and verb != "delete":
                rule_ref_count[rule_key] = 1

            _deduplicated_rules.append(rule)

            _rule = copy.deepcopy(rule)
            if rule_key:
                # filter empty rule expressions. Rich rules add quite a bit of
                # them, but it makes the rest of the code simpler. libnftables
                # does not tolerate them.
                _rule[verb]["rule"]["expr"] = list(filter(None, _rule[verb]["rule"]["expr"]))

                self._set_rule_replace_priority(_rule, rich_rule_priority_counts, "%%RICH_RULE_PRIORITY%%")
                self._set_rule_replace_priority(_rule, policy_priority_counts, "%%POLICY_PRIORITY%%")
                self._run_replace_zone_source(_rule, zone_source_index_cache)

                # delete using rule handle
                if verb == "delete":
                    _rule = {"delete": {"rule": {"family": _rule["delete"]["rule"]["family"],
                                                 "table": _rule["delete"]["rule"]["table"],
                                                 "chain": _rule["delete"]["rule"]["chain"],
                                                 "handle": self.rule_to_handle[rule_key]}}}

            _executed_rules.append(_rule)

        json_blob = {"nftables": [{"metainfo": {"json_schema_version": 1}}] + _executed_rules}
        if log.getDebugLogLevel() >= 3:
            # guarded with if statement because json.dumps() is expensive.
            log.debug3("%s: calling python-nftables with JSON blob: %s", self.__class__,
                       json.dumps(json_blob))
        rc, output, error = self.nftables.json_cmd(json_blob)
        if rc != 0:
            raise ValueError("'%s' failed: %s\nJSON blob:\n%s" % ("python-nftables", error, json.dumps(json_blob)))

        self.rich_rule_priority_counts = rich_rule_priority_counts
        self.policy_priority_counts = policy_priority_counts
        self.zone_source_index_cache = zone_source_index_cache
        self.rule_ref_count = rule_ref_count

        index = 0
        for rule in _deduplicated_rules:
            index += 1 # +1 due to metainfo
            rule_key = self._get_rule_key(rule)

            if not rule_key:
                continue

            if "delete" in rule:
                del self.rule_to_handle[rule_key]
                del self.rule_ref_count[rule_key]
                continue

            for verb in _valid_add_verbs:
                if verb in output["nftables"][index]:
                    break
            if verb not in output["nftables"][index]:
                continue

            self.rule_to_handle[rule_key] = output["nftables"][index][verb]["rule"]["handle"]

    def set_rule(self, rule, log_denied):
        self.set_rules([rule], log_denied)
        return ""

    def get_available_tables(self, table=None):
        # Tables always exist in nftables
        return [table] if table else IPTABLES_TO_NFT_HOOK.keys()

    def _build_delete_table_rules(self, table):
        # To avoid nftables returning ENOENT we always add the table before
        # deleting to guarantee it will exist.
        #
        # In the future, this add+delete should be replaced with "destroy", but
        # that verb is too new to rely upon.
        rules = []
        for family in ["inet", "ip", "ip6"]:
            rules.append({"add": {"table": {"family": family,
                                            "name": table}}})
            rules.append({"delete": {"table": {"family": family,
                                               "name": table}}})
        return rules

    def build_flush_rules(self):
        # Policy is stashed in a separate table that we're _not_ going to
        # flush. As such, we retain the policy rule handles and ref counts.
        saved_rule_to_handle = {}
        saved_rule_ref_count = {}
        for rule in self._build_set_policy_rules_ct_rules(True):
            policy_key = self._get_rule_key(rule)
            if policy_key in self.rule_to_handle:
                saved_rule_to_handle[policy_key] = self.rule_to_handle[policy_key]
                saved_rule_ref_count[policy_key] = self.rule_ref_count[policy_key]

        self.rule_to_handle = saved_rule_to_handle
        self.rule_ref_count = saved_rule_ref_count
        self.rich_rule_priority_counts = {}
        self.policy_priority_counts = {}
        self.zone_source_index_cache = {}

        for family in ["inet", "ip", "ip6"]:
            if TABLE_NAME in self.created_tables[family]:
                self.created_tables[family].remove(TABLE_NAME)

        return self._build_delete_table_rules(TABLE_NAME)

    def _build_set_policy_rules_ct_rules(self, enable):
        add_del = { True: "add", False: "delete" }[enable]
        rules = []
        for hook in ["input", "forward", "output"]:
            rules.append({add_del: {"rule": {"family": "inet",
                                             "table": TABLE_NAME_POLICY,
                                             "chain": "%s_%s" % ("filter", hook),
                                             "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                 "op": "in",
                                                                 "right": {"set": ["established", "related"]}}},
                                                      {"accept": None}]}}})
        return rules

    def build_set_policy_rules(self, policy):
        # Policy is not exposed to the user. It's only to make sure we DROP
        # packets while reloading and for panic mode. As such, using hooks with
        # a higher priority than our base chains is sufficient.
        rules = []
        if policy == "PANIC":
            rules.append({"add": {"table": {"family": "inet",
                                            "name": TABLE_NAME_POLICY}}})
            self.created_tables["inet"].append(TABLE_NAME_POLICY)

            # Use "raw" priority for panic mode. This occurs before
            # conntrack, mangle, nat, etc
            for hook in ["prerouting", "output"]:
                rules.append({"add": {"chain": {"family": "inet",
                                                "table": TABLE_NAME_POLICY,
                                                "name": "%s_%s" % ("raw", hook),
                                                "type": "filter",
                                                "hook": hook,
                                                "prio": -300 + NFT_HOOK_OFFSET - 1,
                                                "policy": "drop"}}})
        if policy == "DROP":
            rules.append({"add": {"table": {"family": "inet",
                                            "name": TABLE_NAME_POLICY}}})
            self.created_tables["inet"].append(TABLE_NAME_POLICY)

            # To drop everything except existing connections we use
            # "filter" because it occurs _after_ conntrack.
            for hook in ["input", "forward", "output"]:
                rules.append({"add": {"chain": {"family": "inet",
                                                "table": TABLE_NAME_POLICY,
                                                "name": "%s_%s" % ("filter", hook),
                                                "type": "filter",
                                                "hook": hook,
                                                "prio": 0 + NFT_HOOK_OFFSET - 1,
                                                "policy": "drop"}}})

            rules += self._build_set_policy_rules_ct_rules(True)
        elif policy == "ACCEPT":
            for rule in self._build_set_policy_rules_ct_rules(False):
                policy_key = self._get_rule_key(rule)
                if policy_key in self.rule_to_handle:
                    rules.append(rule)

            rules += self._build_delete_table_rules(TABLE_NAME_POLICY)

            if TABLE_NAME_POLICY in self.created_tables["inet"]:
                self.created_tables["inet"].remove(TABLE_NAME_POLICY)
        else:
            FirewallError(UNKNOWN_ERROR, "not implemented")

        return rules

    def supported_icmp_types(self, ipv=None):
        # nftables supports any icmp_type via arbitrary type/code matching.
        # We just need a translation for it in ICMP_TYPES_FRAGMENTS.
        supported = set()

        for _ipv in [ipv] if ipv else ICMP_TYPES_FRAGMENTS.keys():
            supported.update(ICMP_TYPES_FRAGMENTS[_ipv].keys())

        return list(supported)

    def build_default_tables(self):
        default_tables = []
        for family in ["inet", "ip", "ip6"]:
            default_tables.append({"add": {"table": {"family": family,
                                                     "name": TABLE_NAME}}})
            self.created_tables[family].append(TABLE_NAME)
        return default_tables

    def build_default_rules(self, log_denied="off"):
        default_rules = []
        for chain in IPTABLES_TO_NFT_HOOK["mangle"].keys():
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "mangle_%s" % chain,
                                                    "type": "filter",
                                                    "hook": "%s" % IPTABLES_TO_NFT_HOOK["mangle"][chain][0],
                                                    "prio": IPTABLES_TO_NFT_HOOK["mangle"][chain][1]}}})
            for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
                default_rules.append({"add": {"chain": {"family": "inet",
                                                        "table": TABLE_NAME,
                                                        "name": "mangle_%s_%s" % (chain, dispatch_suffix)}}})
                default_rules.append({"add": {"rule":  {"family": "inet",
                                                        "table": TABLE_NAME,
                                                        "chain": "mangle_%s" % chain,
                                                        "expr": [{"jump": {"target": "mangle_%s_%s" % (chain, dispatch_suffix)}}]}}})

        for family in ["ip", "ip6"]:
            for chain in IPTABLES_TO_NFT_HOOK["nat"].keys():
                default_rules.append({"add": {"chain": {"family": family,
                                                        "table": TABLE_NAME,
                                                        "name": "nat_%s" % chain,
                                                        "type": "nat",
                                                        "hook": "%s" % IPTABLES_TO_NFT_HOOK["nat"][chain][0],
                                                        "prio": IPTABLES_TO_NFT_HOOK["nat"][chain][1]}}})

                for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
                    default_rules.append({"add": {"chain": {"family": family,
                                                            "table": TABLE_NAME,
                                                            "name": "nat_%s_%s" % (chain, dispatch_suffix)}}})
                    default_rules.append({"add": {"rule":  {"family": family,
                                                            "table": TABLE_NAME,
                                                            "chain": "nat_%s" % chain,
                                                            "expr": [{"jump": {"target": "nat_%s_%s" % (chain, dispatch_suffix)}}]}}})

        for chain in IPTABLES_TO_NFT_HOOK["filter"].keys():
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "filter_%s" % chain,
                                                    "type": "filter",
                                                    "hook": "%s" % IPTABLES_TO_NFT_HOOK["filter"][chain][0],
                                                    "prio": IPTABLES_TO_NFT_HOOK["filter"][chain][1]}}})

        # filter, INPUT
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "INPUT",
                                                "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                    "op": "in",
                                                                    "right": {"set": ["established", "related"]}}},
                                                         {"accept": None}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "INPUT",
                                                "expr": [{"match": {"left": {"ct": {"key": "status"}},
                                                                    "op": "in",
                                                                    "right": "dnat"}},
                                                         {"accept": None}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "INPUT",
                                                "expr": [{"match": {"left": {"meta": {"key": "iifname"}},
                                                                    "op": "==",
                                                                    "right": "lo"}},
                                                         {"accept": None}]}}})
        for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "filter_%s_%s" % ("INPUT", dispatch_suffix)}}})
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "INPUT",
                                                    "expr": [{"jump": {"target": "filter_%s_%s" % ("INPUT", dispatch_suffix)}}]}}})
        if log_denied != "off":
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "INPUT",
                                                    "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                        "op": "in",
                                                                        "right": {"set": ["invalid"]}}},
                                                             self._pkttype_match_fragment(log_denied),
                                                             {"log": {"prefix": "STATE_INVALID_DROP: "}}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "INPUT",
                                                "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                    "op": "in",
                                                                    "right": {"set": ["invalid"]}}},
                                                         {"drop": None}]}}})
        if log_denied != "off":
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "INPUT",
                                                    "expr": [self._pkttype_match_fragment(log_denied),
                                                             {"log": {"prefix": "FINAL_REJECT: "}}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "INPUT",
                                                "expr": [{"reject": {"type": "icmpx", "expr": "admin-prohibited"}}]}}})

        # filter, FORWARD
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "FORWARD",
                                                "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                    "op": "in",
                                                                    "right": {"set": ["established", "related"]}}},
                                                         {"accept": None}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "FORWARD",
                                                "expr": [{"match": {"left": {"ct": {"key": "status"}},
                                                                    "op": "in",
                                                                    "right": "dnat"}},
                                                         {"accept": None}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "FORWARD",
                                                "expr": [{"match": {"left": {"meta": {"key": "iifname"}},
                                                                    "op": "==",
                                                                    "right": "lo"}},
                                                         {"accept": None}]}}})
        for dispatch_suffix in ["POLICIES_pre"]:
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}})
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "FORWARD",
                                                    "expr": [{"jump": {"target": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}]}}})
        for direction in ["IN", "OUT"]:
            for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]:
                default_rules.append({"add": {"chain": {"family": "inet",
                                                        "table": TABLE_NAME,
                                                        "name": "filter_%s_%s_%s" % ("FORWARD", direction, dispatch_suffix)}}})
                default_rules.append({"add": {"rule":  {"family": "inet",
                                                        "table": TABLE_NAME,
                                                        "chain": "filter_%s" % "FORWARD",
                                                        "expr": [{"jump": {"target": "filter_%s_%s_%s" % ("FORWARD", direction, dispatch_suffix)}}]}}})
        for dispatch_suffix in ["POLICIES_post"]:
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}})
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "FORWARD",
                                                    "expr": [{"jump": {"target": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}]}}})
        if log_denied != "off":
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "FORWARD",
                                                    "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                        "op": "in",
                                                                        "right": {"set": ["invalid"]}}},
                                                             self._pkttype_match_fragment(log_denied),
                                                             {"log": {"prefix": "STATE_INVALID_DROP: "}}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "FORWARD",
                                                "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                    "op": "in",
                                                                    "right": {"set": ["invalid"]}}},
                                                         {"drop": None}]}}})
        if log_denied != "off":
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "FORWARD",
                                                    "expr": [self._pkttype_match_fragment(log_denied),
                                                             {"log": {"prefix": "FINAL_REJECT: "}}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "FORWARD",
                                                "expr": [{"reject": {"type": "icmpx", "expr": "admin-prohibited"}}]}}})

        # filter, OUTPUT
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_%s" % "OUTPUT",
                                                "expr": [{"match": {"left": {"ct": {"key": "state"}},
                                                                    "op": "in",
                                                                    "right": {"set": ["established", "related"]}}},
                                                         {"accept": None}]}}})
        default_rules.append({"add": {"rule":  {"family": "inet",
                                                "table": TABLE_NAME,
                                                "chain": "filter_OUTPUT",
                                                "expr": [{"match": {"left": {"meta": {"key": "oifname"}},
                                                          "op": "==",
                                                          "right": "lo"}},
                                                         {"accept": None}]}}})
        for dispatch_suffix in ["POLICIES_pre"]:
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}})
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "OUTPUT",
                                                    "expr": [{"jump": {"target": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}]}}})
        for dispatch_suffix in ["POLICIES_post"]:
            default_rules.append({"add": {"chain": {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "name": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}})
            default_rules.append({"add": {"rule":  {"family": "inet",
                                                    "table": TABLE_NAME,
                                                    "chain": "filter_%s" % "OUTPUT",
                                                    "expr": [{"jump": {"target": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}]}}})

        return default_rules

    def get_zone_table_chains(self, table):
        if table == "filter":
            return ["INPUT", "FORWARD_IN", "FORWARD_OUT"]
        if table == "mangle":
            return ["PREROUTING"]
        if table == "nat":
            return ["PREROUTING", "POSTROUTING"]

        return []

    def build_policy_ingress_egress_rules(self, enable, policy, table, chain,
                                          ingress_interfaces, egress_interfaces,
                                          ingress_sources, egress_sources,
                                          family="inet"):
        # nat tables need to use ip/ip6 family
        if table == "nat" and family == "inet":
            rules = []
            rules.extend(self.build_policy_ingress_egress_rules(enable, policy, table, chain,
                                          ingress_interfaces, egress_interfaces,
                                          ingress_sources, egress_sources,
                                          family="ip"))
            rules.extend(self.build_policy_ingress_egress_rules(enable, policy, table, chain,
                                          ingress_interfaces, egress_interfaces,
                                          ingress_sources, egress_sources,
                                          family="ip6"))
            return rules

        p_obj = self._fw.policy.get_policy(policy)
        chain_suffix = "pre" if p_obj.priority < 0 else "post"
        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT)

        ingress_fragments = []
        egress_fragments = []
        if ingress_interfaces:
            ingress_fragments.append({"match": {"left": {"meta": {"key": "iifname"}},
                                                "op": "==",
                                                "right": {"set": list(ingress_interfaces)}}})
        if egress_interfaces:
            egress_fragments.append({"match": {"left": {"meta": {"key": "oifname"}},
                                               "op": "==",
                                               "right": {"set": list(egress_interfaces)}}})
        ipv_to_family = {"ipv4": "ip", "ipv6": "ip6"}
        if ingress_sources:
            for src in ingress_sources:
                # skip if this source doesn't apply to the current family.
                if table == "nat":
                    ipv = self._fw.zone.check_source(src)
                    if ipv in ipv_to_family and family != ipv_to_family[ipv]:
                        continue

                ingress_fragments.append(self._rule_addr_fragment("saddr", src))
        if egress_sources:
            for dst in egress_sources:
                # skip if this source doesn't apply to the current family.
                if table == "nat":
                    ipv = self._fw.zone.check_source(dst)
                    if ipv in ipv_to_family and family != ipv_to_family[ipv]:
                        continue

                egress_fragments.append(self._rule_addr_fragment("daddr", dst))

        def _generate_policy_dispatch_rule(ingress_fragment, egress_fragment):
            expr_fragments = []
            if ingress_fragment:
                expr_fragments.append(ingress_fragment)
            if egress_fragment:
                expr_fragments.append(egress_fragment)
            expr_fragments.append({"jump": {"target": "%s_%s" % (table, _policy)}})

            rule = {"family": family,
                    "table": TABLE_NAME,
                    "chain": "%s_%s_POLICIES_%s" % (table, chain, chain_suffix),
                    "expr": expr_fragments}
            rule.update(self._policy_priority_fragment(p_obj))

            if enable:
                return {"add": {"rule": rule}}
            else:
                return {"delete": {"rule": rule}}

        rules = []
        if ingress_fragments: # zone --> [zone, ANY, HOST]
            for ingress_fragment in ingress_fragments:
                if egress_fragments:
                    # zone --> zone
                    for egress_fragment in egress_fragments:
                        rules.append(_generate_policy_dispatch_rule(ingress_fragment, egress_fragment))
                elif table =="nat" and egress_sources:
                    # if the egress source is not for the current family (there
                    # are no egress fragments), then avoid creating an invalid
                    # catch all rule.
                    pass
                else:
                    # zone --> [ANY, HOST]
                    rules.append(_generate_policy_dispatch_rule(ingress_fragment, None))
        elif table =="nat" and ingress_sources:
            # if the ingress source is not for the current family (there are no
            # ingress fragments), then avoid creating an invalid catch all
            # rule.
            pass
        else: # [ANY, HOST] --> [zone, ANY, HOST]
            if egress_fragments:
                # [ANY, HOST] --> zone
                for egress_fragment in egress_fragments:
                    rules.append(_generate_policy_dispatch_rule(None, egress_fragment))
            elif table =="nat" and egress_sources:
                # if the egress source is not for the current family (there are
                # no egress fragments), then avoid creating an invalid catch
                # all rule.
                pass
            else:
                # [ANY, HOST] --> [ANY, HOST]
                rules.append(_generate_policy_dispatch_rule(None, None))

        return rules

    def build_zone_source_interface_rules(self, enable, zone, policy, interface,
                                          table, chain, append=False,
                                          family="inet"):
        # nat tables needs to use ip/ip6 family
        if table == "nat" and family == "inet":
            rules = []
            rules.extend(self.build_zone_source_interface_rules(enable, zone, policy,
                            interface, table, chain, append, "ip"))
            rules.extend(self.build_zone_source_interface_rules(enable, zone, policy,
                            interface, table, chain, append, "ip6"))
            return rules

        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT)
        opt = {
            "PREROUTING": "iifname",
            "POSTROUTING": "oifname",
            "INPUT": "iifname",
            "FORWARD_IN": "iifname",
            "FORWARD_OUT": "oifname",
            "OUTPUT": "oifname",
        }[chain]

        if interface[len(interface)-1] == "+":
            interface = interface[:len(interface)-1] + "*"

        action = "goto"

        if interface == "*":
            expr_fragments = [{action: {"target": "%s_%s" % (table, _policy)}}]
        else:
            expr_fragments = [{"match": {"left": {"meta": {"key": opt}},
                                         "op": "==",
                                         "right": interface}},
                              {action: {"target": "%s_%s" % (table, _policy)}}]

        if enable and not append:
            verb = "insert"
            rule = {"family": family,
                    "table": TABLE_NAME,
                    "chain": "%s_%s_ZONES" % (table, chain),
                    "expr": expr_fragments}
            rule.update(self._zone_interface_fragment())
        elif enable:
            verb = "add"
            rule = {"family": family,
                    "table": TABLE_NAME,
                    "chain": "%s_%s_ZONES" % (table, chain),
                    "expr": expr_fragments}
        else:
            verb = "delete"
            rule = {"family": family,
                    "table": TABLE_NAME,
                    "chain": "%s_%s_ZONES" % (table, chain),
                    "expr": expr_fragments}
            if not append:
                rule.update(self._zone_interface_fragment())

        return [{verb: {"rule": rule}}]

    def build_zone_source_address_rules(self, enable, zone, policy,
                                        address, table, chain, family="inet"):
        # nat tables needs to use ip/ip6 family
        if table == "nat" and family == "inet":
            rules = []
            if address.startswith("ipset:"):
                ipset_family = self._set_get_family(address[len("ipset:"):])
            else:
                ipset_family = None

            if check_address("ipv4", address) or check_mac(address) or ipset_family == "ip":
                rules.extend(self.build_zone_source_address_rules(enable, zone, policy,
                                    address, table, chain, "ip"))
            if check_address("ipv6", address) or check_mac(address) or ipset_family == "ip6":
                rules.extend(self.build_zone_source_address_rules(enable, zone, policy,
                                    address, table, chain, "ip6"))
            return rules

        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT)
        add_del = { True: "insert", False: "delete" }[enable]

        opt = {
            "PREROUTING": "saddr",
            "POSTROUTING": "daddr",
            "INPUT": "saddr",
            "FORWARD_IN": "saddr",
            "FORWARD_OUT": "daddr",
            "OUTPUT": "daddr",
        }[chain]

        if self._fw._allow_zone_drifting:
            zone_dispatch_chain = "%s_%s_ZONES_SOURCE" % (table, chain)
        else:
            zone_dispatch_chain = "%s_%s_ZONES" % (table, chain)

        action = "goto"

        rule = {"family": family,
                "table": TABLE_NAME,
                "chain": zone_dispatch_chain,
                "expr": [self._rule_addr_fragment(opt, address),
                         {action: {"target": "%s_%s" % (table, _policy)}}]}
        rule.update(self._zone_source_fragment(zone, address))
        return [{add_del: {"rule": rule}}]

    def build_policy_chain_rules(self, enable, policy, table, chain, family="inet"):
        # nat tables needs to use ip/ip6 family
        if table == "nat" and family == "inet":
            rules = []
            rules.extend(self.build_policy_chain_rules(enable, policy, table, chain, "ip"))
            rules.extend(self.build_policy_chain_rules(enable, policy, table, chain, "ip6"))
            return rules

        add_del = { True: "add", False: "delete" }[enable]
        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT)

        rules = []
        rules.append({add_del: {"chain": {"family": family,
                                          "table": TABLE_NAME,
                                          "name": "%s_%s" % (table, _policy)}}})
        for chain_suffix in ["pre", "log", "deny", "allow", "post"]:
            rules.append({add_del: {"chain": {"family": family,
                                              "table": TABLE_NAME,
                                              "name": "%s_%s_%s" % (table, _policy, chain_suffix)}}})

        for chain_suffix in ["pre", "log", "deny", "allow", "post"]:
            rules.append({add_del: {"rule": {"family": family,
                                             "table": TABLE_NAME,
                                             "chain": "%s_%s" % (table, _policy),
                                             "expr": [{"jump": {"target": "%s_%s_%s" % (table, _policy, chain_suffix)}}]}}})

        target = self._fw.policy._policies[policy].target

        if self._fw.get_log_denied() != "off":
            if table == "filter":
                if target in ["REJECT", "%%REJECT%%", "DROP"]:
                    log_suffix = target
                    if target == "%%REJECT%%":
                        log_suffix = "REJECT"
                    rules.append({add_del: {"rule": {"family": family,
                                                     "table": TABLE_NAME,
                                                     "chain": "%s_%s" % (table, _policy),
                                                     "expr": [self._pkttype_match_fragment(self._fw.get_log_denied()),
                                                              {"log": {"prefix": "\"filter_%s_%s: \"" % (_policy, log_suffix)}}]}}})

        if table == "filter" and \
           target in ["ACCEPT", "REJECT", "%%REJECT%%", "DROP"]:
            if target in ["%%REJECT%%", "REJECT"]:
                target_fragment = self._reject_fragment()
            else:
                target_fragment = {target.lower(): None}
            rules.append({add_del: {"rule": {"family": family,
                                             "table": TABLE_NAME,
                                             "chain": "%s_%s" % (table, _policy),
                                             "expr": [target_fragment]}}})

        if not enable:
            rules.reverse()

        return rules

    def _pkttype_match_fragment(self, pkttype):
        if pkttype == "all":
            return {}
        elif pkttype in ["unicast", "broadcast", "multicast"]:
            return {"match": {"left": {"meta": {"key": "pkttype"}},
                               "op": "==",
                               "right": pkttype}}

        raise FirewallError(INVALID_RULE, "Invalid pkttype \"%s\"", pkttype)

    def _reject_types_fragment(self, reject_type):
        frags = {
            # REJECT_TYPES              : <nft reject rule fragment>
            "icmp-host-prohibited"      : {"reject": {"type": "icmp", "expr": "host-prohibited"}},
            "host-prohib"               : {"reject": {"type": "icmp", "expr": "host-prohibited"}},
            "icmp-net-prohibited"       : {"reject": {"type": "icmp", "expr": "net-prohibited"}},
            "net-prohib"                : {"reject": {"type": "icmp", "expr": "net-prohibited"}},
            "icmp-admin-prohibited"     : {"reject": {"type": "icmp", "expr": "admin-prohibited"}},
            "admin-prohib"              : {"reject": {"type": "icmp", "expr": "admin-prohibited"}},
            "icmp6-adm-prohibited"      : {"reject": {"type": "icmpv6", "expr": "admin-prohibited"}},
            "adm-prohibited"            : {"reject": {"type": "icmpv6", "expr": "admin-prohibited"}},

            "icmp-net-unreachable"      : {"reject": {"type": "icmp", "expr": "net-unreachable"}},
            "net-unreach"               : {"reject": {"type": "icmp", "expr": "net-unreachable"}},
            "icmp-host-unreachable"     : {"reject": {"type": "icmp", "expr": "host-unreachable"}},
            "host-unreach"              : {"reject": {"type": "icmp", "expr": "host-unreachable"}},
            "icmp-port-unreachable"     : {"reject": {"type": "icmp", "expr": "port-unreachable"}},
            "icmp6-port-unreachable"    : {"reject": {"type": "icmpv6", "expr": "port-unreachable"}},
            "port-unreach"              : {"reject": {"type": "icmpx", "expr": "port-unreachable"}},
            "icmp-proto-unreachable"    : {"reject": {"type": "icmp", "expr": "prot-unreachable"}},
            "proto-unreach"             : {"reject": {"type": "icmp", "expr": "prot-unreachable"}},
            "icmp6-addr-unreachable"    : {"reject": {"type": "icmpv6", "expr": "addr-unreachable"}},
            "addr-unreach"              : {"reject": {"type": "icmpv6", "expr": "addr-unreachable"}},

            "icmp6-no-route"            : {"reject": {"type": "icmpv6", "expr": "no-route"}},
            "no-route"                  : {"reject": {"type": "icmpv6", "expr": "no-route"}},

            "tcp-reset"                 : {"reject": {"type": "tcp reset"}},
            "tcp-rst"                   : {"reject": {"type": "tcp reset"}},
        }
        return frags[reject_type]

    def _reject_fragment(self):
        return {"reject": {"type": "icmpx",
                           "expr": "admin-prohibited"}}

    def _icmp_match_fragment(self):
        return {"match": {"left": {"meta": {"key": "l4proto"}},
                          "op": "==",
                          "right": {"set": ["icmp", "icmpv6"]}}}

    def _rich_rule_limit_fragment(self, limit):
        if not limit:
            return {}

        rich_to_nft = {
            "s" : "second",
            "m" : "minute",
            "h" : "hour",
            "d" : "day",
        }

        rate, duration = limit.value_parse()

        d = {
            "rate": rate,
            "per": rich_to_nft[duration],
        }

        burst = limit.burst_parse()
        if burst is not None:
            d["burst"] = burst

        return {"limit": d}

    def _rich_rule_chain_suffix(self, rich_rule):
        if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock]:
            # These are special and don't have an explicit action
            pass
        elif rich_rule.action:
            if type(rich_rule.action) not in [Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark]:
                raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action))
        else:
            raise FirewallError(INVALID_RULE, "No rule action specified.")

        if rich_rule.priority == 0:
            if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort] or \
               type(rich_rule.action) in [Rich_Accept, Rich_Mark]:
                return "allow"
            elif type(rich_rule.element) in [Rich_IcmpBlock] or \
                 type(rich_rule.action) in [Rich_Reject, Rich_Drop]:
                return "deny"
        elif rich_rule.priority < 0:
            return "pre"
        else:
            return "post"

    def _rich_rule_chain_suffix_from_log(self, rich_rule):
        if not rich_rule.log and not rich_rule.audit:
            raise FirewallError(INVALID_RULE, "Not log or audit")

        if rich_rule.priority == 0:
            return "log"
        elif rich_rule.priority < 0:
            return "pre"
        else:
            return "post"

    def _zone_interface_fragment(self):
        return {"%%ZONE_INTERFACE%%": None}

    def _zone_source_fragment(self, zone, address):
        if check_single_address("ipv6", address):
            address = normalizeIP6(address)
        elif check_address("ipv6", address):
            addr_split = address.split("/")
            address = normalizeIP6(addr_split[0]) + "/" + addr_split[1]
        return {"%%ZONE_SOURCE%%": {"zone": zone, "address": address}}

    def _policy_priority_fragment(self, policy):
        return {"%%POLICY_PRIORITY%%": policy.priority}

    def _rich_rule_priority_fragment(self, rich_rule):
        if not rich_rule or rich_rule.priority == 0:
            return {}
        return {"%%RICH_RULE_PRIORITY%%": rich_rule.priority}

    def _rich_rule_log(self, policy, rich_rule, enable, table, expr_fragments):
        if not rich_rule.log:
            return {}

        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        add_del = { True: "add", False: "delete" }[enable]

        chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule)

        log_options = {}
        if rich_rule.log.prefix:
            log_options["prefix"] = "%s" % rich_rule.log.prefix
        if rich_rule.log.level:
            level = "warn" if "warning" == rich_rule.log.level else rich_rule.log.level
            log_options["level"] = "%s" % level

        rule = {"family": "inet",
                "table": TABLE_NAME,
                "chain": "%s_%s_%s" % (table, _policy, chain_suffix),
                "expr": expr_fragments +
                        [self._rich_rule_limit_fragment(rich_rule.log.limit),
                         {"log": log_options}]}
        rule.update(self._rich_rule_priority_fragment(rich_rule))
        return {add_del: {"rule": rule}}

    def _rich_rule_audit(self, policy, rich_rule, enable, table, expr_fragments):
        if not rich_rule.audit:
            return {}

        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        add_del = { True: "add", False: "delete" }[enable]

        chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule)
        rule = {"family": "inet",
                "table": TABLE_NAME,
                "chain": "%s_%s_%s" % (table, _policy, chain_suffix),
                "expr": expr_fragments +
                        [self._rich_rule_limit_fragment(rich_rule.audit.limit),
                         {"log": {"level": "audit"}}]}
        rule.update(self._rich_rule_priority_fragment(rich_rule))
        return {add_del: {"rule": rule}}

    def _rich_rule_action(self, policy, rich_rule, enable, table, expr_fragments):
        if not rich_rule.action:
            return {}

        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        add_del = { True: "add", False: "delete" }[enable]

        chain_suffix = self._rich_rule_chain_suffix(rich_rule)
        chain = "%s_%s_%s" % (table, _policy, chain_suffix)
        if type(rich_rule.action) == Rich_Accept:
            rule_action = {"accept": None}
        elif type(rich_rule.action) == Rich_Reject:
            if rich_rule.action.type:
                rule_action = self._reject_types_fragment(rich_rule.action.type)
            else:
                rule_action = {"reject": None}
        elif type(rich_rule.action) ==  Rich_Drop:
            rule_action = {"drop": None}
        elif type(rich_rule.action) == Rich_Mark:
            table = "mangle"
            _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
            chain = "%s_%s_%s" % (table, _policy, chain_suffix)
            value = rich_rule.action.set.split("/")
            if len(value) > 1:
                rule_action = {"mangle": {"key": {"meta": {"key": "mark"}},
                                          "value": {"^": [{"&": [{"meta": {"key": "mark"}}, value[1]]}, value[0]]}}}
            else:
                rule_action = {"mangle": {"key": {"meta": {"key": "mark"}},
                                          "value": value[0]}}

        else:
            raise FirewallError(INVALID_RULE,
                                "Unknown action %s" % type(rich_rule.action))

        rule = {"family": "inet",
                "table": TABLE_NAME,
                "chain": chain,
                "expr": expr_fragments +
                        [self._rich_rule_limit_fragment(rich_rule.action.limit), rule_action]}
        rule.update(self._rich_rule_priority_fragment(rich_rule))
        return {add_del: {"rule": rule}}

    def _rule_addr_fragment(self, addr_field, address, invert=False):
        if address.startswith("ipset:"):
            return self._set_match_fragment(address[len("ipset:"):], True if "daddr" == addr_field else False, invert)
        else:
            if check_mac(address):
                family = "ether"
            elif check_single_address("ipv4", address):
                family = "ip"
            elif check_address("ipv4", address):
                family = "ip"
                normalized_address = ipaddress.IPv4Network(address, strict=False)
                address = {"prefix": {"addr": normalized_address.network_address.compressed, "len": normalized_address.prefixlen}}
            elif check_single_address("ipv6", address):
                family = "ip6"
                address = normalizeIP6(address)
            else:
                family = "ip6"
                addr_len = address.split("/")
                address = {"prefix": {"addr": normalizeIP6(addr_len[0]), "len": int(addr_len[1])}}

            return {"match": {"left": {"payload": {"protocol": family,
                                                   "field": addr_field}},
                              "op": "!=" if invert else "==",
                              "right": address}}

    def _rich_rule_family_fragment(self, rich_family):
        if not rich_family:
            return {}
        if rich_family not in ["ipv4", "ipv6"]:
            raise FirewallError(INVALID_RULE,
                                "Invalid family" % rich_family)

        return {"match": {"left": {"meta": {"key": "nfproto"}},
                          "op": "==",
                          "right": rich_family}}

    def _rich_rule_destination_fragment(self, rich_dest):
        if not rich_dest:
            return {}
        if rich_dest.addr:
            address = rich_dest.addr
        elif rich_dest.ipset:
            address = "ipset:" + rich_dest.ipset

        return self._rule_addr_fragment("daddr", address, invert=rich_dest.invert)

    def _rich_rule_source_fragment(self, rich_source):
        if not rich_source:
            return {}

        if rich_source.addr:
            address = rich_source.addr
        elif hasattr(rich_source, "mac") and rich_source.mac:
            address = rich_source.mac
        elif hasattr(rich_source, "ipset") and rich_source.ipset:
            address = "ipset:" + rich_source.ipset

        return self._rule_addr_fragment("saddr", address, invert=rich_source.invert)

    def _port_fragment(self, port):
        range = getPortRange(port)
        if isinstance(range, int) and range < 0:
            raise FirewallError(INVALID_PORT)
        elif len(range) == 1:
            return range[0]
        else:
            return {"range": [range[0], range[1]]}

    def build_policy_ports_rules(self, enable, policy, proto, port, destination=None, rich_rule=None):
        add_del = { True: "add", False: "delete" }[enable]
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        expr_fragments = []
        if rich_rule:
            expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family))
        if destination:
            expr_fragments.append(self._rule_addr_fragment("daddr", destination))
        if rich_rule:
            expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
            expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))

        expr_fragments.append({"match": {"left": {"payload": {"protocol": proto,
                                                              "field": "dport"}},
                                         "op": "==",
                                         "right": self._port_fragment(port)}})
        if not rich_rule or type(rich_rule.action) != Rich_Mark:
            expr_fragments.append({"match": {"left": {"ct": {"key": "state"}},
                                             "op": "in",
                                             "right": {"set": ["new", "untracked"]}}})

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments))
            rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments))
        else:
            rules.append({add_del: {"rule": {"family": "inet",
                                             "table": TABLE_NAME,
                                             "chain": "%s_%s_allow" % (table, _policy),
                                             "expr": expr_fragments + [{"accept": None}]}}})

        return rules

    def build_policy_protocol_rules(self, enable, policy, protocol, destination=None, rich_rule=None):
        add_del = { True: "add", False: "delete" }[enable]
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        expr_fragments = []
        if rich_rule:
            expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family))
        if destination:
            expr_fragments.append(self._rule_addr_fragment("daddr", destination))
        if rich_rule:
            expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
            expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))

        expr_fragments.append({"match": {"left": {"meta": {"key": "l4proto"}},
                                         "op": "==",
                                         "right": protocol}})
        if not rich_rule or type(rich_rule.action) != Rich_Mark:
            expr_fragments.append({"match": {"left": {"ct": {"key": "state"}},
                                             "op": "in",
                                             "right": {"set": ["new", "untracked"]}}})

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments))
            rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments))
        else:
            rules.append({add_del: {"rule": {"family": "inet",
                                             "table": TABLE_NAME,
                                             "chain": "%s_%s_allow" % (table, _policy),
                                             "expr": expr_fragments + [{"accept": None}]}}})

        return rules

    def build_policy_source_ports_rules(self, enable, policy, proto, port,
                                      destination=None, rich_rule=None):
        add_del = { True: "add", False: "delete" }[enable]
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        expr_fragments = []
        if rich_rule:
            expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family))
        if destination:
            expr_fragments.append(self._rule_addr_fragment("daddr", destination))
        if rich_rule:
            expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
            expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))

        expr_fragments.append({"match": {"left": {"payload": {"protocol": proto,
                                                              "field": "sport"}},
                                         "op": "==",
                                         "right": self._port_fragment(port)}})
        if not rich_rule or type(rich_rule.action) != Rich_Mark:
            expr_fragments.append({"match": {"left": {"ct": {"key": "state"}},
                                             "op": "in",
                                             "right": {"set": ["new", "untracked"]}}})

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments))
            rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments))
        else:
            rules.append({add_del: {"rule": {"family": "inet",
                                             "table": TABLE_NAME,
                                             "chain": "%s_%s_allow" % (table, _policy),
                                             "expr": expr_fragments + [{"accept": None}]}}})

        return rules

    def build_policy_helper_ports_rules(self, enable, policy, proto, port,
                                        destination, helper_name, module_short_name):
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "add", False: "delete" }[enable]
        rules = []

        if enable:
            rules.append({"add": {"ct helper": {"family": "inet",
                                                "table": TABLE_NAME,
                                                "name": "helper-%s-%s" % (helper_name, proto),
                                                "type": module_short_name,
                                                "protocol": proto}}})

        expr_fragments = []
        if destination:
            expr_fragments.append(self._rule_addr_fragment("daddr", destination))
        expr_fragments.append({"match": {"left": {"payload": {"protocol": proto,
                                                              "field": "dport"}},
                                         "op": "==",
                                         "right": self._port_fragment(port)}})
        expr_fragments.append({"ct helper": "helper-%s-%s" % (helper_name, proto)})
        rules.append({add_del: {"rule": {"family": "inet",
                                         "table": TABLE_NAME,
                                         "chain": "filter_%s_allow" % (_policy),
                                         "expr": expr_fragments}}})

        return rules

    def build_zone_forward_rules(self, enable, zone, policy, table, interface=None, source=None):
        add_del = { True: "add", False: "delete" }[enable]
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        rules = []

        if interface:
            if interface[len(interface)-1] == "+":
                interface = interface[:len(interface)-1] + "*"

            expr = [{"match": {"left": {"meta": {"key": "oifname"}},
                               "op": "==",
                               "right": interface}},
                    {"accept": None}]
        else: # source
            expr = [self._rule_addr_fragment("daddr", source), {"accept": None}]

        rule = {"family": "inet",
                "table": TABLE_NAME,
                "chain": "filter_%s_allow" % (_policy),
                "expr": expr}
        rules.append({add_del: {"rule": rule}})

        return rules

    def _build_policy_masquerade_nat_rules(self, enable, policy, family, rich_rule=None):
        table = "nat"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=True)

        add_del = { True: "add", False: "delete" }[enable]

        expr_fragments = []
        if rich_rule:
            expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
            expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))
            chain_suffix = self._rich_rule_chain_suffix(rich_rule)
        else:
            chain_suffix = "allow"

        rule = {"family": family,
                "table": TABLE_NAME,
                "chain": "nat_%s_%s" % (_policy, chain_suffix),
                "expr": expr_fragments +
                        [{"match": {"left": {"meta": {"key": "oifname"}},
                                    "op": "!=",
                                    "right": "lo"}},
                         {"masquerade": None}]}
        rule.update(self._rich_rule_priority_fragment(rich_rule))
        return [{add_del: {"rule": rule}}]

    def build_policy_masquerade_rules(self, enable, policy, rich_rule=None):
        # nat tables needs to use ip/ip6 family
        rules = []
        if rich_rule and (rich_rule.family and rich_rule.family == "ipv6"
           or rich_rule.source and check_address("ipv6", rich_rule.source.addr)):
            rules.extend(self._build_policy_masquerade_nat_rules(enable, policy, "ip6", rich_rule))
        elif rich_rule and (rich_rule.family and rich_rule.family == "ipv4"
           or rich_rule.source and check_address("ipv4", rich_rule.source.addr)):
            rules.extend(self._build_policy_masquerade_nat_rules(enable, policy, "ip", rich_rule))
        else:
            rules.extend(self._build_policy_masquerade_nat_rules(enable, policy, "ip", rich_rule))

        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "add", False: "delete" }[enable]

        expr_fragments = []
        if rich_rule:
            expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
            expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))
            chain_suffix = self._rich_rule_chain_suffix(rich_rule)
        else:
            chain_suffix = "allow"

        rule = {"family": "inet",
                "table": TABLE_NAME,
                "chain": "filter_%s_%s" % (_policy, chain_suffix),
                "expr": expr_fragments +
                        [{"match": {"left": {"ct": {"key": "state"}},
                                    "op": "in",
                                    "right": {"set": ["new", "untracked"]}}},
                         {"accept": None}]}
        rule.update(self._rich_rule_priority_fragment(rich_rule))
        rules.append({add_del: {"rule": rule}})

        return rules

    def _build_policy_forward_port_nat_rules(self, enable, policy, port, protocol,
                                           toaddr, toport, family,
                                           rich_rule=None):
        table = "nat"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "add", False: "delete" }[enable]

        expr_fragments = []
        if rich_rule:
            expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
            expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))
            chain_suffix = self._rich_rule_chain_suffix(rich_rule)
        else:
            chain_suffix = "allow"

        expr_fragments.append({"match": {"left": {"payload": {"protocol": protocol,
                                                              "field": "dport"}},
                                         "op": "==",
                                         "right": self._port_fragment(port)}})

        if toaddr:
            if check_single_address("ipv6", toaddr):
                toaddr = normalizeIP6(toaddr)
            if toport and toport != "":
                expr_fragments.append({"dnat": {"addr": toaddr, "port": self._port_fragment(toport)}})
            else:
                expr_fragments.append({"dnat": {"addr": toaddr}})
        else:
            expr_fragments.append({"redirect": {"port": self._port_fragment(toport)}})

        rule = {"family": family,
                "table": TABLE_NAME,
                "chain": "nat_%s_%s" % (_policy, chain_suffix),
                "expr": expr_fragments}
        rule.update(self._rich_rule_priority_fragment(rich_rule))
        return [{add_del: {"rule": rule}}]

    def build_policy_forward_port_rules(self, enable, policy, port,
                                      protocol, toport, toaddr, rich_rule=None):
        rules = []
        if rich_rule and (rich_rule.family and rich_rule.family == "ipv6"
           or toaddr and check_single_address("ipv6", toaddr)):
            rules.extend(self._build_policy_forward_port_nat_rules(enable, policy,
                                port, protocol, toaddr, toport, "ip6", rich_rule))
        elif rich_rule and (rich_rule.family and rich_rule.family == "ipv4"
           or toaddr and check_single_address("ipv4", toaddr)):
            rules.extend(self._build_policy_forward_port_nat_rules(enable, policy,
                                port, protocol, toaddr, toport, "ip", rich_rule))
        else:
            if toaddr and check_single_address("ipv6", toaddr):
                rules.extend(self._build_policy_forward_port_nat_rules(enable, policy,
                                    port, protocol, toaddr, toport, "ip6", rich_rule))
            else:
                rules.extend(self._build_policy_forward_port_nat_rules(enable, policy,
                                    port, protocol, toaddr, toport, "ip", rich_rule))

        return rules

    def _icmp_types_to_nft_fragments(self, ipv, icmp_type):
        if icmp_type in ICMP_TYPES_FRAGMENTS[ipv]:
            return ICMP_TYPES_FRAGMENTS[ipv][icmp_type]
        else:
            raise FirewallError(INVALID_ICMPTYPE,
                                "ICMP type '%s' not supported by %s for %s" % (icmp_type, self.name, ipv))

    def build_policy_icmp_block_rules(self, enable, policy, ict, rich_rule=None):
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "add", False: "delete" }[enable]

        if rich_rule and rich_rule.ipvs:
            ipvs = rich_rule.ipvs
        elif ict.destination:
            ipvs = []
            if "ipv4" in ict.destination:
                ipvs.append("ipv4")
            if "ipv6" in ict.destination:
                ipvs.append("ipv6")
        else:
            ipvs = ["ipv4", "ipv6"]

        rules = []
        for ipv in ipvs:
            if self._fw.policy.query_icmp_block_inversion(policy):
                final_chain = "%s_%s_allow" % (table, _policy)
                target_fragment = {"accept": None}
            else:
                final_chain = "%s_%s_deny" % (table, _policy)
                target_fragment = self._reject_fragment()

            expr_fragments = []
            if rich_rule:
                expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family))
                expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
                expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))
            expr_fragments.extend(self._icmp_types_to_nft_fragments(ipv, ict.name))

            if rich_rule:
                rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments))
                rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments))
                if rich_rule.action:
                    rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments))
                else:
                    chain_suffix = self._rich_rule_chain_suffix(rich_rule)
                    rule = {"family": "inet",
                            "table": TABLE_NAME,
                            "chain": "%s_%s_%s" % (table, _policy, chain_suffix),
                            "expr": expr_fragments + [self._reject_fragment()]}
                    rule.update(self._rich_rule_priority_fragment(rich_rule))
                    rules.append({add_del: {"rule": rule}})
            else:
                if self._fw.get_log_denied() != "off" and not self._fw.policy.query_icmp_block_inversion(policy):
                    rules.append({add_del: {"rule": {"family": "inet",
                                                     "table": TABLE_NAME,
                                                     "chain": final_chain,
                                                     "expr": (expr_fragments +
                                                              [self._pkttype_match_fragment(self._fw.get_log_denied()),
                                                               {"log": {"prefix": "\"%s_%s_ICMP_BLOCK: \"" % (table, policy)}}])}}})
                rules.append({add_del: {"rule": {"family": "inet",
                                                 "table": TABLE_NAME,
                                                 "chain": final_chain,
                                                 "expr": expr_fragments + [target_fragment]}}})

        return rules

    def build_policy_icmp_block_inversion_rules(self, enable, policy):
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        rules = []
        add_del = { True: "add", False: "delete" }[enable]

        if self._fw.policy.query_icmp_block_inversion(policy):
            target_fragment = self._reject_fragment()
        else:
            target_fragment = {"accept": None}

        # WARN: The "index" used here must be kept in sync with
        # build_policy_chain_rules()
        #
        rules.append({add_del: {"rule": {"family": "inet",
                                         "table": TABLE_NAME,
                                         "chain": "%s_%s" % (table, _policy),
                                         "index": 4,
                                         "expr": [self._icmp_match_fragment(),
                                                  target_fragment]}}})

        if self._fw.get_log_denied() != "off" and self._fw.policy.query_icmp_block_inversion(policy):
            rules.append({add_del: {"rule": {"family": "inet",
                                             "table": TABLE_NAME,
                                             "chain": "%s_%s" % (table, _policy),
                                             "index": 4,
                                             "expr": [self._icmp_match_fragment(),
                                                      self._pkttype_match_fragment(self._fw.get_log_denied()),
                                                      {"log": {"prefix": "%s_%s_ICMP_BLOCK: " % (table, policy)}}]}}})
        return rules

    def build_rpfilter_rules(self, log_denied=False):
        rules = []
        expr_fragments = [{"match": {"left": {"meta": {"key": "nfproto"}},
                                     "op": "==",
                                     "right": "ipv6"}},
                          {"match": {"left": {"fib": {"flags": ["saddr", "iif", "mark"],
                                                      "result": "oif"}},
                                     "op": "==",
                                     "right": False}}]
        if log_denied != "off":
            expr_fragments.append({"log": {"prefix": "rpfilter_DROP: "}})
        expr_fragments.append({"drop": None})

        rules.append({"insert": {"rule": {"family": "inet",
                                          "table": TABLE_NAME,
                                          "chain": "filter_PREROUTING",
                                          "expr": expr_fragments}}})
        # RHBZ#1058505, RHBZ#1575431 (bug in kernel 4.16-4.17)
        rules.append({"insert": {"rule": {"family": "inet",
                                          "table": TABLE_NAME,
                                          "chain": "filter_PREROUTING",
                                          "expr": [{"match": {"left": {"payload": {"protocol": "icmpv6",
                                                                                   "field": "type"}},
                                                              "op": "==",
                                                              "right": {"set": ["nd-router-advert", "nd-neighbor-solicit"]}}},
                                                   {"accept": None}]}}})
        return rules

    def build_rfc3964_ipv4_rules(self):
        daddr_set = ["::0.0.0.0/96", # IPv4 compatible
                     "::ffff:0.0.0.0/96", # IPv4 mapped
                     "2002:0000::/24", # 0.0.0.0/8 (the system has no address assigned yet)
                     "2002:0a00::/24", # 10.0.0.0/8 (private)
                     "2002:7f00::/24", # 127.0.0.0/8 (loopback)
                     "2002:ac10::/28", # 172.16.0.0/12 (private)
                     "2002:c0a8::/32", # 192.168.0.0/16 (private)
                     "2002:a9fe::/32", # 169.254.0.0/16 (IANA Assigned DHCP link-local)
                     "2002:e000::/19", # 224.0.0.0/4 (multicast), 240.0.0.0/4 (reserved and broadcast)
                     ]
        daddr_set = [{"prefix": {"addr": x.split("/")[0], "len": int(x.split("/")[1])}} for x in daddr_set]

        expr_fragments = [{"match": {"left": {"payload": {"protocol": "ip6",
                                                          "field": "daddr"}},
                                     "op": "==",
                                     "right": {"set": daddr_set}}}]
        if self._fw._log_denied in ["unicast", "all"]:
            expr_fragments.append({"log": {"prefix": "RFC3964_IPv4_REJECT: "}})
        expr_fragments.append(self._reject_types_fragment("addr-unreach"))

        rules = []
        # WARN: index must be kept in sync with build_default_rules()
        rules.append({"add": {"rule": {"family": "inet",
                                       "table": TABLE_NAME,
                                       "chain": "filter_OUTPUT",
                                       "index": 1,
                                       "expr": expr_fragments}}})
        rules.append({"add": {"rule": {"family": "inet",
                                       "table": TABLE_NAME,
                                       "chain": "filter_FORWARD",
                                       "index": 2,
                                       "expr": expr_fragments}}})
        return rules

    def build_policy_rich_source_destination_rules(self, enable, policy, rich_rule):
        table = "filter"

        expr_fragments = []
        expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family))
        expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination))
        expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source))

        rules = []
        rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments))
        rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments))
        rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments))

        return rules

    def is_ipv_supported(self, ipv):
        if ipv in ["ipv4", "ipv6", "eb"]:
            return True
        return False

    def _set_type_list(self, ipv, type):
        ipv_addr = {
            "ipv4" : "ipv4_addr",
            "ipv6" : "ipv6_addr",
        }
        types = {
            "hash:ip" : ipv_addr[ipv],
            "hash:ip,port" : [ipv_addr[ipv], "inet_proto", "inet_service"],
            "hash:ip,port,ip" : [ipv_addr[ipv], "inet_proto", "inet_service", ipv_addr[ipv]],
            "hash:ip,port,net" : [ipv_addr[ipv], "inet_proto", "inet_service", ipv_addr[ipv]],
            "hash:ip,mark" : [ipv_addr[ipv], "mark"],

            "hash:net" : ipv_addr[ipv],
            "hash:net,net" : [ipv_addr[ipv], ipv_addr[ipv]],
            "hash:net,port" : [ipv_addr[ipv], "inet_proto", "inet_service"],
            "hash:net,port,net" : [ipv_addr[ipv], "inet_proto", "inet_service", ipv_addr[ipv]],
            "hash:net,iface" : [ipv_addr[ipv], "ifname"],

            "hash:mac" : "ether_addr",
        }
        if type in types:
            return types[type]
        else:
            raise FirewallError(INVALID_TYPE,
                                "ipset type name '%s' is not valid" % type)

    def build_set_create_rules(self, name, type, options=None):
        if options and "family" in options and options["family"] == "inet6":
            ipv = "ipv6"
        else:
            ipv = "ipv4"

        set_dict = {"table": TABLE_NAME,
                    "name": name,
                    "type": self._set_type_list(ipv, type)}

        # Some types need the interval flag
        for t in type.split(":")[1].split(","):
            if t in ["ip", "net", "port"]:
                set_dict["flags"] = ["interval"]
                break

        if options:
            if "timeout" in options:
                set_dict["timeout"] = options["timeout"]
            if "maxelem" in options:
                set_dict["size"] = options["maxelem"]

        rules = []
        for family in ["inet", "ip", "ip6"]:
            rule_dict = {"family": family}
            rule_dict.update(set_dict)
            rules.append({"add": {"set": rule_dict}})

        return rules

    def set_create(self, name, type, options=None):
        rules = self.build_set_create_rules(name, type, options)
        self.set_rules(rules, self._fw.get_log_denied())

    def set_destroy(self, name):
        for family in ["inet", "ip", "ip6"]:
            rule = {"delete": {"set": {"family": family,
                                       "table": TABLE_NAME,
                                       "name": name}}}
            self.set_rule(rule, self._fw.get_log_denied())

    def _set_match_fragment(self, name, match_dest, invert=False):
        type_format = self._fw.ipset.get_ipset(name).type.split(":")[1].split(",")

        fragments = []
        for i in range(len(type_format)):
            if type_format[i] == "port":
                fragments.append({"meta": {"key": "l4proto"}})
                fragments.append({"payload": {"protocol": "th",
                                              "field": "dport" if match_dest else "sport"}})
            elif type_format[i] in ["ip", "net", "mac"]:
                fragments.append({"payload": {"protocol": self._set_get_family(name),
                                              "field": "daddr" if match_dest else "saddr"}})
            elif type_format[i] == "iface":
                fragments.append({"meta": {"key": "iifname" if match_dest else "oifname"}})
            elif type_format[i] == "mark":
                fragments.append({"meta": {"key": "mark"}})
            else:
                raise FirewallError("Unsupported ipset type for match fragment: %s" % (type_format[i]))

        return {"match": {"left": {"concat": fragments} if len(type_format) > 1 else fragments[0],
                          "op": "!=" if invert else "==",
                          "right": "@" + name}}

    def _set_entry_fragment(self, name, entry):
        # convert something like
        #    1.2.3.4,sctp:8080 (type hash:ip,port)
        # to
        #    ["1.2.3.4", "sctp", "8080"]
        obj = self._fw.ipset.get_ipset(name)
        type_format = obj.type.split(":")[1].split(",")
        entry_tokens = entry.split(",")
        if len(type_format) != len(entry_tokens):
            raise FirewallError(INVALID_ENTRY,
                                "Number of values does not match ipset type.")
        fragment = []
        for i in range(len(type_format)):
            if type_format[i] == "port":
                try:
                    index = entry_tokens[i].index(":")
                except ValueError:
                    # no protocol means default tcp
                    fragment.append("tcp")
                    port_str = entry_tokens[i]
                else:
                    fragment.append(entry_tokens[i][:index])
                    port_str = entry_tokens[i][index+1:]

                try:
                    index = port_str.index("-")
                except ValueError:
                    fragment.append(port_str)
                else:
                    fragment.append({"range": [port_str[:index], port_str[index+1:]]})

            elif type_format[i] in ["ip", "net"]:
                if '-' in entry_tokens[i]:
                    fragment.append({"range": entry_tokens[i].split('-') })
                else:
                    try:
                        index = entry_tokens[i].index("/")
                    except ValueError:
                        addr = entry_tokens[i]
                        if "family" in obj.options and obj.options["family"] == "inet6":
                            addr = normalizeIP6(addr)
                        fragment.append(addr)
                    else:
                        addr = entry_tokens[i][:index]
                        if "family" in obj.options and obj.options["family"] == "inet6":
                            addr = normalizeIP6(addr)
                        fragment.append({"prefix": {"addr": addr,
                                                    "len": int(entry_tokens[i][index+1:])}})
            else:
                fragment.append(entry_tokens[i])
        return [{"concat": fragment}] if len(type_format) > 1 else fragment

    def build_set_add_rules(self, name, entry):
        rules = []
        element = self._set_entry_fragment(name, entry)
        for family in ["inet", "ip", "ip6"]:
            rules.append({"add": {"element": {"family": family,
                                              "table": TABLE_NAME,
                                              "name": name,
                                              "elem": element}}})
        return rules

    def set_add(self, name, entry):
        rules = self.build_set_add_rules(name, entry)
        self.set_rules(rules, self._fw.get_log_denied())

    def set_delete(self, name, entry):
        element = self._set_entry_fragment(name, entry)
        for family in ["inet", "ip", "ip6"]:
            rule = {"delete": {"element": {"family": family,
                                           "table": TABLE_NAME,
                                           "name": name,
                                           "elem": element}}}
            self.set_rule(rule, self._fw.get_log_denied())

    def build_set_flush_rules(self, name):
        rules = []
        for family in ["inet", "ip", "ip6"]:
            rule = {"flush": {"set": {"family": family,
                                      "table": TABLE_NAME,
                                      "name": name}}}
            rules.append(rule)
        return rules

    def set_flush(self, name):
        rules = self.build_set_flush_rules(name)
        self.set_rules(rules, self._fw.get_log_denied())

    def _set_get_family(self, name):
        ipset = self._fw.ipset.get_ipset(name)

        if ipset.type == "hash:mac":
            family = "ether"
        elif ipset.options and "family" in ipset.options \
             and ipset.options["family"] == "inet6":
            family = "ip6"
        else:
            family = "ip"

        return family

    def set_restore(self, set_name, type_name, entries,
                    create_options=None, entry_options=None):
        rules = []
        rules.extend(self.build_set_create_rules(set_name, type_name, create_options))
        rules.extend(self.build_set_flush_rules(set_name))

        # avoid large memory usage by chunking the entries
        chunk = 0
        for entry in entries:
            rules.extend(self.build_set_add_rules(set_name, entry))
            chunk += 1
            if chunk >= 1000:
                self.set_rules(rules, self._fw.get_log_denied())
                rules.clear()
                chunk = 0
        else:
            self.set_rules(rules, self._fw.get_log_denied())
ipXtables.py000064400000170666151731527140007077 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import os.path
import copy

from firewall.core.prog import runProg
from firewall.core.logger import log
from firewall.functions import tempFile, readfile, splitArgs, check_mac, portStr, \
                               check_single_address, check_address, normalizeIP6
from firewall import config
from firewall.errors import FirewallError, INVALID_PASSTHROUGH, INVALID_RULE, UNKNOWN_ERROR, INVALID_ADDR
from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark, \
                               Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock
import string

POLICY_CHAIN_PREFIX = ""

BUILT_IN_CHAINS = {
    "security": [ "INPUT", "OUTPUT", "FORWARD" ],
    "raw": [ "PREROUTING", "OUTPUT" ],
    "mangle": [ "PREROUTING", "POSTROUTING", "INPUT", "OUTPUT", "FORWARD" ],
    "nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ],
    "filter": [ "INPUT", "OUTPUT", "FORWARD" ],
}

DEFAULT_REJECT_TYPE = {
    "ipv4": "icmp-host-prohibited",
    "ipv6": "icmp6-adm-prohibited",
}

ICMP = {
    "ipv4": "icmp",
    "ipv6": "ipv6-icmp",
}

# ipv ebtables also uses this
#
def common_reverse_rule(args):
    """ Inverse valid rule """

    replace_args = {
        # Append
        "-A": "-D",
        "--append": "--delete",
        # Insert
        "-I": "-D",
        "--insert": "--delete",
        # New chain
        "-N": "-X",
        "--new-chain": "--delete-chain",
    }

    ret_args = args[:]

    for arg in replace_args:
        try:
            idx = ret_args.index(arg)
        except Exception:
            continue

        if arg in [ "-I", "--insert" ]:
            # With insert rulenum, then remove it if it is a number
            # Opt at position idx, chain at position idx+1, [rulenum] at
            # position idx+2
            try:
                int(ret_args[idx+2])
            except Exception:
                pass
            else:
                ret_args.pop(idx+2)

        ret_args[idx] = replace_args[arg]
    return ret_args

def common_reverse_passthrough(args):
    """ Reverse valid passthough rule """

    replace_args = {
        # Append
        "-A": "-D",
        "--append": "--delete",
        # Insert
        "-I": "-D",
        "--insert": "--delete",
        # New chain
        "-N": "-X",
        "--new-chain": "--delete-chain",
    }

    ret_args = args[:]

    for x in replace_args:
        try:
            idx = ret_args.index(x)
        except ValueError:
            continue

        if x in [ "-I", "--insert" ]:
            # With insert rulenum, then remove it if it is a number
            # Opt at position idx, chain at position idx+1, [rulenum] at
            # position idx+2
            try:
                int(ret_args[idx+2])
            except ValueError:
                pass
            else:
                ret_args.pop(idx+2)

        ret_args[idx] = replace_args[x]
        return ret_args

    raise FirewallError(INVALID_PASSTHROUGH,
                        "no '-A', '-I' or '-N' arg")

# ipv ebtables also uses this
#
def common_check_passthrough(args):
    """ Check if passthough rule is valid (only add, insert and new chain
    rules are allowed) """

    args = set(args)
    not_allowed = set(["-C", "--check",           # check rule
                       "-D", "--delete",          # delete rule
                       "-R", "--replace",         # replace rule
                       "-L", "--list",            # list rule
                       "-S", "--list-rules",      # print rules
                       "-F", "--flush",           # flush rules
                       "-Z", "--zero",            # zero rules
                       "-X", "--delete-chain",    # delete chain
                       "-P", "--policy",          # policy
                       "-E", "--rename-chain"])   # rename chain)
    # intersection of args and not_allowed is not empty, i.e.
    # something from args is not allowed
    if len(args & not_allowed) > 0:
        raise FirewallError(INVALID_PASSTHROUGH,
                            "arg '%s' is not allowed" %
                            list(args & not_allowed)[0])

    # args need to contain one of -A, -I, -N
    needed = set(["-A", "--append",
                  "-I", "--insert",
                  "-N", "--new-chain"])
    # empty intersection of args and needed, i.e.
    # none from args contains any needed command
    if len(args & needed) == 0:
        raise FirewallError(INVALID_PASSTHROUGH,
                            "no '-A', '-I' or '-N' arg")

class ip4tables(object):
    ipv = "ipv4"
    name = "ip4tables"
    policies_supported = True

    def __init__(self, fw):
        self._fw = fw
        self._command = config.COMMANDS[self.ipv]
        self._restore_command = config.COMMANDS["%s-restore" % self.ipv]
        self.wait_option = self._detect_wait_option()
        self.restore_wait_option = self._detect_restore_wait_option()
        self.fill_exists()
        self.available_tables = []
        self.rich_rule_priority_counts = {}
        self.policy_priority_counts = {}
        self.zone_source_index_cache = []
        self.our_chains = {} # chains created by firewalld

    def fill_exists(self):
        self.command_exists = os.path.exists(self._command)
        self.restore_command_exists = os.path.exists(self._restore_command)

    def __run(self, args):
        # convert to string list
        if self.wait_option and self.wait_option not in args:
            _args = [self.wait_option] + ["%s" % item for item in args]
        else:
            _args = ["%s" % item for item in args]
        log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args))
        (status, ret) = runProg(self._command, _args)
        if status != 0:
            raise ValueError("'%s %s' failed: %s" % (self._command,
                                                     " ".join(_args), ret))
        return ret

    def _rule_replace(self, rule, pattern, replacement):
        try:
            i = rule.index(pattern)
        except ValueError:
            return False
        else:
            rule[i:i+1] = replacement
            return True

    def is_chain_builtin(self, ipv, table, chain):
        return table in BUILT_IN_CHAINS and \
               chain in BUILT_IN_CHAINS[table]

    def build_chain_rules(self, add, table, chain):
        rule = [ "-t", table ]
        if add:
            rule.append("-N")
        else:
            rule.append("-X")
        rule.append(chain)
        return [rule]

    def build_rule(self, add, table, chain, index, args):
        rule = [ "-t", table ]
        if add:
            rule += [ "-I", chain, str(index) ]
        else:
            rule += [ "-D", chain ]
        rule += args
        return rule

    def reverse_rule(self, args):
        return common_reverse_rule(args)

    def check_passthrough(self, args):
        common_check_passthrough(args)

    def reverse_passthrough(self, args):
        return common_reverse_passthrough(args)

    def passthrough_parse_table_chain(self, args):
        table = "filter"
        try:
            i = args.index("-t")
        except ValueError:
            pass
        else:
            if len(args) >= i+1:
                table = args[i+1]
        chain = None
        for opt in [ "-A", "--append",
                     "-I", "--insert",
                     "-N", "--new-chain" ]:
            try:
                i = args.index(opt)
            except ValueError:
                pass
            else:
                if len(args) >= i+1:
                    chain = args[i+1]
        return (table, chain)

    def _run_replace_zone_source(self, rule, zone_source_index_cache):
        try:
            i = rule.index("%%ZONE_SOURCE%%")
            rule.pop(i)
            zone = rule.pop(i)
            if "-m" == rule[4]: # ipset/mac
                zone_source = (zone, rule[7]) # (zone, address)
            else:
                zone_source = (zone, rule[5]) # (zone, address)
        except ValueError:
            try:
                i = rule.index("%%ZONE_INTERFACE%%")
                rule.pop(i)
                zone_source = None
            except ValueError:
                return

        rule_add = True
        if rule[0] in ["-D", "--delete"]:
            rule_add = False

        if zone_source and not rule_add:
            if zone_source in zone_source_index_cache:
                zone_source_index_cache.remove(zone_source)
        elif rule_add:
            if zone_source:
                # order source based dispatch by zone name
                if zone_source not in zone_source_index_cache:
                    zone_source_index_cache.append(zone_source)
                    zone_source_index_cache.sort(key=lambda x: x[0])

                index = zone_source_index_cache.index(zone_source)
            else:
                if self._fw._allow_zone_drifting:
                    index = 0
                else:
                    index = len(zone_source_index_cache)

            rule[0] = "-I"
            rule.insert(2, "%d" % (index + 1))

    def _set_rule_replace_priority(self, rule, priority_counts, token):
        """
        Change something like
          -t filter -I public_IN %%RICH_RULE_PRIORITY%% 123
        or
          -t filter -A public_IN %%RICH_RULE_PRIORITY%% 321
        into
          -t filter -I public_IN 4
        or
          -t filter -I public_IN
        """
        try:
            i = rule.index(token)
        except ValueError:
            pass
        else:
            rule_add = True
            insert = False
            insert_add_index = -1
            rule.pop(i)
            priority = rule.pop(i)
            if type(priority) != int:
                raise FirewallError(INVALID_RULE, "priority must be followed by a number")

            table = "filter"
            for opt in [ "-t", "--table" ]:
                try:
                    j = rule.index(opt)
                except ValueError:
                    pass
                else:
                    if len(rule) >= j+1:
                        table = rule[j+1]
            for opt in [ "-A", "--append",
                         "-I", "--insert",
                         "-D", "--delete" ]:
                try:
                    insert_add_index = rule.index(opt)
                except ValueError:
                    pass
                else:
                    if len(rule) >= insert_add_index+1:
                        chain = rule[insert_add_index+1]

                    if opt in [ "-I", "--insert" ]:
                        insert = True
                    if opt in [ "-D", "--delete" ]:
                        rule_add = False

            chain = (table, chain)

            # Add the rule to the priority counts. We don't need to store the
            # rule, just bump the ref count for the priority value.
            if not rule_add:
                if chain not in priority_counts or \
                   priority not in priority_counts[chain] or \
                   priority_counts[chain][priority] <= 0:
                    raise FirewallError(UNKNOWN_ERROR, "nonexistent or underflow of priority count")

                priority_counts[chain][priority] -= 1
            else:
                if chain not in priority_counts:
                    priority_counts[chain] = {}
                if priority not in priority_counts[chain]:
                    priority_counts[chain][priority] = 0

                # calculate index of new rule
                index = 1
                for p in sorted(priority_counts[chain].keys()):
                    if p == priority and insert:
                        break
                    index += priority_counts[chain][p]
                    if p == priority:
                        break

                priority_counts[chain][priority] += 1

                rule[insert_add_index] = "-I"
                rule.insert(insert_add_index+2, "%d" % index)

    def set_rules(self, rules, log_denied):
        temp_file = tempFile()

        table_rules = { }
        rich_rule_priority_counts = copy.deepcopy(self.rich_rule_priority_counts)
        policy_priority_counts = copy.deepcopy(self.policy_priority_counts)
        zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache)
        for _rule in rules:
            rule = _rule[:]

            # replace %%REJECT%%
            self._rule_replace(rule, "%%REJECT%%", \
                    ["REJECT", "--reject-with", DEFAULT_REJECT_TYPE[self.ipv]])

            # replace %%ICMP%%
            self._rule_replace(rule, "%%ICMP%%", [ICMP[self.ipv]])

            # replace %%LOGTYPE%%
            try:
                i = rule.index("%%LOGTYPE%%")
            except ValueError:
                pass
            else:
                if log_denied == "off":
                    continue
                if log_denied in [ "unicast", "broadcast", "multicast" ]:
                    rule[i:i+1] = [ "-m", "pkttype", "--pkt-type", log_denied ]
                else:
                    rule.pop(i)

            self._set_rule_replace_priority(rule, rich_rule_priority_counts, "%%RICH_RULE_PRIORITY%%")
            self._set_rule_replace_priority(rule, policy_priority_counts, "%%POLICY_PRIORITY%%")
            self._run_replace_zone_source(rule, zone_source_index_cache)

            table = "filter"
            # get table form rule
            for opt in [ "-t", "--table" ]:
                try:
                    i = rule.index(opt)
                except ValueError:
                    pass
                else:
                    if len(rule) >= i+1:
                        rule.pop(i)
                        table = rule.pop(i)

            # we can not use joinArgs here, because it would use "'" instead
            # of '"' for the start and end of the string, this breaks
            # iptables-restore
            for i in range(len(rule)):
                for c in string.whitespace:
                    if c in rule[i] and not (rule[i].startswith('"') and
                                             rule[i].endswith('"')):
                        rule[i] = '"%s"' % rule[i]

            table_rules.setdefault(table, []).append(rule)

        for table in table_rules:
            rules = table_rules[table]

            temp_file.write("*%s\n" % table)
            for rule in rules:
                temp_file.write(" ".join(rule) + "\n")
            temp_file.write("COMMIT\n")

        temp_file.close()

        stat = os.stat(temp_file.name)
        log.debug2("%s: %s %s", self.__class__, self._restore_command,
                   "%s: %d" % (temp_file.name, stat.st_size))
        args = [ ]
        if self.restore_wait_option:
            args.append(self.restore_wait_option)
        args.append("-n")

        (status, ret) = runProg(self._restore_command, args,
                                stdin=temp_file.name)

        if log.getDebugLogLevel() > 2:
            lines = readfile(temp_file.name)
            if lines is not None:
                i = 1
                for line in lines:
                    log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0)
                    if not line.endswith("\n"):
                        log.debug3("", nofmt=1)
                    i += 1

        os.unlink(temp_file.name)

        if status != 0:
            raise ValueError("'%s %s' failed: %s" % (self._restore_command,
                                                     " ".join(args), ret))
        self.rich_rule_priority_counts = rich_rule_priority_counts
        self.policy_priority_counts = policy_priority_counts
        self.zone_source_index_cache = zone_source_index_cache

    def set_rule(self, rule, log_denied):
        # replace %%REJECT%%
        self._rule_replace(rule, "%%REJECT%%", \
                ["REJECT", "--reject-with", DEFAULT_REJECT_TYPE[self.ipv]])

        # replace %%ICMP%%
        self._rule_replace(rule, "%%ICMP%%", [ICMP[self.ipv]])

        # replace %%LOGTYPE%%
        try:
            i = rule.index("%%LOGTYPE%%")
        except ValueError:
            pass
        else:
            if log_denied == "off":
                return ""
            if log_denied in [ "unicast", "broadcast", "multicast" ]:
                rule[i:i+1] = [ "-m", "pkttype", "--pkt-type", log_denied ]
            else:
                rule.pop(i)

        rich_rule_priority_counts = copy.deepcopy(self.rich_rule_priority_counts)
        policy_priority_counts = copy.deepcopy(self.policy_priority_counts)
        zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache)
        self._set_rule_replace_priority(rule, rich_rule_priority_counts, "%%RICH_RULE_PRIORITY%%")
        self._set_rule_replace_priority(rule, policy_priority_counts, "%%POLICY_PRIORITY%%")
        self._run_replace_zone_source(rule, zone_source_index_cache)

        output = self.__run(rule)

        self.rich_rule_priority_counts = rich_rule_priority_counts
        self.policy_priority_counts = policy_priority_counts
        self.zone_source_index_cache = zone_source_index_cache
        return output

    def get_available_tables(self, table=None):
        ret = []
        tables = [ table ] if table else BUILT_IN_CHAINS.keys()
        for table in tables:
            if table in self.available_tables:
                ret.append(table)
            else:
                try:
                    self.__run(["-t", table, "-L", "-n"])
                    self.available_tables.append(table)
                    ret.append(table)
                except ValueError:
                    log.debug1("%s table '%s' does not exist (or not enough permission to check)." % (self.ipv, table))

        return ret

    def _detect_wait_option(self):
        wait_option = ""
        ret = runProg(self._command, ["-w", "-L", "-n"])  # since iptables-1.4.20
        if ret[0] == 0:
            wait_option = "-w"  # wait for xtables lock
            ret = runProg(self._command, ["-w10", "-L", "-n"])  # since iptables > 1.4.21
            if ret[0] == 0:
                wait_option = "-w10"  # wait max 10 seconds
            log.debug2("%s: %s will be using %s option.", self.__class__, self._command, wait_option)

        return wait_option

    def _detect_restore_wait_option(self):
        temp_file = tempFile()
        temp_file.write("#foo")
        temp_file.close()

        wait_option = ""
        for test_option in ["-w", "--wait=2"]:
            ret = runProg(self._restore_command, [test_option], stdin=temp_file.name)
            if ret[0] == 0 and "invalid option" not in ret[1] \
                           and "unrecognized option" not in ret[1]:
                wait_option = test_option
                break

        log.debug2("%s: %s will be using %s option.", self.__class__, self._restore_command, wait_option)

        os.unlink(temp_file.name)

        return wait_option

    def build_flush_rules(self):
        self.rich_rule_priority_counts = {}
        self.policy_priority_counts = {}
        self.zone_source_index_cache = []
        rules = []
        for table in BUILT_IN_CHAINS.keys():
            if not self.get_available_tables(table):
                continue
            # Flush firewall rules: -F
            # Delete firewall chains: -X
            # Set counter to zero: -Z
            for flag in [ "-F", "-X", "-Z" ]:
                rules.append(["-t", table, flag])
        return rules

    def build_set_policy_rules(self, policy):
        rules = []
        _policy = "DROP" if policy == "PANIC" else policy
        for table in BUILT_IN_CHAINS.keys():
            if not self.get_available_tables(table):
                continue
            if table == "nat":
                continue
            for chain in BUILT_IN_CHAINS[table]:
                rules.append(["-t", table, "-P", chain, _policy])
        return rules

    def supported_icmp_types(self, ipv=None):
        """Return ICMP types that are supported by the iptables/ip6tables command and kernel"""
        ret = [ ]
        output = ""
        try:
            output = self.__run(["-p",
                                 "icmp" if self.ipv == "ipv4" else "ipv6-icmp",
                                 "--help"])
        except ValueError as ex:
            if self.ipv == "ipv4":
                log.debug1("iptables error: %s" % ex)
            else:
                log.debug1("ip6tables error: %s" % ex)
        lines = output.splitlines()

        in_types = False
        for line in lines:
            #print(line)
            if in_types:
                line = line.strip().lower()
                splits = line.split()
                for split in splits:
                    if split.startswith("(") and split.endswith(")"):
                        x = split[1:-1]
                    else:
                        x = split
                    if x not in ret:
                        ret.append(x)
            if self.ipv == "ipv4" and line.startswith("Valid ICMP Types:") or \
               self.ipv == "ipv6" and line.startswith("Valid ICMPv6 Types:"):
                in_types = True
        return ret

    def build_default_tables(self):
        # nothing to do, they always exist
        return []

    def build_default_rules(self, log_denied="off"):
        default_rules = {}

        if self.get_available_tables("security"):
            default_rules["security"] = [ ]
            self.our_chains["security"] = set()
            for chain in BUILT_IN_CHAINS["security"]:
                default_rules["security"].append("-N %s_direct" % chain)
                default_rules["security"].append("-A %s -j %s_direct" % (chain, chain))
                self.our_chains["security"].add("%s_direct" % chain)

        if self.get_available_tables("raw"):
            default_rules["raw"] = [ ]
            self.our_chains["raw"] = set()
            for chain in BUILT_IN_CHAINS["raw"]:
                default_rules["raw"].append("-N %s_direct" % chain)
                default_rules["raw"].append("-A %s -j %s_direct" % (chain, chain))
                self.our_chains["raw"].add("%s_direct" % chain)

                if chain == "PREROUTING":
                    for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
                        default_rules["raw"].append("-N %s_%s" % (chain, dispatch_suffix))
                        default_rules["raw"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix))
                        self.our_chains["raw"].update(set(["%s_%s" % (chain, dispatch_suffix)]))

        if self.get_available_tables("mangle"):
            default_rules["mangle"] = [ ]
            self.our_chains["mangle"] = set()
            for chain in BUILT_IN_CHAINS["mangle"]:
                default_rules["mangle"].append("-N %s_direct" % chain)
                default_rules["mangle"].append("-A %s -j %s_direct" % (chain, chain))
                self.our_chains["mangle"].add("%s_direct" % chain)

                if chain == "PREROUTING":
                    for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
                        default_rules["mangle"].append("-N %s_%s" % (chain, dispatch_suffix))
                        default_rules["mangle"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix))
                        self.our_chains["mangle"].update(set(["%s_%s" % (chain, dispatch_suffix)]))

        if self.get_available_tables("nat"):
            default_rules["nat"] = [ ]
            self.our_chains["nat"] = set()
            for chain in BUILT_IN_CHAINS["nat"]:
                default_rules["nat"].append("-N %s_direct" % chain)
                default_rules["nat"].append("-A %s -j %s_direct" % (chain, chain))
                self.our_chains["nat"].add("%s_direct" % chain)

                if chain in [ "PREROUTING", "POSTROUTING" ]:
                    for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
                        default_rules["nat"].append("-N %s_%s" % (chain, dispatch_suffix))
                        default_rules["nat"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix))
                        self.our_chains["nat"].update(set(["%s_%s" % (chain, dispatch_suffix)]))

        default_rules["filter"] = []
        self.our_chains["filter"] = set()
        default_rules["filter"].append("-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT")
        default_rules["filter"].append("-A INPUT -i lo -j ACCEPT")
        default_rules["filter"].append("-N INPUT_direct")
        default_rules["filter"].append("-A INPUT -j INPUT_direct")
        self.our_chains["filter"].update(set("INPUT_direct"))
        for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]:
            default_rules["filter"].append("-N INPUT_%s" % (dispatch_suffix))
            default_rules["filter"].append("-A INPUT -j INPUT_%s" % (dispatch_suffix))
            self.our_chains["filter"].update(set("INPUT_%s" % (dispatch_suffix)))
        if log_denied != "off":
            default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '")
        default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID -j DROP")
        if log_denied != "off":
            default_rules["filter"].append("-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '")
        default_rules["filter"].append("-A INPUT -j %%REJECT%%")

        default_rules["filter"].append("-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT")
        default_rules["filter"].append("-A FORWARD -i lo -j ACCEPT")
        default_rules["filter"].append("-N FORWARD_direct")
        default_rules["filter"].append("-A FORWARD -j FORWARD_direct")
        self.our_chains["filter"].update(set("FORWARD_direct"))
        for dispatch_suffix in ["POLICIES_pre"]:
            default_rules["filter"].append("-N FORWARD_%s" % (dispatch_suffix))
            default_rules["filter"].append("-A FORWARD -j FORWARD_%s" % (dispatch_suffix))
            self.our_chains["filter"].update(set("FORWARD_%s" % (dispatch_suffix)))
        for direction in ["IN", "OUT"]:
            for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]:
                default_rules["filter"].append("-N FORWARD_%s_%s" % (direction, dispatch_suffix))
                default_rules["filter"].append("-A FORWARD -j FORWARD_%s_%s" % (direction, dispatch_suffix))
                self.our_chains["filter"].update(set("FORWARD_%s_%s" % (direction, dispatch_suffix)))
        for dispatch_suffix in ["POLICIES_post"]:
            default_rules["filter"].append("-N FORWARD_%s" % (dispatch_suffix))
            default_rules["filter"].append("-A FORWARD -j FORWARD_%s" % (dispatch_suffix))
            self.our_chains["filter"].update(set("FORWARD_%s" % (dispatch_suffix)))
        if log_denied != "off":
            default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '")
        default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID -j DROP")
        if log_denied != "off":
            default_rules["filter"].append("-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '")
        default_rules["filter"].append("-A FORWARD -j %%REJECT%%")

        default_rules["filter"] += [
            "-N OUTPUT_direct",

            "-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT",
            "-A OUTPUT -o lo -j ACCEPT",
            "-A OUTPUT -j OUTPUT_direct",
        ]
        self.our_chains["filter"].update(set("OUTPUT_direct"))
        for dispatch_suffix in ["POLICIES_pre"]:
            default_rules["filter"].append("-N OUTPUT_%s" % (dispatch_suffix))
            default_rules["filter"].append("-A OUTPUT -j OUTPUT_%s" % (dispatch_suffix))
            self.our_chains["filter"].update(set("OUTPUT_%s" % (dispatch_suffix)))
        for dispatch_suffix in ["POLICIES_post"]:
            default_rules["filter"].append("-N OUTPUT_%s" % (dispatch_suffix))
            default_rules["filter"].append("-A OUTPUT -j OUTPUT_%s" % (dispatch_suffix))
            self.our_chains["filter"].update(set("OUTPUT_%s" % (dispatch_suffix)))

        final_default_rules = []
        for table in default_rules:
            if table not in self.get_available_tables():
                continue
            for rule in default_rules[table]:
                final_default_rules.append(["-t", table] + splitArgs(rule))

        return final_default_rules

    def get_zone_table_chains(self, table):
        if table == "filter":
            return { "INPUT", "FORWARD_IN", "FORWARD_OUT" }
        if table == "mangle":
            if "mangle" in self.get_available_tables():
                return { "PREROUTING" }
        if table == "nat":
            if "nat" in self.get_available_tables():
                return { "PREROUTING", "POSTROUTING" }
        if table == "raw":
            if "raw" in self.get_available_tables():
                return { "PREROUTING" }

        return {}

    def build_policy_ingress_egress_rules(self, enable, policy, table, chain,
                                          ingress_interfaces, egress_interfaces,
                                          ingress_sources, egress_sources):
        p_obj = self._fw.policy.get_policy(policy)
        chain_suffix = "pre" if p_obj.priority < 0 else "post"
        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT)

        ingress_fragments = []
        egress_fragments = []
        for interface in ingress_interfaces:
            ingress_fragments.append(["-i", interface])
        for interface in egress_interfaces:
            egress_fragments.append(["-o", interface])
        for addr in ingress_sources:
            ipv = self._fw.zone.check_source(addr)
            if ipv in ["ipv4", "ipv6"] and not self.is_ipv_supported(ipv):
                continue
            ingress_fragments.append(self._rule_addr_fragment("-s", addr))
        for addr in egress_sources:
            ipv = self._fw.zone.check_source(addr)
            if ipv in ["ipv4", "ipv6"] and not self.is_ipv_supported(ipv):
                continue
            # iptables can not match destination MAC
            if check_mac(addr) and chain in ["POSTROUTING", "FORWARD_OUT", "OUTPUT"]:
                continue

            egress_fragments.append(self._rule_addr_fragment("-d", addr))

        def _generate_policy_dispatch_rule(ingress_fragment, egress_fragment):
            add_del = {True: "-A", False: "-D" }[enable]
            rule = ["-t", table, add_del, "%s_POLICIES_%s" % (chain, chain_suffix),
                    "%%POLICY_PRIORITY%%", p_obj.priority]
            if ingress_fragment:
                rule.extend(ingress_fragment)
            if egress_fragment:
                rule.extend(egress_fragment)
            rule.extend(["-j", _policy])

            return rule

        rules = []
        if ingress_fragments:
            # zone --> [zone, ANY, HOST]
            for ingress_fragment in ingress_fragments:
                # zone --> zone
                if egress_fragments:
                    for egress_fragment in egress_fragments:
                        rules.append(_generate_policy_dispatch_rule(ingress_fragment, egress_fragment))
                elif egress_sources:
                    # if the egress source is not for the current family (there
                    # are no egress fragments), then avoid creating an invalid
                    # catch all rule.
                    pass
                else:
                    rules.append(_generate_policy_dispatch_rule(ingress_fragment, None))
        elif ingress_sources:
            # if the ingress source is not for the current family (there are no
            # ingress fragments), then avoid creating an invalid catch all
            # rule.
            pass
        else: # [ANY, HOST] --> [zone, ANY, HOST]
            # [ANY, HOST] --> zone
            if egress_fragments:
                for egress_fragment in egress_fragments:
                    rules.append(_generate_policy_dispatch_rule(None, egress_fragment))
            elif egress_sources:
                # if the egress source is not for the current family (there
                # are no egress fragments), then avoid creating an invalid
                # catch all rule.
                pass
            else:
                # [ANY, HOST] --> [ANY, HOST]
                rules.append(_generate_policy_dispatch_rule(None, None))

        return rules

    def build_zone_source_interface_rules(self, enable, zone, policy, interface,
                                          table, chain, append=False):
        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT)
        opt = {
            "PREROUTING": "-i",
            "POSTROUTING": "-o",
            "INPUT": "-i",
            "FORWARD_IN": "-i",
            "FORWARD_OUT": "-o",
            "OUTPUT": "-o",
        }[chain]

        action = "-g"

        if enable and not append:
            rule = [ "-I", "%s_ZONES" % chain, "%%ZONE_INTERFACE%%" ]
        elif enable:
            rule = [ "-A", "%s_ZONES" % chain ]
        else:
            rule = [ "-D", "%s_ZONES" % chain ]
            if not append:
                rule += ["%%ZONE_INTERFACE%%"]
        rule += [ "-t", table, opt, interface, action, _policy ]
        return [rule]

    def _rule_addr_fragment(self, opt, address, invert=False):
        if address.startswith("ipset:"):
            name = address[6:]
            if opt == "-d":
                opt = "dst"
            else:
                opt = "src"
            flags = ",".join([opt] * self._fw.ipset.get_dimension(name))
            return ["-m", "set", "--match-set", name, flags]
        elif check_mac(address):
            # outgoing can not be set
            if opt == "-d":
                raise FirewallError(INVALID_ADDR, "Can't match a destination MAC.")
            return ["-m", "mac", "--mac-source", address.upper()]
        else:
            if check_single_address("ipv6", address):
                address = normalizeIP6(address)
            elif check_address("ipv6", address):
                addr_split = address.split("/")
                address = normalizeIP6(addr_split[0]) + "/" + addr_split[1]
            return [opt, address]

    def build_zone_source_address_rules(self, enable, zone, policy,
                                        address, table, chain):
        add_del = { True: "-I", False: "-D" }[enable]

        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT)
        opt = {
            "PREROUTING": "-s",
            "POSTROUTING": "-d",
            "INPUT": "-s",
            "FORWARD_IN": "-s",
            "FORWARD_OUT": "-d",
            "OUTPUT": "-d",
        }[chain]

        if self._fw._allow_zone_drifting:
            zone_dispatch_chain = "%s_ZONES_SOURCE" % (chain)
        else:
            zone_dispatch_chain = "%s_ZONES" % (chain)

        # iptables can not match destination MAC
        if check_mac(address) and chain in ["POSTROUTING", "FORWARD_OUT", "OUTPUT"]:
            return []

        rule = [add_del, zone_dispatch_chain, "%%ZONE_SOURCE%%", zone, "-t", table]
        rule.extend(self._rule_addr_fragment(opt, address))
        rule.extend(["-g", _policy])

        return [rule]

    def build_policy_chain_rules(self, enable, policy, table, chain):
        add_del_chain = { True: "-N", False: "-X" }[enable]
        add_del_rule = { True: "-A", False: "-D" }[enable]
        isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT)

        self.our_chains[table].update(set([_policy,
                                      "%s_log" % _policy,
                                      "%s_deny" % _policy,
                                      "%s_pre" % _policy,
                                      "%s_post" % _policy,
                                      "%s_allow" % _policy]))

        rules = []
        rules.append([ add_del_chain, _policy, "-t", table ])
        rules.append([ add_del_chain, "%s_pre" % _policy, "-t", table ])
        rules.append([ add_del_chain, "%s_log" % _policy, "-t", table ])
        rules.append([ add_del_chain, "%s_deny" % _policy, "-t", table ])
        rules.append([ add_del_chain, "%s_allow" % _policy, "-t", table ])
        rules.append([ add_del_chain, "%s_post" % _policy, "-t", table ])
        rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_pre" % _policy ])
        rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_log" % _policy ])
        rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_deny" % _policy ])
        rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_allow" % _policy ])
        rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_post" % _policy ])

        target = self._fw.policy._policies[policy].target

        if self._fw.get_log_denied() != "off":
            if table == "filter":
                if target in [ "REJECT", "%%REJECT%%" ]:
                    rules.append([ add_del_rule, _policy, "-t", table, "%%LOGTYPE%%",
                                   "-j", "LOG", "--log-prefix",
                                   "\"%s_REJECT: \"" % _policy ])
                if target == "DROP":
                    rules.append([ add_del_rule, _policy, "-t", table, "%%LOGTYPE%%",
                                   "-j", "LOG", "--log-prefix",
                                   "\"%s_DROP: \"" % _policy ])

        if table == "filter" and \
           target in [ "ACCEPT", "REJECT", "%%REJECT%%", "DROP" ]:
            rules.append([ add_del_rule, _policy, "-t", table, "-j", target ])

        if not enable:
            rules.reverse()

        return rules

    def _rule_limit(self, limit):
        if not limit:
            return []
        s = ["-m", "limit", "--limit", limit.value]
        if limit.burst is not None:
            s += ["--limit-burst", limit.burst]
        return s

    def _rich_rule_chain_suffix(self, rich_rule):
        if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock]:
            # These are special and don't have an explicit action
            pass
        elif rich_rule.action:
            if type(rich_rule.action) not in [Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark]:
                raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action))
        else:
            raise FirewallError(INVALID_RULE, "No rule action specified.")

        if rich_rule.priority == 0:
            if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort] or \
               type(rich_rule.action) in [Rich_Accept, Rich_Mark]:
                return "allow"
            elif type(rich_rule.element) in [Rich_IcmpBlock] or \
                 type(rich_rule.action) in [Rich_Reject, Rich_Drop]:
                return "deny"
        elif rich_rule.priority < 0:
            return "pre"
        else:
            return "post"

    def _rich_rule_chain_suffix_from_log(self, rich_rule):
        if not rich_rule.log and not rich_rule.audit:
            raise FirewallError(INVALID_RULE, "Not log or audit")

        if rich_rule.priority == 0:
            return "log"
        elif rich_rule.priority < 0:
            return "pre"
        else:
            return "post"

    def _rich_rule_priority_fragment(self, rich_rule):
        if rich_rule.priority == 0:
            return []
        return ["%%RICH_RULE_PRIORITY%%", rich_rule.priority]

    def _rich_rule_log(self, policy, rich_rule, enable, table, rule_fragment):
        if not rich_rule.log:
            return []

        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        add_del = { True: "-A", False: "-D" }[enable]

        chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule)
        rule = ["-t", table, add_del, "%s_%s" % (_policy, chain_suffix)]
        rule += self._rich_rule_priority_fragment(rich_rule)
        rule += rule_fragment + [ "-j", "LOG" ]
        if rich_rule.log.prefix:
            rule += [ "--log-prefix", "'%s'" % rich_rule.log.prefix ]
        if rich_rule.log.level:
            rule += [ "--log-level", "%s" % rich_rule.log.level ]
        rule += self._rule_limit(rich_rule.log.limit)

        return rule

    def _rich_rule_audit(self, policy, rich_rule, enable, table, rule_fragment):
        if not rich_rule.audit:
            return []

        add_del = { True: "-A", False: "-D" }[enable]

        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule)
        rule = ["-t", table, add_del, "%s_%s" % (_policy, chain_suffix)]
        rule += self._rich_rule_priority_fragment(rich_rule)
        rule += rule_fragment
        if type(rich_rule.action) == Rich_Accept:
            _type = "accept"
        elif type(rich_rule.action) == Rich_Reject:
            _type = "reject"
        elif type(rich_rule.action) ==  Rich_Drop:
            _type = "drop"
        else:
            _type = "unknown"
        rule += [ "-j", "AUDIT", "--type", _type ]
        rule += self._rule_limit(rich_rule.audit.limit)

        return rule

    def _rich_rule_action(self, policy, rich_rule, enable, table, rule_fragment):
        if not rich_rule.action:
            return []

        add_del = { True: "-A", False: "-D" }[enable]

        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        chain_suffix = self._rich_rule_chain_suffix(rich_rule)
        chain = "%s_%s" % (_policy, chain_suffix)
        if type(rich_rule.action) == Rich_Accept:
            rule_action = [ "-j", "ACCEPT" ]
        elif type(rich_rule.action) == Rich_Reject:
            rule_action = [ "-j", "REJECT" ]
            if rich_rule.action.type:
                rule_action += [ "--reject-with", rich_rule.action.type ]
        elif type(rich_rule.action) ==  Rich_Drop:
            rule_action = [ "-j", "DROP" ]
        elif type(rich_rule.action) == Rich_Mark:
            table = "mangle"
            _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
            chain = "%s_%s" % (_policy, chain_suffix)
            rule_action = [ "-j", "MARK", "--set-xmark", rich_rule.action.set ]
        else:
            raise FirewallError(INVALID_RULE,
                                "Unknown action %s" % type(rich_rule.action))

        rule = ["-t", table, add_del, chain]
        rule += self._rich_rule_priority_fragment(rich_rule)
        rule += rule_fragment + rule_action
        rule += self._rule_limit(rich_rule.action.limit)

        return rule

    def _rich_rule_destination_fragment(self, rich_dest):
        if not rich_dest:
            return []

        rule_fragment = []
        if rich_dest.addr:
            if rich_dest.invert:
                rule_fragment.append("!")
            if check_single_address("ipv6", rich_dest.addr):
                rule_fragment += [ "-d", normalizeIP6(rich_dest.addr) ]
            elif check_address("ipv6", rich_dest.addr):
                addr_split = rich_dest.addr.split("/")
                rule_fragment += [ "-d", normalizeIP6(addr_split[0]) + "/" + addr_split[1] ]
            else:
                rule_fragment += [ "-d", rich_dest.addr ]
        elif rich_dest.ipset:
            rule_fragment += [ "-m", "set" ]
            if rich_dest.invert:
                rule_fragment.append("!")
            flags = self._fw.zone._ipset_match_flags(rich_dest.ipset, "dst")
            rule_fragment += [ "--match-set", rich_dest.ipset, flags ]

        return rule_fragment

    def _rich_rule_source_fragment(self, rich_source):
        if not rich_source:
            return []

        rule_fragment = []
        if rich_source.addr:
            if rich_source.invert:
                rule_fragment.append("!")
            if check_single_address("ipv6", rich_source.addr):
                rule_fragment += [ "-s", normalizeIP6(rich_source.addr) ]
            elif check_address("ipv6", rich_source.addr):
                addr_split = rich_source.addr.split("/")
                rule_fragment += [ "-s", normalizeIP6(addr_split[0]) + "/" + addr_split[1] ]
            else:
                rule_fragment += [ "-s", rich_source.addr ]
        elif hasattr(rich_source, "mac") and rich_source.mac:
            rule_fragment += [ "-m", "mac" ]
            if rich_source.invert:
                rule_fragment.append("!")
            rule_fragment += [ "--mac-source", rich_source.mac ]
        elif hasattr(rich_source, "ipset") and rich_source.ipset:
            rule_fragment += [ "-m", "set" ]
            if rich_source.invert:
                rule_fragment.append("!")
            flags = self._fw.zone._ipset_match_flags(rich_source.ipset, "src")
            rule_fragment += [ "--match-set", rich_source.ipset, flags ]

        return rule_fragment

    def build_policy_ports_rules(self, enable, policy, proto, port, destination=None, rich_rule=None):
        add_del = { True: "-A", False: "-D" }[enable]
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        rule_fragment = [ "-p", proto ]
        if port:
            rule_fragment += [ "--dport", "%s" % portStr(port) ]
        if destination:
            rule_fragment += [ "-d", destination ]
        if rich_rule:
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        if not rich_rule or type(rich_rule.action) != Rich_Mark:
            rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ]

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment))
        else:
            rules.append([add_del, "%s_allow" % (_policy), "-t", table] +
                         rule_fragment + [ "-j", "ACCEPT" ])

        return rules

    def build_policy_protocol_rules(self, enable, policy, protocol, destination=None, rich_rule=None):
        add_del = { True: "-A", False: "-D" }[enable]
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        rule_fragment = [ "-p", protocol ]
        if destination:
            rule_fragment += [ "-d", destination ]
        if rich_rule:
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        if not rich_rule or type(rich_rule.action) != Rich_Mark:
            rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ]

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment))
        else:
            rules.append([add_del, "%s_allow" % (_policy), "-t", table] +
                         rule_fragment + [ "-j", "ACCEPT" ])

        return rules

    def build_policy_source_ports_rules(self, enable, policy, proto, port,
                                     destination=None, rich_rule=None):
        add_del = { True: "-A", False: "-D" }[enable]
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        rule_fragment = [ "-p", proto ]
        if port:
            rule_fragment += [ "--sport", "%s" % portStr(port) ]
        if destination:
            rule_fragment += [ "-d", destination ]
        if rich_rule:
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        if not rich_rule or type(rich_rule.action) != Rich_Mark:
            rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ]

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment))
        else:
            rules.append([add_del, "%s_allow" % (_policy), "-t", table] +
                         rule_fragment + [ "-j", "ACCEPT" ])

        return rules

    def build_policy_helper_ports_rules(self, enable, policy, proto, port,
                                      destination, helper_name, module_short_name):
        table = "raw"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "-A", False: "-D" }[enable]

        rule = [ add_del, "%s_allow" % (_policy), "-t", "raw", "-p", proto ]
        if port:
            rule += [ "--dport", "%s" % portStr(port) ]
        if destination:
            rule += [ "-d",  destination ]
        rule += [ "-j", "CT", "--helper", module_short_name ]

        return [rule]

    def build_zone_forward_rules(self, enable, zone, policy, table, interface=None, source=None):
        add_del = { True: "-A", False: "-D" }[enable]
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        rules = []
        if interface:
            rules.append(["-t", "filter", add_del, "%s_allow" % _policy,
                          "-o", interface, "-j", "ACCEPT"])
        else: # source
            # iptables can not match destination MAC
            if check_mac(source):
                return []

            rules.append(["-t", "filter", add_del, "%s_allow" % _policy]
                         + self._rule_addr_fragment("-d", source) +
                         ["-j", "ACCEPT"])
        return rules

    def build_policy_masquerade_rules(self, enable, policy, rich_rule=None):
        table = "nat"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=True)

        add_del = { True: "-A", False: "-D" }[enable]

        rule_fragment = []
        if rich_rule:
            chain_suffix = self._rich_rule_chain_suffix(rich_rule)
            rule_fragment += self._rich_rule_priority_fragment(rich_rule)
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        else:
            chain_suffix = "allow"

        rules = []
        rules.append(["-t", "nat", add_del, "%s_%s" % (_policy, chain_suffix)]
                     + rule_fragment +
                     [ "!", "-o", "lo", "-j", "MASQUERADE" ])

        rule_fragment = []
        if rich_rule:
            chain_suffix = self._rich_rule_chain_suffix(rich_rule)
            rule_fragment += self._rich_rule_priority_fragment(rich_rule)
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        else:
            chain_suffix = "allow"

        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        rules.append(["-t", "filter", add_del, "%s_%s" % (_policy, chain_suffix)]
                     + rule_fragment +
                     ["-m", "conntrack", "--ctstate", "NEW,UNTRACKED", "-j", "ACCEPT" ])

        return rules

    def build_policy_forward_port_rules(self, enable, policy, port,
                                      protocol, toport, toaddr, rich_rule=None):
        table = "nat"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "-A", False: "-D" }[enable]

        to = ""
        if toaddr:
            if check_single_address("ipv6", toaddr):
                to += "[%s]" % normalizeIP6(toaddr)
            else:
                to += toaddr
        if toport and toport != "":
            to += ":%s" % portStr(toport, "-")

        rule_fragment = []
        if rich_rule:
            chain_suffix = self._rich_rule_chain_suffix(rich_rule)
            rule_fragment = self._rich_rule_priority_fragment(rich_rule)
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        else:
            chain_suffix = "allow"

        rules = []
        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, "nat", rule_fragment))
        rules.append(["-t", "nat", add_del, "%s_%s" % (_policy, chain_suffix)]
                     + rule_fragment +
                     ["-p", protocol, "--dport", portStr(port),
                      "-j", "DNAT", "--to-destination", to])

        return rules

    def build_policy_icmp_block_rules(self, enable, policy, ict, rich_rule=None):
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
        add_del = { True: "-A", False: "-D" }[enable]

        if self.ipv == "ipv4":
            proto = [ "-p", "icmp" ]
            match = [ "-m", "icmp", "--icmp-type", ict.name ]
        else:
            proto = [ "-p", "ipv6-icmp" ]
            match = [ "-m", "icmp6", "--icmpv6-type", ict.name ]

        rules = []
        if self._fw.policy.query_icmp_block_inversion(policy):
            final_chain = "%s_allow" % (_policy)
            final_target = "ACCEPT"
        else:
            final_chain = "%s_deny" % (_policy)
            final_target = "%%REJECT%%"

        rule_fragment = []
        if rich_rule:
            rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
            rule_fragment += self._rich_rule_source_fragment(rich_rule.source)
        rule_fragment += proto + match

        if rich_rule:
            rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment))
            rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment))
            if rich_rule.action:
                rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment))
            else:
                chain_suffix = self._rich_rule_chain_suffix(rich_rule)
                rules.append(["-t", table, add_del, "%s_%s" % (_policy, chain_suffix)]
                             + self._rich_rule_priority_fragment(rich_rule)
                             + rule_fragment +
                             [ "-j", "%%REJECT%%" ])
        else:
            if self._fw.get_log_denied() != "off" and final_target != "ACCEPT":
                rules.append([ add_del, final_chain, "-t", table ]
                             + rule_fragment +
                             [ "%%LOGTYPE%%", "-j", "LOG",
                               "--log-prefix", "\"%s_ICMP_BLOCK: \"" % policy ])
            rules.append([ add_del, final_chain, "-t", table ]
                         + rule_fragment +
                         [ "-j", final_target ])

        return rules

    def build_policy_icmp_block_inversion_rules(self, enable, policy):
        table = "filter"
        _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)

        rules = []
        rule_idx = 6

        if self._fw.policy.query_icmp_block_inversion(policy):
            ibi_target = "%%REJECT%%"

            if self._fw.get_log_denied() != "off":
                if enable:
                    rule = [ "-I", _policy, str(rule_idx) ]
                else:
                    rule = [ "-D", _policy ]

                rule = rule + [ "-t", table, "-p", "%%ICMP%%",
                              "%%LOGTYPE%%",
                              "-j", "LOG", "--log-prefix",
                              "\"%s_ICMP_BLOCK: \"" % _policy ]
                rules.append(rule)
                rule_idx += 1
        else:
            ibi_target = "ACCEPT"

        if enable:
            rule = [ "-I", _policy, str(rule_idx) ]
        else:
            rule = [ "-D", _policy ]
        rule = rule + [ "-t", table, "-p", "%%ICMP%%", "-j", ibi_target ]
        rules.append(rule)

        return rules

    def build_policy_rich_source_destination_rules(self, enable, policy, rich_rule):
        table = "filter"

        rule_fragment = []
        rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination)
        rule_fragment += self._rich_rule_source_fragment(rich_rule.source)

        rules = []
        rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment))
        rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment))
        rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment))

        return rules

    def is_ipv_supported(self, ipv):
        return ipv == self.ipv

class ip6tables(ip4tables):
    ipv = "ipv6"
    name = "ip6tables"

    def build_rpfilter_rules(self, log_denied=False):
        rules = []
        rules.append([ "-I", "PREROUTING", "-t", "mangle",
                       "-m", "rpfilter", "--invert", "--validmark",
                       "-j", "DROP" ])
        if log_denied != "off":
            rules.append([ "-I", "PREROUTING", "-t", "mangle",
                           "-m", "rpfilter", "--invert", "--validmark",
                           "-j", "LOG",
                           "--log-prefix", "rpfilter_DROP: " ])
        rules.append([ "-I", "PREROUTING", "-t", "mangle",
                       "-p", "ipv6-icmp",
                       "--icmpv6-type=neighbour-solicitation",
                       "-j", "ACCEPT" ]) # RHBZ#1575431, kernel bug in 4.16-4.17
        rules.append([ "-I", "PREROUTING", "-t", "mangle",
                       "-p", "ipv6-icmp",
                       "--icmpv6-type=router-advertisement",
                       "-j", "ACCEPT" ]) # RHBZ#1058505
        return rules

    def build_rfc3964_ipv4_rules(self):
        daddr_list = [
                     "::0.0.0.0/96", # IPv4 compatible
                     "::ffff:0.0.0.0/96", # IPv4 mapped
                     "2002:0000::/24", # 0.0.0.0/8 (the system has no address assigned yet)
                     "2002:0a00::/24", # 10.0.0.0/8 (private)
                     "2002:7f00::/24", # 127.0.0.0/8 (loopback)
                     "2002:ac10::/28", # 172.16.0.0/12 (private)
                     "2002:c0a8::/32", # 192.168.0.0/16 (private)
                     "2002:a9fe::/32", # 169.254.0.0/16 (IANA Assigned DHCP link-local)
                     "2002:e000::/19", # 224.0.0.0/4 (multicast), 240.0.0.0/4 (reserved and broadcast)
                     ]

        chain_name = "RFC3964_IPv4"
        self.our_chains["filter"].add(chain_name)

        rules = []
        rules.append(["-t", "filter", "-N", chain_name])
        for daddr in daddr_list:
            rules.append(["-t", "filter", "-I", chain_name,
                          "-d", daddr, "-j", "REJECT", "--reject-with",
                          "addr-unreach"])
            if self._fw._log_denied in ["unicast", "all"]:
                rules.append(["-t", "filter", "-I", chain_name,
                              "-d", daddr, "-j", "LOG",
                              "--log-prefix", "\"RFC3964_IPv4_REJECT: \""])

        # Inject into FORWARD and OUTPUT chains
        rules.append(["-t", "filter", "-I", "OUTPUT", "4",
                      "-j", chain_name])
        rules.append(["-t", "filter", "-I", "FORWARD", "4",
                      "-j", chain_name])
        return rules
fw_icmptype.py000064400000004665151731527140007465 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "FirewallIcmpType" ]

from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class FirewallIcmpType(object):
    def __init__(self, fw):
        self._fw = fw
        self._icmptypes = { }

    def __repr__(self):
        return '%s(%r)' % (self.__class__, self._icmptypes)

    def cleanup(self):
        self._icmptypes.clear()

    # zones

    def get_icmptypes(self):
        return sorted(self._icmptypes.keys())

    def check_icmptype(self, icmptype):
        if icmptype not in self._icmptypes:
            raise FirewallError(errors.INVALID_ICMPTYPE, icmptype)

    def get_icmptype(self, icmptype):
        self.check_icmptype(icmptype)
        return self._icmptypes[icmptype]

    def add_icmptype(self, obj):
        orig_ipvs = obj.destination
        if len(orig_ipvs) == 0:
            orig_ipvs = [ "ipv4", "ipv6" ]
        for ipv in orig_ipvs:
            if ipv == "ipv4":
                if not self._fw.ip4tables_enabled and not self._fw.nftables_enabled:
                    continue
                supported_icmps = self._fw.ipv4_supported_icmp_types
            elif ipv == "ipv6":
                if not self._fw.ip6tables_enabled and not self._fw.nftables_enabled:
                    continue
                supported_icmps = self._fw.ipv6_supported_icmp_types
            else:
                supported_icmps = [ ]
            if obj.name.lower() not in supported_icmps:
                log.info1("ICMP type '%s' is not supported by the kernel for %s." % (obj.name, ipv))
        self._icmptypes[obj.name] = obj

    def remove_icmptype(self, icmptype):
        self.check_icmptype(icmptype)
        del self._icmptypes[icmptype]
fw_ipset.py000064400000022712151731527140006750 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2015-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""ipset backend"""

__all__ = [ "FirewallIPSet" ]

from firewall.core.logger import log
from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts, \
                                normalize_ipset_entry, check_entry_overlaps_existing, \
                                check_for_overlapping_entries
from firewall.core.io.ipset import IPSet
from firewall import errors
from firewall.errors import FirewallError

class FirewallIPSet(object):
    def __init__(self, fw):
        self._fw = fw
        self._ipsets = { }

    def __repr__(self):
        return '%s(%r)' % (self.__class__, self._ipsets)

    # ipsets

    def cleanup(self):
        self._ipsets.clear()

    def check_ipset(self, name):
        if name not in self.get_ipsets():
            raise FirewallError(errors.INVALID_IPSET, name)

    def query_ipset(self, name):
        return name in self.get_ipsets()

    def get_ipsets(self):
        return sorted(self._ipsets.keys())

    def has_ipsets(self):
        return len(self._ipsets) > 0

    def get_ipset(self, name, applied=False):
        self.check_ipset(name)
        obj = self._ipsets[name]
        if applied:
            self.check_applied_obj(obj)
        return obj

    def backends(self):
        backends = []
        if self._fw.nftables_enabled:
            backends.append(self._fw.nftables_backend)
        if self._fw.ipset_enabled:
            backends.append(self._fw.ipset_backend)
        return backends

    def add_ipset(self, obj):
        if obj.type not in self._fw.ipset_supported_types:
            raise FirewallError(errors.INVALID_TYPE,
                                "'%s' is not supported by ipset." % obj.type)
        self._ipsets[obj.name] = obj

    def remove_ipset(self, name, keep=False):
        obj = self._ipsets[name]
        if obj.applied and not keep:
            try:
                for backend in self.backends():
                    backend.set_destroy(name)
            except Exception as msg:
                raise FirewallError(errors.COMMAND_FAILED, msg)
        else:
            log.debug1("Keeping ipset '%s' because of timeout option", name)
        del self._ipsets[name]

    def apply_ipset(self, name):
        obj = self._ipsets[name]

        for backend in self.backends():
            if backend.name == "ipset":
                active = backend.set_get_active_terse()

                if name in active and ("timeout" not in obj.options or \
                                       obj.options["timeout"] == "0" or \
                                       obj.type != active[name][0] or \
                                       rm_def_cr_opts(obj.options) != \
                                       active[name][1]):
                    try:
                        backend.set_destroy(name)
                    except Exception as msg:
                        raise FirewallError(errors.COMMAND_FAILED, msg)

            if self._fw._individual_calls:
                try:
                    backend.set_create(obj.name, obj.type, obj.options)
                except Exception as msg:
                    raise FirewallError(errors.COMMAND_FAILED, msg)
                else:
                    obj.applied = True
                    if "timeout" in obj.options and \
                       obj.options["timeout"] != "0":
                        # no entries visible for ipsets with timeout
                        continue

                try:
                    backend.set_flush(obj.name)
                except Exception as msg:
                    raise FirewallError(errors.COMMAND_FAILED, msg)

                for entry in obj.entries:
                    try:
                        backend.set_add(obj.name, entry)
                    except Exception as msg:
                        raise FirewallError(errors.COMMAND_FAILED, msg)
            else:
                try:
                    backend.set_restore(obj.name, obj.type,
                                                   obj.entries, obj.options,
                                                   None)
                except Exception as msg:
                    raise FirewallError(errors.COMMAND_FAILED, msg)
                else:
                    obj.applied = True

    def apply_ipsets(self):
        for name in self.get_ipsets():
            obj = self._ipsets[name]
            obj.applied = False

            log.debug1("Applying ipset '%s'" % name)
            self.apply_ipset(name)

    def flush(self):
        for backend in self.backends():
            # nftables sets are part of the normal firewall ruleset.
            if backend.name == "nftables":
                continue
            for ipset in self.get_ipsets():
                try:
                    self.check_applied(ipset)
                    backend.set_destroy(ipset)
                except FirewallError as msg:
                    if msg.code != errors.NOT_APPLIED:
                        raise msg

    # TYPE

    def get_type(self, name, applied=True):
        return self.get_ipset(name, applied=applied).type

    # DIMENSION
    def get_dimension(self, name):
        return len(self.get_ipset(name, applied=True).type.split(","))

    def check_applied(self, name):
        obj = self.get_ipset(name)
        self.check_applied_obj(obj)

    def check_applied_obj(self, obj):
        if not obj.applied:
            raise FirewallError(
                errors.NOT_APPLIED, obj.name)

    # OPTIONS

    def get_family(self, name, applied=True):
        obj = self.get_ipset(name, applied=applied)
        if "family" in obj.options:
            if obj.options["family"] == "inet6":
                return "ipv6"
        return "ipv4"

    # ENTRIES

    def add_entry(self, name, entry):
        obj = self.get_ipset(name, applied=True)
        entry = normalize_ipset_entry(entry)

        IPSet.check_entry(entry, obj.options, obj.type)
        if entry in obj.entries:
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already is in '%s'" % (entry, name))
        check_entry_overlaps_existing(entry, obj.entries)

        try:
            for backend in self.backends():
                backend.set_add(obj.name, entry)
        except Exception as msg:
            raise FirewallError(errors.COMMAND_FAILED, msg)
        else:
            if "timeout" not in obj.options or obj.options["timeout"] == "0":
                # no entries visible for ipsets with timeout
                obj.entries.append(entry)

    def remove_entry(self, name, entry):
        obj = self.get_ipset(name, applied=True)
        entry = normalize_ipset_entry(entry)

        # no entry check for removal
        if entry not in obj.entries:
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (entry, name))
        try:
            for backend in self.backends():
                backend.set_delete(obj.name, entry)
        except Exception as msg:
            raise FirewallError(errors.COMMAND_FAILED, msg)
        else:
            if "timeout" not in obj.options or obj.options["timeout"] == "0":
                # no entries visible for ipsets with timeout
                obj.entries.remove(entry)

    def query_entry(self, name, entry):
        obj = self.get_ipset(name, applied=True)
        entry = normalize_ipset_entry(entry)
        if "timeout" in obj.options and obj.options["timeout"] != "0":
            # no entries visible for ipsets with timeout
            raise FirewallError(errors.IPSET_WITH_TIMEOUT, name)

        return entry in obj.entries

    def get_entries(self, name):
        obj = self.get_ipset(name, applied=True)
        return obj.entries

    def set_entries(self, name, entries):
        obj = self.get_ipset(name, applied=True)

        check_for_overlapping_entries(entries)

        for entry in entries:
            IPSet.check_entry(entry, obj.options, obj.type)
        if "timeout" not in obj.options or obj.options["timeout"] == "0":
            # no entries visible for ipsets with timeout
            obj.entries = entries

        try:
            for backend in self.backends():
                backend.set_flush(obj.name)
        except Exception as msg:
            raise FirewallError(errors.COMMAND_FAILED, msg)
        else:
            obj.applied = True

        try:
            for backend in self.backends():
                if self._fw._individual_calls:
                    for entry in obj.entries:
                        backend.set_add(obj.name, entry)
                else:
                    backend.set_restore(obj.name, obj.type, obj.entries,
                                                   obj.options, None)
        except Exception as msg:
            raise FirewallError(errors.COMMAND_FAILED, msg)
        else:
            obj.applied = True

        return
fw_policy.py000064400000253075151731527140007133 0ustar00# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: GPL-2.0-or-later

import time
import copy
from firewall.core.logger import log
from firewall.functions import portStr, checkIPnMask, checkIP6nMask, \
    checkProtocol, enable_ip_forwarding, check_single_address, \
    portInPortRange, get_nf_conntrack_short_name, coalescePortRange, breakPortRange
from firewall.core.rich import Rich_Rule, Rich_Accept, \
    Rich_Service, Rich_Port, Rich_Protocol, \
    Rich_Masquerade, Rich_ForwardPort, Rich_SourcePort, Rich_IcmpBlock, \
    Rich_IcmpType, Rich_Mark
from firewall.core.fw_transaction import FirewallTransaction
from firewall import errors
from firewall.errors import FirewallError
from firewall.fw_types import LastUpdatedOrderedDict
from firewall.core.base import SOURCE_IPSET_TYPES

class FirewallPolicy(object):
    def __init__(self, fw):
        self._fw = fw
        self._chains = { }
        self._policies = { }

    def __repr__(self):
        return '%s(%r, %r)' % (self.__class__, self._chains, self._policies)

    def cleanup(self):
        self._chains.clear()
        self._policies.clear()

    # transaction

    def new_transaction(self):
        return FirewallTransaction(self._fw)

    # policies

    def get_policies(self):
        return sorted(self._policies.keys())

    def get_policies_not_derived_from_zone(self):
        policies = []
        for p in self.get_policies():
            p_obj = self.get_policy(p)
            if not p_obj.derived_from_zone:
                policies.append(p)
        return sorted(policies)

    def get_active_policies_not_derived_from_zone(self):
        active_policies = []
        for policy in self.get_policies_not_derived_from_zone():
            settings = self.get_settings(policy)
            if (set(settings["ingress_zones"]) & (set(self._fw.zone.get_active_zones()) | set(["HOST", "ANY"]))) and \
               (set(settings["egress_zones"]) & (set(self._fw.zone.get_active_zones()) | set(["HOST", "ANY"]))):
                active_policies.append(policy)

        return active_policies

    def get_policy(self, policy):
        p = self._fw.check_policy(policy)
        return self._policies[p]

    def add_policy(self, obj):
        obj.settings = { x : LastUpdatedOrderedDict()
                         for x in [ "services", "ports",
                                    "masquerade", "forward_ports",
                                    "source_ports",
                                    "icmp_blocks", "rules",
                                    "protocols", "icmp_block_inversion",
                                    "ingress_zones", "egress_zones" ] }

        self._policies[obj.name] = obj
        self.copy_permanent_to_runtime(obj.name)

    def remove_policy(self, policy):
        obj = self._policies[policy]
        if obj.applied:
            self.unapply_policy_settings(policy)
        obj.settings.clear()
        del self._policies[policy]

    def copy_permanent_to_runtime(self, policy):
        obj = self._policies[policy]

        if obj.applied:
            return

        for args in obj.ingress_zones:
            self.add_ingress_zone(policy, args, allow_apply=False)
        for args in obj.egress_zones:
            self.add_egress_zone(policy, args, allow_apply=False)
        for args in obj.icmp_blocks:
            self.add_icmp_block(policy, args)
        for args in obj.forward_ports:
            self.add_forward_port(policy, *args)
        for args in obj.services:
            self.add_service(policy, args)
        for args in obj.ports:
            try:
                self.add_port(policy, *args)
            except FirewallError as error:
                if error.code in [errors.ALREADY_ENABLED]:
                    log.warning(error)
                else:
                    raise error
        for args in obj.protocols:
            self.add_protocol(policy, args)
        for args in obj.source_ports:
            try:
                self.add_source_port(policy, *args)
            except FirewallError as error:
                if error.code in [errors.ALREADY_ENABLED]:
                    log.warning(error)
                else:
                    raise error
        for args in obj.rules:
            self.add_rule(policy, args)
        if obj.masquerade:
            self.add_masquerade(policy)

    def apply_policies(self, use_transaction=None):
        for policy in self.get_policies():
            p_obj = self._policies[policy]
            if p_obj.derived_from_zone:
                continue
            if policy in self.get_active_policies_not_derived_from_zone():
                log.debug1("Applying policy '%s'", policy)
                self.apply_policy_settings(policy, use_transaction=use_transaction)

    def set_policy_applied(self, policy, applied):
        obj = self._policies[policy]
        obj.applied = applied

    # settings

    # generate settings record with sender, timeout
    def __gen_settings(self, timeout, sender):
        ret = {
            "date": time.time(),
            "sender": sender,
            "timeout": timeout,
        }
        return ret

    def get_settings(self, policy):
        return self.get_policy(policy).settings

    def _policy_settings(self, enable, policy, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        obj = self._policies[_policy]
        if (enable and obj.applied) or (not enable and not obj.applied):
            return
        if enable:
            obj.applied = True

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if enable:
            # build the base chain layout of the policy
            for (table, chain) in self._get_table_chains_for_policy_dispatch(policy) if not obj.derived_from_zone \
                             else self._get_table_chains_for_zone_dispatch(policy):
                self.gen_chain_rules(policy, True, table, chain, transaction)

        settings = self.get_settings(policy)
        if not obj.derived_from_zone:
            self._ingress_egress_zones(enable, _policy, transaction)
        for key in settings:
            for args in settings[key]:
                if key == "icmp_blocks":
                    self._icmp_block(enable, _policy, args, transaction)
                elif key == "icmp_block_inversion":
                    continue
                elif key == "forward_ports":
                    self._forward_port(enable, _policy, transaction,
                                       *args)
                elif key == "services":
                    self._service(enable, _policy, args, transaction)
                elif key == "ports":
                    self._port(enable, _policy, args[0], args[1],
                                transaction)
                elif key == "protocols":
                    self._protocol(enable, _policy, args, transaction)
                elif key == "source_ports":
                    self._source_port(enable, _policy, args[0], args[1],
                                       transaction)
                elif key == "masquerade":
                    self._masquerade(enable, _policy, transaction)
                elif key == "rules":
                    self.__rule(enable, _policy, Rich_Rule(rule_str=args),
                                transaction)
                elif key == "ingress_zones":
                    continue
                elif key == "egress_zones":
                    continue
                else:
                    log.warning("Policy '%s': Unknown setting '%s:%s', "
                                "unable to apply", policy, key, args)

        if not enable:
            for (table, chain) in self._get_table_chains_for_policy_dispatch(policy) if not obj.derived_from_zone \
                             else self._get_table_chains_for_zone_dispatch(policy):
                self.gen_chain_rules(policy, False, table, chain, transaction)
            obj.applied = False

        if use_transaction is None:
            transaction.execute(enable)

    def apply_policy_settings(self, policy, use_transaction=None):
        self._policy_settings(True, policy, use_transaction=use_transaction)

    def unapply_policy_settings(self, policy, use_transaction=None):
        self._policy_settings(False, policy, use_transaction=use_transaction)

    def get_config_with_settings_dict(self, policy):
        """
        :return: exported config updated with runtime settings
        """
        permanent = self.get_policy(policy).export_config_dict()
        runtime = { "services": self.list_services(policy),
                    "ports": self.list_ports(policy),
                    "icmp_blocks": self.list_icmp_blocks(policy),
                    "masquerade": self.query_masquerade(policy),
                    "forward_ports": self.list_forward_ports(policy),
                    "rich_rules": self.list_rules(policy),
                    "protocols": self.list_protocols(policy),
                    "source_ports": self.list_source_ports(policy),
                    "ingress_zones": self.list_ingress_zones(policy),
                    "egress_zones": self.list_egress_zones(policy),
                    }
        return self._fw.combine_runtime_with_permanent_settings(permanent, runtime)

    def set_config_with_settings_dict(self, policy, settings, sender):
        # stupid wrappers to convert rich rule string to rich rule object
        from firewall.core.rich import Rich_Rule
        def add_rule_wrapper(policy, rule_str, timeout=0, sender=None):
            self.add_rule(policy, Rich_Rule(rule_str=rule_str), timeout=0, sender=sender)
        def remove_rule_wrapper(policy, rule_str):
            self.remove_rule(policy, Rich_Rule(rule_str=rule_str))

        setting_to_fn = {
            "services": (self.add_service, self.remove_service),
            "ports": (self.add_port, self.remove_port),
            "icmp_blocks": (self.add_icmp_block, self.remove_icmp_block),
            "masquerade": (self.add_masquerade, self.remove_masquerade),
            "forward_ports": (self.add_forward_port, self.remove_forward_port),
            "rich_rules": (add_rule_wrapper, remove_rule_wrapper),
            "protocols": (self.add_protocol, self.remove_protocol),
            "source_ports": (self.add_source_port, self.remove_source_port),
            "ingress_zones": (self.add_ingress_zone, self.remove_ingress_zone),
            "egress_zones": (self.add_egress_zone, self.remove_egress_zone),
        }

        old_settings = self.get_config_with_settings_dict(policy)
        (add_settings, remove_settings) = self._fw.get_added_and_removed_settings(old_settings, settings)

        for key in remove_settings:
            if isinstance(remove_settings[key], list):
                for args in remove_settings[key]:
                    if isinstance(args, tuple):
                        setting_to_fn[key][1](policy, *args)
                    else:
                        setting_to_fn[key][1](policy, args)
            else: # bool
                setting_to_fn[key][1](policy)

        for key in add_settings:
            if isinstance(add_settings[key], list):
                for args in add_settings[key]:
                    if isinstance(args, tuple):
                        setting_to_fn[key][0](policy, *args, timeout=0, sender=sender)
                    else:
                        setting_to_fn[key][0](policy, args, timeout=0, sender=sender)
            else: # bool
                setting_to_fn[key][0](policy, timeout=0, sender=sender)

    # ingress zones

    def check_ingress_zone(self, zone):
        if not zone:
            raise FirewallError(errors.INVALID_ZONE)
        if zone not in ["HOST", "ANY"]:
            self._fw.check_zone(zone)

    def __ingress_zone_id(self, zone):
        self.check_ingress_zone(zone)
        return zone

    def add_ingress_zone(self, policy, zone, timeout=0, sender=None,
                         use_transaction=None, allow_apply=True):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        zone_id = self.__ingress_zone_id(zone)
        if zone_id in _obj.settings["ingress_zones"]:
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already in '%s'" % (zone, _policy))

        if "ANY" in _obj.settings["ingress_zones"] or "HOST" in _obj.settings["ingress_zones"] or \
           zone in ["ANY", "HOST"] and _obj.settings["ingress_zones"]:
            raise FirewallError(errors.INVALID_ZONE, "'ingress-zones' may only contain one of: many regular zones, ANY, or HOST")

        if zone == "HOST" and "HOST" in _obj.settings["egress_zones"]:
            raise FirewallError(errors.INVALID_ZONE, "'HOST' can only appear in either ingress or egress zones, but not both")

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if allow_apply:
            if _obj.applied:
                self._ingress_egress_zones(False, _policy, transaction)

            # register early so backends can access updated zone list
            self.__register_ingress_zone(_obj, zone_id, timeout, sender)
            transaction.add_fail(self.__unregister_ingress_zone, _obj, zone_id)

            if not _obj.applied:
                if _policy in self.get_active_policies_not_derived_from_zone():
                    self.apply_policy_settings(_policy, use_transaction=transaction)
                    transaction.add_fail(self.set_policy_applied, _policy, False)
            else:
                self._ingress_egress_zones(True, _policy, transaction)
        else:
            self.__register_ingress_zone(_obj, zone_id, timeout, sender)
            transaction.add_fail(self.__unregister_ingress_zone, _obj, zone_id)

        if use_transaction is None:
            transaction.execute(True)

    def __register_ingress_zone(self, _obj, zone_id, timeout, sender):
        _obj.settings["ingress_zones"][zone_id] = self.__gen_settings(timeout, sender)

    def remove_ingress_zone(self, policy, zone, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        zone_id = self.__ingress_zone_id(zone)
        if zone_id not in _obj.settings["ingress_zones"]:
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (zone, _policy))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            if len(_obj.settings["ingress_zones"]) == 1:
                self.unapply_policy_settings(_policy, transaction)
            else:
                self._ingress_egress_zones(False, _policy, transaction)

            # unregister early so backends have updated zone list
            self.__unregister_ingress_zone(_obj, zone_id)
            transaction.add_fail(self.__register_ingress_zone, _obj, zone_id, None, None)

            if _policy in self.get_active_policies_not_derived_from_zone():
                self._ingress_egress_zones(True, _policy, transaction)
        else:
            transaction.add_post(self.__unregister_ingress_zone, _obj, zone_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_ingress_zone(self, _obj, zone_id):
        if zone_id in _obj.settings["ingress_zones"]:
            del _obj.settings["ingress_zones"][zone_id]

    def query_ingress_zone(self, policy, zone):
        return self.__ingress_zone_id(zone) in self.get_settings(policy)["ingress_zones"]

    def list_ingress_zones(self, policy):
        return list(self.get_settings(policy)["ingress_zones"].keys())

    # egress zones

    def check_egress_zone(self, zone):
        if not zone:
            raise FirewallError(errors.INVALID_ZONE)
        if zone not in ["HOST", "ANY"]:
            self._fw.check_zone(zone)

    def __egress_zone_id(self, zone):
        self.check_egress_zone(zone)
        return zone

    def add_egress_zone(self, policy, zone, timeout=0, sender=None,
                         use_transaction=None, allow_apply=True):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        zone_id = self.__egress_zone_id(zone)
        if zone_id in _obj.settings["egress_zones"]:
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already in '%s'" % (zone, _policy))

        if "ANY" in _obj.settings["egress_zones"] or "HOST" in _obj.settings["egress_zones"] or \
           zone in ["ANY", "HOST"] and _obj.settings["egress_zones"]:
            raise FirewallError(errors.INVALID_ZONE, "'egress-zones' may only contain one of: many regular zones, ANY, or HOST")

        if zone == "HOST" and "HOST" in _obj.settings["ingress_zones"]:
            raise FirewallError(errors.INVALID_ZONE, "'HOST' can only appear in either ingress or egress zones, but not both")

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if allow_apply:
            if _obj.applied:
                self._ingress_egress_zones(False, _policy, transaction)

            # register early so backends can access updated zone list
            self.__register_egress_zone(_obj, zone_id, timeout, sender)
            transaction.add_fail(self.__unregister_egress_zone, _obj, zone_id)

            if not _obj.applied:
                if _policy in self.get_active_policies_not_derived_from_zone():
                    self.apply_policy_settings(_policy, use_transaction=transaction)
                    transaction.add_fail(self.set_policy_applied, _policy, False)
            else:
                self._ingress_egress_zones(True, _policy, transaction)
        else:
            self.__register_egress_zone(_obj, zone_id, timeout, sender)
            transaction.add_fail(self.__unregister_egress_zone, _obj, zone_id)

        if use_transaction is None:
            transaction.execute(True)

    def __register_egress_zone(self, _obj, zone_id, timeout, sender):
        _obj.settings["egress_zones"][zone_id] = self.__gen_settings(timeout, sender)

    def remove_egress_zone(self, policy, zone, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        zone_id = self.__egress_zone_id(zone)
        if zone_id not in _obj.settings["egress_zones"]:
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (zone, _policy))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            if len(_obj.settings["egress_zones"]) == 1:
                self.unapply_policy_settings(_policy, transaction)
            else:
                self._ingress_egress_zones(False, _policy, transaction)

            # unregister early so backends have updated zone list
            self.__unregister_egress_zone(_obj, zone_id)
            transaction.add_fail(self.__register_egress_zone, _obj, zone_id, None, None)

            if _policy in self.get_active_policies_not_derived_from_zone():
                self._ingress_egress_zones(True, _policy, transaction)
        else:
            transaction.add_post(self.__unregister_egress_zone, _obj, zone_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_egress_zone(self, _obj, zone_id):
        if zone_id in _obj.settings["egress_zones"]:
            del _obj.settings["egress_zones"][zone_id]

    def query_egress_zone(self, policy, zone):
        return self.__egress_zone_id(zone) in self.get_settings(policy)["egress_zones"]

    def list_egress_zones(self, policy):
        return list(self.get_settings(policy)["egress_zones"].keys())

    # RICH LANGUAGE

    def check_rule(self, rule):
        rule.check()

    def __rule_id(self, rule):
        self.check_rule(rule)
        return str(rule)

    def _rule_source_ipv(self, source):
        if not source:
            return None

        if source.addr:
            if checkIPnMask(source.addr):
                return "ipv4"
            elif checkIP6nMask(source.addr):
                return "ipv6"
        elif hasattr(source, "mac") and source.mac:
            return ""
        elif hasattr(source, "ipset") and source.ipset:
            self._check_ipset_type_for_source(source.ipset)
            self._check_ipset_applied(source.ipset)
            return self._ipset_family(source.ipset)

        return None

    def __rule(self, enable, policy, rule, transaction):
        self._rule_prepare(enable, policy, rule, transaction)

    def add_rule(self, policy, rule, timeout=0, sender=None,
                 use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        rule_id = self.__rule_id(rule)
        if rule_id in _obj.settings["rules"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already in '%s'" % (rule, _name))

        if not _obj.derived_from_zone:
            if rule.element and isinstance(rule.element, Rich_Masquerade):
                if "HOST" in _obj.settings["egress_zones"]:
                    raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'")
                if "HOST" in _obj.settings["ingress_zones"]:
                    raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'")
                for zone in _obj.settings["ingress_zones"]:
                    if zone == "ANY":
                        continue
                    if self._fw.zone.list_interfaces(zone):
                        raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces")
            if rule.element and isinstance(rule.element, Rich_ForwardPort):
                if "HOST" in _obj.settings["egress_zones"]:
                    if rule.element.to_address:
                        raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'")
                elif _obj.settings["egress_zones"]:
                    if not rule.element.to_address:
                        raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone")
                    for zone in _obj.settings["egress_zones"]:
                        if zone == "ANY":
                            continue
                        if self._fw.zone.list_interfaces(zone):
                            raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces")
            if rule.action and isinstance(rule.action, Rich_Mark):
                for zone in _obj.settings["egress_zones"]:
                    if zone in ["ANY", "HOST"]:
                        continue
                    if self._fw.zone.list_interfaces(zone):
                        raise FirewallError(errors.INVALID_ZONE, "'mark' action cannot be used in a policy if an egress zone has assigned interfaces")

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self.__rule(True, _policy, rule, transaction)

        self.__register_rule(_obj, rule_id, timeout, sender)
        transaction.add_fail(self.__unregister_rule, _obj, rule_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_rule(self, _obj, rule_id, timeout, sender):
        _obj.settings["rules"][rule_id] = self.__gen_settings(
            timeout, sender)

    def remove_rule(self, policy, rule,
                    use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        rule_id = self.__rule_id(rule)
        if rule_id not in _obj.settings["rules"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (rule, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self.__rule(False, _policy, rule, transaction)

        transaction.add_post(self.__unregister_rule, _obj, rule_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_rule(self, _obj, rule_id):
        if rule_id in _obj.settings["rules"]:
            del _obj.settings["rules"][rule_id]

    def query_rule(self, policy, rule):
        return self.__rule_id(rule) in self.get_settings(policy)["rules"]

    def list_rules(self, policy):
        return list(self.get_settings(policy)["rules"].keys())

    # SERVICES

    def check_service(self, service):
        self._fw.check_service(service)

    def __service_id(self, service):
        self.check_service(service)
        return service

    def add_service(self, policy, service, timeout=0, sender=None,
                    use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        service_id = self.__service_id(service)
        if service_id in _obj.settings["services"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already in '%s'" % (service, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._service(True, _policy, service, transaction)

        self.__register_service(_obj, service_id, timeout, sender)
        transaction.add_fail(self.__unregister_service, _obj, service_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_service(self, _obj, service_id, timeout, sender):
        _obj.settings["services"][service_id] = \
            self.__gen_settings(timeout, sender)

    def remove_service(self, policy, service,
                       use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        service_id = self.__service_id(service)
        if service_id not in _obj.settings["services"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (service, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._service(False, _policy, service, transaction)

        transaction.add_post(self.__unregister_service, _obj, service_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_service(self, _obj, service_id):
        if service_id in _obj.settings["services"]:
            del _obj.settings["services"][service_id]

    def query_service(self, policy, service):
        return self.__service_id(service) in self.get_settings(policy)["services"]

    def list_services(self, policy):
        return self.get_settings(policy)["services"].keys()

    def get_helpers_for_service_helpers(self, helpers):
        _helpers = [ ]
        for helper in helpers:
            try:
                _helper = self._fw.helper.get_helper(helper)
            except FirewallError:
                raise FirewallError(errors.INVALID_HELPER, helper)
            _helpers.append(_helper)
        return _helpers

    def get_helpers_for_service_modules(self, modules, enable):
        # If automatic helper assignment is turned off, helpers that
        # do not have ports defined will be replaced by the helpers
        # that the helper.module defines.
        _helpers = [ ]
        for module in modules:
            try:
                helper = self._fw.helper.get_helper(module)
            except FirewallError:
                raise FirewallError(errors.INVALID_HELPER, module)
            if len(helper.ports) < 1:
                _module_short_name = get_nf_conntrack_short_name(helper.module)
                try:
                    _helper = self._fw.helper.get_helper(_module_short_name)
                    _helpers.append(_helper)
                except FirewallError:
                    if enable:
                        log.warning("Helper '%s' is not available" % _module_short_name)
                    continue
            else:
                _helpers.append(helper)
        return _helpers

    # PORTS

    def check_port(self, port, protocol):
        self._fw.check_port(port)
        self._fw.check_tcpudp(protocol)

    def __port_id(self, port, protocol):
        self.check_port(port, protocol)
        return (portStr(port, "-"), protocol)

    def add_port(self, policy, port, protocol, timeout=0, sender=None,
                 use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["ports"]))
        for port_id in existing_port_ids:
            if portInPortRange(port, port_id[0]):
                _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
                raise FirewallError(errors.ALREADY_ENABLED,
                                    "'%s:%s' already in '%s'" % (port, protocol, _name))

        added_ranges, removed_ranges = coalescePortRange(port, [_port for (_port, _protocol) in existing_port_ids])

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            for range in added_ranges:
                self._port(True, _policy, portStr(range, "-"), protocol, transaction)
            for range in removed_ranges:
                self._port(False, _policy, portStr(range, "-"), protocol, transaction)

        for range in added_ranges:
            port_id = self.__port_id(range, protocol)
            self.__register_port(_obj, port_id, timeout, sender)
            transaction.add_fail(self.__unregister_port, _obj, port_id)
        for range in removed_ranges:
            port_id = self.__port_id(range, protocol)
            transaction.add_post(self.__unregister_port, _obj, port_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_port(self, _obj, port_id, timeout, sender):
        _obj.settings["ports"][port_id] = \
            self.__gen_settings(timeout, sender)

    def remove_port(self, policy, port, protocol,
                    use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["ports"]))
        for port_id in existing_port_ids:
            if portInPortRange(port, port_id[0]):
                break
        else:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s:%s' not in '%s'" % (port, protocol, _name))

        added_ranges, removed_ranges = breakPortRange(port, [_port for (_port, _protocol) in existing_port_ids])

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            for range in added_ranges:
                self._port(True, _policy, portStr(range, "-"), protocol, transaction)
            for range in removed_ranges:
                self._port(False, _policy, portStr(range, "-"), protocol, transaction)

        for range in added_ranges:
            port_id = self.__port_id(range, protocol)
            self.__register_port(_obj, port_id, 0, None)
            transaction.add_fail(self.__unregister_port, _obj, port_id)
        for range in removed_ranges:
            port_id = self.__port_id(range, protocol)
            transaction.add_post(self.__unregister_port, _obj, port_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_port(self, _obj, port_id):
        if port_id in _obj.settings["ports"]:
            del _obj.settings["ports"][port_id]

    def query_port(self, policy, port, protocol):
        for (_port, _protocol) in self.get_settings(policy)["ports"]:
            if portInPortRange(port, _port) and protocol == _protocol:
                return True

        return False

    def list_ports(self, policy):
        return list(self.get_settings(policy)["ports"].keys())

    # PROTOCOLS

    def check_protocol(self, protocol):
        if not checkProtocol(protocol):
            raise FirewallError(errors.INVALID_PROTOCOL, protocol)

    def __protocol_id(self, protocol):
        self.check_protocol(protocol)
        return protocol

    def add_protocol(self, policy, protocol, timeout=0, sender=None,
                     use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        protocol_id = self.__protocol_id(protocol)
        if protocol_id in _obj.settings["protocols"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already in '%s'" % (protocol, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._protocol(True, _policy, protocol, transaction)

        self.__register_protocol(_obj, protocol_id, timeout, sender)
        transaction.add_fail(self.__unregister_protocol, _obj, protocol_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_protocol(self, _obj, protocol_id, timeout, sender):
        _obj.settings["protocols"][protocol_id] = \
            self.__gen_settings(timeout, sender)

    def remove_protocol(self, policy, protocol,
                        use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        protocol_id = self.__protocol_id(protocol)
        if protocol_id not in _obj.settings["protocols"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (protocol, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._protocol(False, _policy, protocol, transaction)

        transaction.add_post(self.__unregister_protocol, _obj,
                                  protocol_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_protocol(self, _obj, protocol_id):
        if protocol_id in _obj.settings["protocols"]:
            del _obj.settings["protocols"][protocol_id]

    def query_protocol(self, policy, protocol):
        return self.__protocol_id(protocol) in self.get_settings(policy)["protocols"]

    def list_protocols(self, policy):
        return list(self.get_settings(policy)["protocols"].keys())

    # SOURCE PORTS

    def __source_port_id(self, port, protocol):
        self.check_port(port, protocol)
        return (portStr(port, "-"), protocol)

    def add_source_port(self, policy, port, protocol, timeout=0, sender=None,
                        use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["source_ports"]))
        for port_id in existing_port_ids:
            if portInPortRange(port, port_id[0]):
                _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
                raise FirewallError(errors.ALREADY_ENABLED,
                                    "'%s:%s' already in '%s'" % (port, protocol, _name))

        added_ranges, removed_ranges = coalescePortRange(port, [_port for (_port, _protocol) in existing_port_ids])

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            for range in added_ranges:
                self._source_port(True, _policy, portStr(range, "-"), protocol, transaction)
            for range in removed_ranges:
                self._source_port(False, _policy, portStr(range, "-"), protocol, transaction)

        for range in added_ranges:
            port_id = self.__source_port_id(range, protocol)
            self.__register_source_port(_obj, port_id, timeout, sender)
            transaction.add_fail(self.__unregister_source_port, _obj, port_id)
        for range in removed_ranges:
            port_id = self.__source_port_id(range, protocol)
            transaction.add_post(self.__unregister_source_port, _obj, port_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_source_port(self, _obj, port_id, timeout, sender):
        _obj.settings["source_ports"][port_id] = \
            self.__gen_settings(timeout, sender)

    def remove_source_port(self, policy, port, protocol,
                           use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["source_ports"]))
        for port_id in existing_port_ids:
            if portInPortRange(port, port_id[0]):
                break
        else:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s:%s' not in '%s'" % (port, protocol, _name))

        added_ranges, removed_ranges = breakPortRange(port, [_port for (_port, _protocol) in existing_port_ids])

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            for range in added_ranges:
                self._source_port(True, _policy, portStr(range, "-"), protocol, transaction)
            for range in removed_ranges:
                self._source_port(False, _policy, portStr(range, "-"), protocol, transaction)

        for range in added_ranges:
            port_id = self.__source_port_id(range, protocol)
            self.__register_source_port(_obj, port_id, 0, None)
            transaction.add_fail(self.__unregister_source_port, _obj, port_id)
        for range in removed_ranges:
            port_id = self.__source_port_id(range, protocol)
            transaction.add_post(self.__unregister_source_port, _obj, port_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_source_port(self, _obj, port_id):
        if port_id in _obj.settings["source_ports"]:
            del _obj.settings["source_ports"][port_id]

    def query_source_port(self, policy, port, protocol):
        for (_port, _protocol) in self.get_settings(policy)["source_ports"]:
            if portInPortRange(port, _port) and protocol == _protocol:
                return True

        return False

    def list_source_ports(self, policy):
        return list(self.get_settings(policy)["source_ports"].keys())

    # MASQUERADE

    def __masquerade_id(self):
        return True

    def add_masquerade(self, policy, timeout=0, sender=None,
                       use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        masquerade_id = self.__masquerade_id()
        if masquerade_id in _obj.settings["masquerade"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.ALREADY_ENABLED,
                                "masquerade already enabled in '%s'" % _name)

        if not _obj.derived_from_zone:
            if "HOST" in _obj.settings["egress_zones"]:
                raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'")
            if "HOST" in _obj.settings["ingress_zones"]:
                raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'")
            for zone in _obj.settings["ingress_zones"]:
                if zone == "ANY":
                    continue
                if self._fw.zone.list_interfaces(zone):
                    raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces")

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._masquerade(True, _policy, transaction)

        self.__register_masquerade(_obj, masquerade_id, timeout, sender)
        transaction.add_fail(self.__unregister_masquerade, _obj, masquerade_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_masquerade(self, _obj, masquerade_id, timeout, sender):
        _obj.settings["masquerade"][masquerade_id] = \
            self.__gen_settings(timeout, sender)

    def remove_masquerade(self, policy, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        masquerade_id = self.__masquerade_id()
        if masquerade_id not in _obj.settings["masquerade"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "masquerade not enabled in '%s'" % _name)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._masquerade(False, _policy, transaction)

        transaction.add_post(self.__unregister_masquerade, _obj, masquerade_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_masquerade(self, _obj, masquerade_id):
        if masquerade_id in _obj.settings["masquerade"]:
            del _obj.settings["masquerade"][masquerade_id]

    def query_masquerade(self, policy):
        return self.__masquerade_id() in self.get_settings(policy)["masquerade"]

    # PORT FORWARDING

    def check_forward_port(self, ipv, port, protocol, toport=None, toaddr=None):
        self._fw.check_port(port)
        self._fw.check_tcpudp(protocol)
        if toport:
            self._fw.check_port(toport)
        if toaddr:
            if not check_single_address(ipv, toaddr):
                raise FirewallError(errors.INVALID_ADDR, toaddr)
        if not toport and not toaddr:
            raise FirewallError(
                errors.INVALID_FORWARD,
                "port-forwarding is missing to-port AND to-addr")

    def __forward_port_id(self, port, protocol, toport=None, toaddr=None):
        if check_single_address("ipv6", toaddr):
            self.check_forward_port("ipv6", port, protocol, toport, toaddr)
        else:
            self.check_forward_port("ipv4", port, protocol, toport, toaddr)
        return (portStr(port, "-"), protocol,
                portStr(toport, "-"), str(toaddr))

    def add_forward_port(self, policy, port, protocol, toport=None,
                         toaddr=None, timeout=0, sender=None,
                         use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        forward_id = self.__forward_port_id(port, protocol, toport, toaddr)
        if forward_id in _obj.settings["forward_ports"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s:%s:%s:%s' already in '%s'" % \
                                (port, protocol, toport, toaddr, _name))

        if not _obj.derived_from_zone:
            if "HOST" in _obj.settings["egress_zones"]:
                if toaddr:
                    raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'")
            elif _obj.settings["egress_zones"]:
                if not toaddr:
                    raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone")
                for zone in _obj.settings["egress_zones"]:
                    if zone == "ANY":
                        continue
                    if self._fw.zone.list_interfaces(zone):
                        raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces")

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._forward_port(True, _policy, transaction, port, protocol,
                               toport, toaddr)

        self.__register_forward_port(_obj, forward_id, timeout, sender)
        transaction.add_fail(self.__unregister_forward_port, _obj, forward_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_forward_port(self, _obj, forward_id, timeout, sender):
        _obj.settings["forward_ports"][forward_id] = \
            self.__gen_settings(timeout, sender)

    def remove_forward_port(self, policy, port, protocol, toport=None,
                            toaddr=None, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        forward_id = self.__forward_port_id(port, protocol, toport, toaddr)
        if forward_id not in _obj.settings["forward_ports"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s:%s:%s:%s' not in '%s'" % \
                                (port, protocol, toport, toaddr, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._forward_port(False, _policy, transaction, port, protocol,
                               toport, toaddr)

        transaction.add_post(self.__unregister_forward_port, _obj, forward_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_forward_port(self, _obj, forward_id):
        if forward_id in _obj.settings["forward_ports"]:
            del _obj.settings["forward_ports"][forward_id]

    def query_forward_port(self, policy, port, protocol, toport=None,
                           toaddr=None):
        forward_id = self.__forward_port_id(port, protocol, toport, toaddr)
        return forward_id in self.get_settings(policy)["forward_ports"]

    def list_forward_ports(self, policy):
        return list(self.get_settings(policy)["forward_ports"].keys())

    # ICMP BLOCK

    def check_icmp_block(self, icmp):
        self._fw.check_icmptype(icmp)

    def __icmp_block_id(self, icmp):
        self.check_icmp_block(icmp)
        return icmp

    def add_icmp_block(self, policy, icmp, timeout=0, sender=None,
                       use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        icmp_id = self.__icmp_block_id(icmp)
        if icmp_id in _obj.settings["icmp_blocks"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.ALREADY_ENABLED,
                                "'%s' already in '%s'" % (icmp, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._icmp_block(True, _policy, icmp, transaction)

        self.__register_icmp_block(_obj, icmp_id, timeout, sender)
        transaction.add_fail(self.__unregister_icmp_block, _obj, icmp_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_icmp_block(self, _obj, icmp_id, timeout, sender):
        _obj.settings["icmp_blocks"][icmp_id] = \
            self.__gen_settings(timeout, sender)

    def remove_icmp_block(self, policy, icmp, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        icmp_id = self.__icmp_block_id(icmp)
        if icmp_id not in _obj.settings["icmp_blocks"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(errors.NOT_ENABLED,
                                "'%s' not in '%s'" % (icmp, _name))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._icmp_block(False, _policy, icmp, transaction)

        transaction.add_post(self.__unregister_icmp_block, _obj, icmp_id)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_icmp_block(self, _obj, icmp_id):
        if icmp_id in _obj.settings["icmp_blocks"]:
            del _obj.settings["icmp_blocks"][icmp_id]

    def query_icmp_block(self, policy, icmp):
        return self.__icmp_block_id(icmp) in self.get_settings(policy)["icmp_blocks"]

    def list_icmp_blocks(self, policy):
        return self.get_settings(policy)["icmp_blocks"].keys()

    # ICMP BLOCK INVERSION

    def __icmp_block_inversion_id(self):
        return True

    def add_icmp_block_inversion(self, policy, sender=None,
                                 use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        icmp_block_inversion_id = self.__icmp_block_inversion_id()
        if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(
                errors.ALREADY_ENABLED,
                "icmp-block-inversion already enabled in '%s'" % _name)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            # undo icmp blocks
            for args in self.get_settings(_policy)["icmp_blocks"]:
                self._icmp_block(False, _policy, args, transaction)

            self._icmp_block_inversion(False, _policy, transaction)

        self.__register_icmp_block_inversion(_obj, icmp_block_inversion_id,
                                             sender)
        transaction.add_fail(self.__undo_icmp_block_inversion, _policy, _obj,
                             icmp_block_inversion_id)

        # redo icmp blocks
        if _obj.applied:
            for args in self.get_settings(_policy)["icmp_blocks"]:
                self._icmp_block(True, _policy, args, transaction)

            self._icmp_block_inversion(True, _policy, transaction)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __register_icmp_block_inversion(self, _obj, icmp_block_inversion_id,
                                        sender):
        _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] = \
            self.__gen_settings(0, sender)

    def __undo_icmp_block_inversion(self, _policy, _obj, icmp_block_inversion_id):
        transaction = self.new_transaction()

        # undo icmp blocks
        if _obj.applied:
            for args in self.get_settings(_policy)["icmp_blocks"]:
                self._icmp_block(False, _policy, args, transaction)

        if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]:
            del _obj.settings["icmp_block_inversion"][icmp_block_inversion_id]

        # redo icmp blocks
        if _obj.applied:
            for args in self.get_settings(_policy)["icmp_blocks"]:
                self._icmp_block(True, _policy, args, transaction)

        transaction.execute(True)

    def remove_icmp_block_inversion(self, policy, use_transaction=None):
        _policy = self._fw.check_policy(policy)
        self._fw.check_panic()
        _obj = self._policies[_policy]

        icmp_block_inversion_id = self.__icmp_block_inversion_id()
        if icmp_block_inversion_id not in _obj.settings["icmp_block_inversion"]:
            _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy
            raise FirewallError(
                errors.NOT_ENABLED,
                "icmp-block-inversion not enabled in '%s'" % _name)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            # undo icmp blocks
            for args in self.get_settings(_policy)["icmp_blocks"]:
                self._icmp_block(False, _policy, args, transaction)

            self._icmp_block_inversion(False, _policy, transaction)

        self.__unregister_icmp_block_inversion(_obj,
                                               icmp_block_inversion_id)
        transaction.add_fail(self.__register_icmp_block_inversion, _obj,
                             icmp_block_inversion_id, None)

        # redo icmp blocks
        if _obj.applied:
            for args in self.get_settings(_policy)["icmp_blocks"]:
                self._icmp_block(True, _policy, args, transaction)

            self._icmp_block_inversion(True, _policy, transaction)

        if use_transaction is None:
            transaction.execute(True)

        return _policy

    def __unregister_icmp_block_inversion(self, _obj, icmp_block_inversion_id):
        if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]:
            del _obj.settings["icmp_block_inversion"][icmp_block_inversion_id]

    def query_icmp_block_inversion(self, policy):
        return self.__icmp_block_inversion_id() in \
            self.get_settings(policy)["icmp_block_inversion"]

    def gen_chain_rules(self, policy, create, table, chain, transaction):
        obj = self._fw.policy.get_policy(policy)
        if obj.derived_from_zone:
            # For policies derived from zones, use only the first policy in the
            # list to track chain creation. The chain names are converted to
            # zone-based names as such they're "global" for all zone derived
            # policies.
            tracking_policy = self._fw.zone._zone_policies[obj.derived_from_zone][0]
        else:
            tracking_policy = policy

        if create:
            if tracking_policy in self._chains and  \
               (table, chain) in self._chains[tracking_policy]:
                return
        else:
            if tracking_policy not in self._chains or \
               (table, chain) not in self._chains[tracking_policy]:
                return

        for backend in self._fw.enabled_backends():
            if backend.policies_supported and \
               table in backend.get_available_tables():
                rules = backend.build_policy_chain_rules(create, policy, table, chain)
                transaction.add_rules(backend, rules)

        self._register_chains(tracking_policy, create, [(table, chain)])
        transaction.add_fail(self._register_chains, tracking_policy, not create, [(table, chain)])

    def _register_chains(self, policy, create, tables):
        for (table, chain) in tables:
            if create:
                self._chains.setdefault(policy, []).append((table, chain))
            else:
                self._chains[policy].remove((table, chain))
                if len(self._chains[policy]) == 0:
                    del self._chains[policy]

    # IPSETS

    def _ipset_family(self, name):
        if self._fw.ipset.get_type(name) == "hash:mac":
            return None
        return self._fw.ipset.get_family(name)

    def __ipset_type(self, name):
        return self._fw.ipset.get_type(name)

    def _ipset_match_flags(self, name, flag):
        return ",".join([flag] * self._fw.ipset.get_dimension(name))

    def _check_ipset_applied(self, name):
        return self._fw.ipset.check_applied(name)

    def _check_ipset_type_for_source(self, name):
        _type = self.__ipset_type(name)
        if _type not in SOURCE_IPSET_TYPES:
            raise FirewallError(
                errors.INVALID_IPSET,
                "ipset '%s' with type '%s' not usable as source" % \
                (name, _type))

    def _rule_prepare(self, enable, policy, rule, transaction, included_services=None):
        # First apply any services this service may include
        if type(rule.element) == Rich_Service:
            svc = self._fw.service.get_service(rule.element.name)
            if included_services is None:
                included_services = [rule.element.name]
            for include in svc.includes:
                if include in included_services:
                    continue
                self.check_service(include)
                included_services.append(include)
                _rule = copy.deepcopy(rule)
                _rule.element.name = include
                self._rule_prepare(enable, policy, _rule, transaction, included_services=included_services)

        ipvs = []
        if rule.family:
            ipvs = [ rule.family ]
        elif rule.element and (isinstance(rule.element, Rich_IcmpBlock) or isinstance(rule.element, Rich_IcmpType)):
            ict = self._fw.config.get_icmptype(rule.element.name)
            if ict.destination:
                ipvs = [ipv for ipv in ["ipv4", "ipv6"] if ipv in ict.destination]

        source_ipv = self._rule_source_ipv(rule.source)
        if source_ipv:
            if rule.family:
                # rule family is defined by user, no way to change it
                if rule.family != source_ipv:
                    raise FirewallError(errors.INVALID_RULE,
                                        "Source address family '%s' conflicts with rule family '%s'." % (source_ipv, rule.family))
            else:
                # use the source family as rule family
                ipvs = [ source_ipv ]

        if not ipvs:
            ipvs = ["ipv4", "ipv6"]

        # clamp ipvs to those that are actually enabled.
        ipvs = [ipv for ipv in ipvs if self._fw.is_ipv_enabled(ipv)]

        # add an element to object to allow backends to know what ipvs this applies to
        rule.ipvs = ipvs

        for backend in set([self._fw.get_backend_by_ipv(x) for x in ipvs]):
            # SERVICE
            if type(rule.element) == Rich_Service:
                svc = self._fw.service.get_service(rule.element.name)

                destinations = []
                if len(svc.destination) > 0:
                    if rule.destination:
                        # we can not use two destinations at the same time
                        raise FirewallError(errors.INVALID_RULE,
                                            "Destination conflict with service.")
                    for ipv in ipvs:
                        if ipv in svc.destination and backend.is_ipv_supported(ipv):
                            destinations.append(svc.destination[ipv])
                else:
                    # dummy for the following for loop
                    destinations.append(None)

                for destination in destinations:
                    if type(rule.action) == Rich_Accept:
                        # only load modules for accept action
                        helpers = self.get_helpers_for_service_modules(svc.modules,
                                                                       enable)
                        helpers += self.get_helpers_for_service_helpers(svc.helpers)
                        helpers = sorted(set(helpers), key=lambda x: x.name)

                        modules = [ ]
                        for helper in helpers:
                            module = helper.module
                            _module_short_name = get_nf_conntrack_short_name(module)
                            nat_module = module.replace("conntrack", "nat")
                            modules.append(nat_module)
                            if helper.family != "" and not backend.is_ipv_supported(helper.family):
                                # no support for family ipv, continue
                                continue
                            if len(helper.ports) < 1:
                                modules.append(module)
                            else:
                                for (port,proto) in helper.ports:
                                    rules = backend.build_policy_helper_ports_rules(
                                                    enable, policy, proto, port,
                                                    destination, helper.name, _module_short_name)
                                    transaction.add_rules(backend, rules)
                        transaction.add_modules(modules)

                    # create rules
                    for (port,proto) in svc.ports:
                        rules = backend.build_policy_ports_rules(
                                    enable, policy, proto, port, destination, rule)
                        transaction.add_rules(backend, rules)

                    for proto in svc.protocols:
                        rules = backend.build_policy_protocol_rules(
                                    enable, policy, proto, destination, rule)
                        transaction.add_rules(backend, rules)

                    # create rules
                    for (port,proto) in svc.source_ports:
                        rules = backend.build_policy_source_ports_rules(
                                    enable, policy, proto, port, destination, rule)
                        transaction.add_rules(backend, rules)

            # PORT
            elif type(rule.element) == Rich_Port:
                port = rule.element.port
                protocol = rule.element.protocol
                self.check_port(port, protocol)

                rules = backend.build_policy_ports_rules(
                            enable, policy, protocol, port, None, rule)
                transaction.add_rules(backend, rules)

            # PROTOCOL
            elif type(rule.element) == Rich_Protocol:
                protocol = rule.element.value
                self.check_protocol(protocol)

                rules = backend.build_policy_protocol_rules(
                            enable, policy, protocol, None, rule)
                transaction.add_rules(backend, rules)

            # MASQUERADE
            elif type(rule.element) == Rich_Masquerade:
                if enable:
                    for ipv in ipvs:
                        if backend.is_ipv_supported(ipv):
                            transaction.add_post(enable_ip_forwarding, ipv)

                rules = backend.build_policy_masquerade_rules(enable, policy, rule)
                transaction.add_rules(backend, rules)

            # FORWARD PORT
            elif type(rule.element) == Rich_ForwardPort:
                port = rule.element.port
                protocol = rule.element.protocol
                toport = rule.element.to_port
                toaddr = rule.element.to_address
                for ipv in ipvs:
                    if backend.is_ipv_supported(ipv):
                        self.check_forward_port(ipv, port, protocol, toport, toaddr)
                    if toaddr and enable:
                        transaction.add_post(enable_ip_forwarding, ipv)

                rules = backend.build_policy_forward_port_rules(
                                    enable, policy, port, protocol, toport,
                                    toaddr, rule)
                transaction.add_rules(backend, rules)

            # SOURCE PORT
            elif type(rule.element) == Rich_SourcePort:
                port = rule.element.port
                protocol = rule.element.protocol
                self.check_port(port, protocol)

                rules = backend.build_policy_source_ports_rules(
                            enable, policy, protocol, port, None, rule)
                transaction.add_rules(backend, rules)

            # ICMP BLOCK and ICMP TYPE
            elif type(rule.element) == Rich_IcmpBlock or \
                 type(rule.element) == Rich_IcmpType:
                ict = self._fw.config.get_icmptype(rule.element.name)

                if rule.family and ict.destination and \
                   rule.family not in ict.destination:
                    raise FirewallError(errors.INVALID_ICMPTYPE,
                                        "rich rule family '%s' conflicts with icmp type '%s'" % \
                                        (rule.family, rule.element.name))

                if type(rule.element) == Rich_IcmpBlock and \
                   rule.action and type(rule.action) == Rich_Accept:
                    # icmp block might have reject or drop action, but not accept
                    raise FirewallError(errors.INVALID_RULE,
                                        "IcmpBlock not usable with accept action")

                rules = backend.build_policy_icmp_block_rules(enable, policy, ict, rule)
                transaction.add_rules(backend, rules)

            elif rule.element is None:
                rules = backend.build_policy_rich_source_destination_rules(
                            enable, policy, rule)
                transaction.add_rules(backend, rules)

            # EVERYTHING ELSE
            else:
                raise FirewallError(errors.INVALID_RULE, "Unknown element %s" %
                                    type(rule.element))

    def _service(self, enable, policy, service, transaction, included_services=None):
        svc = self._fw.service.get_service(service)
        helpers = self.get_helpers_for_service_modules(svc.modules, enable)
        helpers += self.get_helpers_for_service_helpers(svc.helpers)
        helpers = sorted(set(helpers), key=lambda x: x.name)

        # First apply any services this service may include
        if included_services is None:
            included_services = [service]
        for include in svc.includes:
            if include in included_services:
                continue
            self.check_service(include)
            included_services.append(include)
            self._service(enable, policy, include, transaction, included_services=included_services)

        # build a list of (backend, destination). The destination may be ipv4,
        # ipv6 or None
        #
        backends_ipv = []
        for ipv in ["ipv4", "ipv6"]:
            if not self._fw.is_ipv_enabled(ipv):
                continue
            backend = self._fw.get_backend_by_ipv(ipv)
            if len(svc.destination) > 0:
                if ipv in svc.destination:
                    backends_ipv.append((backend, svc.destination[ipv]))
            else:
                if (backend, None) not in backends_ipv:
                    backends_ipv.append((backend, None))

        for (backend,destination) in backends_ipv:
            for helper in helpers:
                module = helper.module
                _module_short_name = get_nf_conntrack_short_name(module)
                nat_module = helper.module.replace("conntrack", "nat")
                transaction.add_module(nat_module)
                if helper.family != "" and not backend.is_ipv_supported(helper.family):
                    # no support for family ipv, continue
                    continue
                if len(helper.ports) < 1:
                    transaction.add_module(module)
                else:
                    for (port,proto) in helper.ports:
                        rules = backend.build_policy_helper_ports_rules(
                                        enable, policy, proto, port,
                                        destination, helper.name, _module_short_name)
                        transaction.add_rules(backend, rules)

            for (port,proto) in svc.ports:
                rules = backend.build_policy_ports_rules(enable, policy, proto,
                                                       port, destination)
                transaction.add_rules(backend, rules)

            for protocol in svc.protocols:
                rules = backend.build_policy_protocol_rules(
                                    enable, policy, protocol, destination)
                transaction.add_rules(backend, rules)

            for (port,proto) in svc.source_ports:
                rules = backend.build_policy_source_ports_rules(
                                    enable, policy, proto, port, destination)
                transaction.add_rules(backend, rules)

    def _port(self, enable, policy, port, protocol, transaction):
        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue

            rules = backend.build_policy_ports_rules(enable, policy, protocol,
                                                   port)
            transaction.add_rules(backend, rules)

    def _protocol(self, enable, policy, protocol, transaction):
        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue

            rules = backend.build_policy_protocol_rules(enable, policy, protocol)
            transaction.add_rules(backend, rules)

    def _source_port(self, enable, policy, port, protocol, transaction):
        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue

            rules = backend.build_policy_source_ports_rules(enable, policy, protocol, port)
            transaction.add_rules(backend, rules)

    def _masquerade(self, enable, policy, transaction):
        ipv = "ipv4"
        transaction.add_post(enable_ip_forwarding, ipv)

        backend = self._fw.get_backend_by_ipv(ipv)
        rules = backend.build_policy_masquerade_rules(enable, policy)
        transaction.add_rules(backend, rules)

    def _forward_port(self, enable, policy, transaction, port, protocol,
                       toport=None, toaddr=None):
        if check_single_address("ipv6", toaddr):
            ipv = "ipv6"
        else:
            ipv = "ipv4"

        if toaddr and enable:
            transaction.add_post(enable_ip_forwarding, ipv)
        backend = self._fw.get_backend_by_ipv(ipv)
        rules = backend.build_policy_forward_port_rules(
                            enable, policy, port, protocol, toport,
                            toaddr)
        transaction.add_rules(backend, rules)

    def _icmp_block(self, enable, policy, icmp, transaction):
        ict = self._fw.config.get_icmptype(icmp)

        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue
            skip_backend = False

            if ict.destination:
                for ipv in ["ipv4", "ipv6"]:
                    if ipv in ict.destination:
                        if not backend.is_ipv_supported(ipv):
                            skip_backend = True
                            break

            if skip_backend:
                continue

            rules = backend.build_policy_icmp_block_rules(enable, policy, ict)
            transaction.add_rules(backend, rules)

    def _icmp_block_inversion(self, enable, policy, transaction):
        target = self._policies[policy].target

        # Do not add general icmp accept rules into a trusted, block or drop
        # policy.
        if target in [ "DROP", "%%REJECT%%", "REJECT" ]:
            return
        if not self.query_icmp_block_inversion(policy) and target == "ACCEPT":
            # ibi target and policy target are ACCEPT, no need to add an extra
            # rule
            return

        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue

            rules = backend.build_policy_icmp_block_inversion_rules(enable, policy)
            transaction.add_rules(backend, rules)

    def check_ingress_egress(self, policy, ingress_zones, egress_zones,
                                           ingress_interfaces, egress_interfaces,
                                           ingress_sources, egress_sources):
        for zone in ingress_zones:
            self.check_ingress_zone(zone)
        for zone in egress_zones:
            self.check_egress_zone(zone)

        if ("ANY" in ingress_zones or "HOST" in ingress_zones) and \
           len(ingress_zones) > 1:
            raise FirewallError(errors.INVALID_ZONE, "'ingress-zones' may only contain one of: many regular zones, ANY, or HOST")

        if ("ANY" in egress_zones or "HOST" in egress_zones) and \
           len(egress_zones) > 1:
            raise FirewallError(errors.INVALID_ZONE, "'egress-zones' may only contain one of: many regular zones, ANY, or HOST")

        if (egress_interfaces or egress_sources) and \
           not ingress_interfaces and not ingress_sources and \
           "HOST" not in ingress_zones and "ANY" not in ingress_zones:
            raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" has no ingress" % (policy))

        if (ingress_interfaces or ingress_sources) and \
           not egress_interfaces and not egress_sources and \
           "HOST" not in egress_zones and "ANY" not in egress_zones:
            raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" has no egress" % (policy))

    def check_ingress_egress_chain(self, policy, table, chain,
                                   ingress_zones, egress_zones,
                                   ingress_interfaces, egress_interfaces,
                                   ingress_sources, egress_sources):
        if chain == "PREROUTING":
            # raw,prerouting is used for conntrack helpers (services), so we
            # need to allow it if egress-zones contains an actual zone
            if table != "raw":
                if egress_interfaces:
                    raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones may not include a zone with added interfaces." % (policy))
        elif chain == "POSTROUTING":
            if "HOST" in ingress_zones:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones may not include HOST." % (policy))
            if "HOST" in egress_zones:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones may not include HOST." % (policy))
            if ingress_interfaces:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones may not include a zone with added interfaces." % (policy))
        elif chain == "FORWARD":
            if "HOST" in ingress_zones:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones may not include HOST." % (policy))
            if "HOST" in egress_zones:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones may not include HOST." % (policy))
        elif chain == "INPUT":
            if "HOST" not in egress_zones:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones must include only HOST." % (policy))
        elif chain == "OUTPUT":
            if "HOST" not in ingress_zones:
                raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones must include only HOST." % (policy))

    def _ingress_egress_zones_transaction(self, enable, policy):
        transaction = self.new_transaction()
        self._ingress_egress_zones(enable, policy, transaction)
        transaction.execute(True)

    def _ingress_egress_zones(self, enable, policy, transaction):
        obj = self._policies[policy]

        ingress_zones = obj.settings["ingress_zones"]
        egress_zones = obj.settings["egress_zones"]

        ingress_interfaces = set()
        egress_interfaces = set()
        ingress_sources = set()
        egress_sources = set()

        for zone in ingress_zones:
            if zone in ["ANY", "HOST"]:
                continue
            ingress_interfaces |= set(self._fw.zone.list_interfaces(zone))
            ingress_sources |= set(self._fw.zone.list_sources(zone))
        for zone in egress_zones:
            if zone in ["ANY", "HOST"]:
                continue
            egress_interfaces |= set(self._fw.zone.list_interfaces(zone))
            egress_sources |= set(self._fw.zone.list_sources(zone))

        self.check_ingress_egress(policy, ingress_zones, egress_zones,
                                          ingress_interfaces, egress_interfaces,
                                          ingress_sources, egress_sources)

        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue

            for (table, chain) in self._get_table_chains_for_policy_dispatch(policy):
                self.check_ingress_egress_chain(policy, table, chain,
                                                ingress_zones, egress_zones,
                                                ingress_interfaces, egress_interfaces,
                                                ingress_sources, egress_sources)
                rules = backend.build_policy_ingress_egress_rules(enable, policy, table, chain,
                                                                  ingress_interfaces, egress_interfaces,
                                                                  ingress_sources, egress_sources)
                transaction.add_rules(backend, rules)

    def _get_table_chains_for_policy_dispatch(self, policy):
        """Create a list of (table, chain) needed for policy dispatch"""
        obj = self._policies[policy]
        if "ANY" in obj.settings["ingress_zones"] and "HOST" in obj.settings["egress_zones"]:
            # any --> HOST
            tc = [("filter", "INPUT"), ("nat", "PREROUTING"),
                  ("mangle", "PREROUTING")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            return tc
        elif "HOST" in obj.settings["egress_zones"]:
            # zone --> HOST
            tc = [("filter", "INPUT")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            return tc
        elif "HOST" in obj.settings["ingress_zones"]:
            # HOST --> zone/any
            return [("filter", "OUTPUT")]
        elif "ANY" in obj.settings["ingress_zones"] and "ANY" in obj.settings["egress_zones"]:
            # any --> any
            tc = [("filter", "FORWARD"), ("nat", "PREROUTING"),
                  ("nat", "POSTROUTING"), ("mangle", "PREROUTING")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            return tc
        elif "ANY" in obj.settings["egress_zones"]:
            # zone --> any
            tc = [("filter", "FORWARD"), ("nat", "PREROUTING"),
                  ("mangle", "PREROUTING")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            for zone in obj.settings["ingress_zones"]:
                if self._fw.zone.get_settings(zone)["interfaces"]:
                    break
            else:
                tc.append(("nat", "POSTROUTING"))
            return tc
        elif "ANY" in obj.settings["ingress_zones"]:
            # any --> zone
            tc = [("filter", "FORWARD"), ("nat", "POSTROUTING")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            for zone in obj.settings["egress_zones"]:
                if self._fw.zone.get_settings(zone)["interfaces"]:
                    break
            else:
                tc.append(("nat", "PREROUTING"))
                tc.append(("mangle", "PREROUTING"))
            return tc
        else:
            # zone -> zone
            tc = [("filter", "FORWARD")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            for zone in obj.settings["ingress_zones"]:
                if self._fw.zone.get_settings(zone)["interfaces"]:
                    break
            else:
                tc.append(("nat", "POSTROUTING"))
            for zone in obj.settings["egress_zones"]:
                if self._fw.zone.get_settings(zone)["interfaces"]:
                    break
            else:
                tc.append(("nat", "PREROUTING"))
                tc.append(("mangle", "PREROUTING"))
            return tc

    def _get_table_chains_for_zone_dispatch(self, policy):
        """Create a list of (table, chain) needed for zone dispatch"""
        obj = self._policies[policy]
        if "HOST" in obj.settings["egress_zones"]:
            # zone --> Host
            tc = [("filter", "INPUT")]
            # iptables backend needs to put conntrack helper rules in raw
            # prerouting.
            if not self._fw.nftables_enabled:
                tc.append(("raw", "PREROUTING"))
            return tc
        elif "ANY" in obj.settings["egress_zones"]:
            # zone --> any
            return [("filter", "FORWARD_IN"), ("nat", "PREROUTING"),
                    ("mangle", "PREROUTING")]
        elif "ANY" in obj.settings["ingress_zones"]:
            # any --> zone
            return [("filter", "FORWARD_OUT"), ("nat", "POSTROUTING")]
        else:
            return FirewallError("Invalid policy: %s" % (policy))

    def policy_base_chain_name(self, policy, table, policy_prefix, isSNAT=False):
        obj = self._fw.policy.get_policy(policy)
        if obj.derived_from_zone:
            suffix = obj.derived_from_zone
        else:
            suffix = policy_prefix + policy

        if "HOST" in obj.settings["egress_zones"]:
            # zone/any --> Host
            if table == "filter":
                return "IN_" + suffix
            if table == "raw":
                # NOTE: nftables doesn't actually use this. Only iptables
                return "PRE_" + suffix
            if not obj.derived_from_zone:
                if table in ["mangle", "nat"]:
                    return "PRE_" + suffix
        elif "HOST" in obj.settings["ingress_zones"]:
            # HOST --> zone/any
            if not obj.derived_from_zone:
                if table == "filter":
                    return "OUT_" + suffix
        elif "ANY" in obj.settings["egress_zones"]:
            # zone/any --> any
            if table == "filter":
                if obj.derived_from_zone:
                    return "FWDI_" + suffix
                else:
                    return "FWD_" + suffix
            elif table == "nat":
                if isSNAT:
                    return "POST_" + suffix
                else:
                    return "PRE_" + suffix
            elif table in ["mangle", "raw"]:
                return "PRE_" + suffix
        elif "ANY" in obj.settings["ingress_zones"]:
            # any --> zone
            if table == "filter":
                if obj.derived_from_zone:
                    return "FWDO_" + suffix
                else:
                    return "FWD_" + suffix
            elif table == "nat":
                if isSNAT:
                    return "POST_" + suffix
                else:
                    return "PRE_" + suffix
            elif table in ["mangle", "raw"]:
                if not obj.derived_from_zone:
                    return "PRE_" + suffix
        elif not obj.derived_from_zone:
            # zone --> zone
            if table == "filter":
                return "FWD_" + suffix
            elif table == "nat":
                if isSNAT:
                    return "POST_" + suffix
                else:
                    return "PRE_" + suffix
            elif table in ["mangle", "raw"]:
                return "PRE_" + suffix
        return FirewallError("Can't convert policy to chain name: %s, %s, %s" % (policy, table, isSNAT))
logger.py000064400000074476151731527140006425 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2005-2007,2012 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "LogTarget", "FileLog", "Logger", "log" ]

import sys
import types
import time
import inspect
import fnmatch
import syslog
import traceback
import fcntl
import os.path
import os

# ---------------------------------------------------------------------------

# abstract class for logging targets
class LogTarget(object):
    """ Abstract class for logging targets. """
    def __init__(self):
        self.fd = None

    def write(self, data, level, logger, is_debug=0):
        raise NotImplementedError("LogTarget.write is an abstract method")

    def flush(self):
        raise NotImplementedError("LogTarget.flush is an abstract method")

    def close(self):
        raise NotImplementedError("LogTarget.close is an abstract method")

# ---------------------------------------------------------------------------

# private class for stdout
class _StdoutLog(LogTarget):
    def __init__(self):
        LogTarget.__init__(self)
        self.fd = sys.stdout

    def write(self, data, level, logger, is_debug=0):
        # ignore level
        self.fd.write(data)
        self.flush()

    def close(self):
        self.flush()

    def flush(self):
        self.fd.flush()

# ---------------------------------------------------------------------------

# private class for stderr
class _StderrLog(_StdoutLog):
    def __init__(self):
        _StdoutLog.__init__(self)
        self.fd = sys.stderr

# ---------------------------------------------------------------------------

# private class for syslog
class _SyslogLog(LogTarget):
    def __init__(self):
        # Only initialize LogTarget here as fs should be None
        LogTarget.__init__(self)
        #
        # Derived from: https://github.com/canvon/firewalld/commit/af0edfee1cc1891b7b13f302ca5911b24e9b0f13
        #
        # Work around Python issue 27875, "Syslogs /usr/sbin/foo as /foo
        # instead of as foo"
        # (but using openlog explicitly might be better anyway)
        #
        # Set ident to basename, log PID as well, and log to facility "daemon".
        syslog.openlog(os.path.basename(sys.argv[0]),
                       syslog.LOG_PID, syslog.LOG_DAEMON)

    def write(self, data, level, logger, is_debug=0):
        priority = None
        if is_debug:
            priority = syslog.LOG_DEBUG
        else:
            if level >= logger.INFO1:
                priority = syslog.LOG_INFO
            elif level == logger.WARNING:
                priority = syslog.LOG_WARNING
            elif level == logger.ERROR:
                priority = syslog.LOG_ERR
            elif level == logger.FATAL:
                priority = syslog.LOG_CRIT

        if data.endswith("\n"):
            data = data[:len(data)-1]
        if len(data) > 0:
            if priority is None:
                syslog.syslog(data)
            else:
                syslog.syslog(priority, data)

    def close(self):
        syslog.closelog()

    def flush(self):
        pass

# ---------------------------------------------------------------------------

class FileLog(LogTarget):
    """ FileLog class.
    File will be opened on the first write. """
    def __init__(self, filename, mode="w"):
        LogTarget.__init__(self)
        self.filename = filename
        self.mode = mode

    def open(self):
        if self.fd:
            return
        flags = os.O_CREAT | os.O_WRONLY
        if self.mode.startswith('a'):
            flags |= os.O_APPEND
        self.fd = os.open(self.filename, flags, 0o640)
        # Make sure that existing file has correct perms
        os.fchmod(self.fd, 0o640)
        # Make it an object
        self.fd = os.fdopen(self.fd, self.mode)
        fcntl.fcntl(self.fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)

    def write(self, data, level, logger, is_debug=0):
        if not self.fd:
            self.open()
        self.fd.write(data)
        self.fd.flush()

    def close(self):
        if not self.fd:
            return
        self.fd.close()
        self.fd = None

    def flush(self):
        if not self.fd:
            return
        self.fd.flush()

# ---------------------------------------------------------------------------

class Logger(object):
    r"""
    Format string:

    %(class)s      Calling class the function belongs to, else empty
    %(date)s       Date using Logger.date_format, see time module
    %(domain)s     Full Domain: %(module)s.%(class)s.%(function)s
    %(file)s       Filename of the module
    %(function)s   Function name, empty in __main__
    %(label)s      Label according to log function call from Logger.label
    %(level)d      Internal logging level
    %(line)d       Line number in module
    %(module)s     Module name
    %(message)s    Log message

    Standard levels:

    FATAL                 Fatal error messages
    ERROR                 Error messages
    WARNING               Warning messages
    INFOx, x in [1..5]    Information
    DEBUGy, y in [1..10]  Debug messages
    NO_INFO               No info output
    NO_DEBUG              No debug output
    INFO_MAX              Maximum info level
    DEBUG_MAX             Maximum debug level

    x and y depend on info_max and debug_max from Logger class
    initialization. See __init__ function.

    Default logging targets:

    stdout        Logs to stdout
    stderr        Logs to stderr
    syslog        Logs to syslog

    Additional arguments for logging functions (fatal, error, warning, info
    and debug):

    nl       Disable newline at the end with nl=0, default is nl=1.
    fmt      Format string for this logging entry, overloads global format
             string. Example: fmt="%(file)s:%(line)d %(message)s"
    nofmt    Only output message with nofmt=1. The nofmt argument wins over
             the fmt argument.

    Example:

    from logger import log
    log.setInfoLogLevel(log.INFO1)
    log.setDebugLogLevel(log.DEBUG1)
    for i in range(1, log.INFO_MAX+1):
        log.setInfoLogLabel(i, "INFO%d: " % i)
    log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: "
                  "%(level)d %(message)s")
    log.setDateFormat("%Y-%m-%d %H:%M:%S")

    fl = FileLog("/tmp/log", "a")
    log.addInfoLogging("*", fl)
    log.addDebugLogging("*", fl)
    log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s")

    log.debug3("debug3")
    log.debug2("debug2")
    log.debug1("debug1")
    log.info2("info2")
    log.info1("info1")
    log.warning("warning\n", nl=0)
    log.error("error\n", nl=0)
    log.fatal("fatal")
    log.info(log.INFO1, "nofmt info", nofmt=1)

    """

    ALL       = -5
    NOTHING   = -4
    FATAL     = -3
    TRACEBACK = -2
    ERROR     = -1
    WARNING   =  0

    # Additional levels are generated in class initilization

    stdout = _StdoutLog()
    stderr = _StderrLog()
    syslog = _SyslogLog()

    def __init__(self, info_max=5, debug_max=10):
        """ Logger class initialization """
        self._level = { }
        self._debug_level = { }
        self._format = ""
        self._date_format = ""
        self._label = { }
        self._debug_label = { }
        self._logging = { }
        self._debug_logging = { }
        self._domains = { }
        self._debug_domains = { }

        # INFO1 is required for standard log level
        if info_max < 1:
            raise ValueError("Logger: info_max %d is too low" % info_max)
        if debug_max < 0:
            raise ValueError("Logger: debug_max %d is too low" % debug_max)

        self.NO_INFO   = self.WARNING # = 0
        self.INFO_MAX  = info_max
        self.NO_DEBUG  = 0
        self.DEBUG_MAX = debug_max

        self.setInfoLogLabel(self.FATAL, "FATAL ERROR: ")
        self.setInfoLogLabel(self.TRACEBACK, "")
        self.setInfoLogLabel(self.ERROR, "ERROR: ")
        self.setInfoLogLabel(self.WARNING, "WARNING: ")

        # generate info levels and infox functions
        for _level in range(1, self.INFO_MAX+1):
            setattr(self, "INFO%d" % _level, _level)
            self.setInfoLogLabel(_level, "")
            setattr(self, "info%d" % (_level),
                    (lambda self, x:
                     lambda message, *args, **kwargs:
                     self.info(x, message, *args, **kwargs))(self, _level)) # pylint: disable=E0602

        # generate debug levels and debugx functions
        for _level in range(1, self.DEBUG_MAX+1):
            setattr(self, "DEBUG%d" % _level, _level)
            self.setDebugLogLabel(_level, "DEBUG%d: " % _level)
            setattr(self, "debug%d" % (_level),
                    (lambda self, x:
                     lambda message, *args, **kwargs:
                     self.debug(x, message, *args, **kwargs))(self, _level)) # pylint: disable=E0602

        # set initial log levels, formats and targets
        self.setInfoLogLevel(self.INFO1)
        self.setDebugLogLevel(self.NO_DEBUG)
        self.setFormat("%(label)s%(message)s")
        self.setDateFormat("%d %b %Y %H:%M:%S")
        self.setInfoLogging("*", self.stderr, [ self.FATAL, self.ERROR,
                                                self.WARNING ])
        self.setInfoLogging("*", self.stdout,
                            [ i for i in range(self.INFO1, self.INFO_MAX+1) ])
        self.setDebugLogging("*", self.stdout,
                             [ i for i in range(1, self.DEBUG_MAX+1) ])

    def close(self):
        """ Close all logging targets """
        for level in range(self.FATAL, self.DEBUG_MAX+1):
            if level not in self._logging:
                continue
            for (dummy, target, dummy) in self._logging[level]:
                target.close()

    def getInfoLogLevel(self, domain="*"):
        """ Get info log level. """
        self._checkDomain(domain)
        if domain in self._level:
            return self._level[domain]
        return self.NOTHING

    def setInfoLogLevel(self, level, domain="*"):
        """ Set log level [NOTHING .. INFO_MAX] """
        self._checkDomain(domain)
        if level < self.NOTHING:
            level = self.NOTHING
        if level > self.INFO_MAX:
            level = self.INFO_MAX
        self._level[domain] = level

    def getDebugLogLevel(self, domain="*"):
        """ Get debug log level. """
        self._checkDomain(domain)
        if domain in self._debug_level:
            return self._debug_level[domain] + self.NO_DEBUG
        return self.NO_DEBUG

    def setDebugLogLevel(self, level, domain="*"):
        """ Set debug log level [NO_DEBUG .. DEBUG_MAX] """
        self._checkDomain(domain)
        if level < 0:
            level = 0
        if level > self.DEBUG_MAX:
            level = self.DEBUG_MAX
        self._debug_level[domain] = level - self.NO_DEBUG

    def getFormat(self):
        return self._format

    def setFormat(self, _format):
        self._format = _format

    def getDateFormat(self):
        return self._date_format

    def setDateFormat(self, _format):
        self._date_format = _format

    def setInfoLogLabel(self, level, label):
        """ Set log label for level. Level can be a single level or an array
        of levels. """
        levels = self._getLevels(level)
        for level in levels:
            self._checkLogLevel(level, min_level=self.FATAL,
                                max_level=self.INFO_MAX)
            self._label[level] = label

    def setDebugLogLabel(self, level, label):
        """ Set log label for level. Level can be a single level or an array
        of levels. """
        levels = self._getLevels(level, is_debug=1)
        for level in levels:
            self._checkLogLevel(level, min_level=self.INFO1,
                                max_level=self.DEBUG_MAX)
            self._debug_label[level] = label

    def setInfoLogging(self, domain, target, level=ALL, fmt=None):
        """ Set info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. """
        self._setLogging(domain, target, level, fmt, is_debug=0)

    def setDebugLogging(self, domain, target, level=ALL, fmt=None):
        """ Set debug log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. """
        self._setLogging(domain, target, level, fmt, is_debug=1)

    def addInfoLogging(self, domain, target, level=ALL, fmt=None):
        """ Add info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. """
        self._addLogging(domain, target, level, fmt, is_debug=0)

    def addDebugLogging(self, domain, target, level=ALL, fmt=None):
        """ Add debg log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. """
        self._addLogging(domain, target, level, fmt, is_debug=1)

    def delInfoLogging(self, domain, target, level=ALL, fmt=None):
        """ Delete info log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. """
        self._delLogging(domain, target, level, fmt, is_debug=0)

    def delDebugLogging(self, domain, target, level=ALL, fmt=None):
        """ Delete debug log target for domain and level. Level can be a single
        level or an array of levels. Use level ALL to set for all levels.
        If no format is specified, the default format will be used. """
        self._delLogging(domain, target, level, fmt, is_debug=1)

    def isInfoLoggingHere(self, level):
        """ Is there currently any info logging for this log level (and
        domain)? """
        return self._isLoggingHere(level, is_debug=0)

    def isDebugLoggingHere(self, level):
        """ Is there currently any debug logging for this log level (and
        domain)? """
        return self._isLoggingHere(level, is_debug=1)

    ### log functions

    def fatal(self, _format, *args, **kwargs):
        """ Fatal error log. """
        self._checkKWargs(kwargs)
        kwargs["is_debug"] = 0
        self._log(self.FATAL, _format, *args, **kwargs)

    def error(self, _format, *args, **kwargs):
        """ Error log. """
        self._checkKWargs(kwargs)
        kwargs["is_debug"] = 0
        self._log(self.ERROR, _format, *args, **kwargs)

    def warning(self, _format, *args, **kwargs):
        """ Warning log. """
        self._checkKWargs(kwargs)
        kwargs["is_debug"] = 0
        self._log(self.WARNING, _format, *args, **kwargs)

    def info(self, level, _format, *args, **kwargs):
        """ Information log using info level [1..info_max].
        There are additional infox functions according to info_max from
        __init__"""
        self._checkLogLevel(level, min_level=1, max_level=self.INFO_MAX)
        self._checkKWargs(kwargs)
        kwargs["is_debug"] = 0
        self._log(level+self.NO_INFO, _format, *args, **kwargs)

    def debug(self, level, _format, *args, **kwargs):
        """ Debug log using debug level [1..debug_max].
        There are additional debugx functions according to debug_max
        from __init__"""
        self._checkLogLevel(level, min_level=1, max_level=self.DEBUG_MAX)
        self._checkKWargs(kwargs)
        kwargs["is_debug"] = 1
        self._log(level, _format, *args, **kwargs)

    def exception(self):
        self._log(self.TRACEBACK, traceback.format_exc(), args=[], kwargs={})

    ### internal functions

    def _checkLogLevel(self, level, min_level, max_level):
        if level < min_level or level > max_level:
            raise ValueError("Level %d out of range, should be [%d..%d]." % \
                             (level, min_level, max_level))

    def _checkKWargs(self, kwargs):
        if not kwargs:
            return
        for key in kwargs.keys():
            if key not in [ "nl", "fmt", "nofmt" ]:
                raise ValueError("Key '%s' is not allowed as argument for logging." % key)

    def _checkDomain(self, domain):
        if not domain or domain == "":
            raise ValueError("Domain '%s' is not valid." % domain)

    def _getLevels(self, level, is_debug=0):
        """ Generate log level array. """
        if level != self.ALL:
            if isinstance(level, list) or isinstance(level, tuple):
                levels = level
            else:
                levels = [ level ]
            for level in levels:
                if is_debug:
                    self._checkLogLevel(level, min_level=1,
                                        max_level=self.DEBUG_MAX)
                else:
                    self._checkLogLevel(level, min_level=self.FATAL,
                                        max_level=self.INFO_MAX)
        else:
            if is_debug:
                levels = [ i for i in range(self.DEBUG1, self.DEBUG_MAX) ]
            else:
                levels = [ i for i in range(self.FATAL, self.INFO_MAX) ]
        return levels

    def _getTargets(self, target):
        """ Generate target array. """
        if isinstance(target, list) or isinstance(target, tuple):
            targets = target
        else:
            targets = [ target ]
        for _target in targets:
            if not issubclass(_target.__class__, LogTarget):
                raise ValueError("'%s' is no valid logging target." % \
                      _target.__class__.__name__)
        return targets

    def _genDomains(self, is_debug=0):
        # private method for self._domains array creation, speeds up
        """ Generate dict with domain by level. """
        if is_debug:
            _domains = self._debug_domains
            _logging = self._debug_logging
            _range = ( 1, self.DEBUG_MAX+1 )
        else:
            _domains = self._domains
            _logging = self._logging
            _range = ( self.FATAL, self.INFO_MAX+1 )

        if len(_domains) > 0:
            _domains.clear()

        for level in range(_range[0], _range[1]):
            if level not in _logging:
                continue
            for (domain, dummy, dummy) in _logging[level]:
                if domain not in _domains:
                    _domains.setdefault(level, [ ]).append(domain)

    def _setLogging(self, domain, target, level=ALL, fmt=None, is_debug=0):
        self._checkDomain(domain)
        levels = self._getLevels(level, is_debug)
        targets = self._getTargets(target)

        if is_debug:
            _logging = self._debug_logging
        else:
            _logging = self._logging

        for level in levels:
            for target in targets:
                _logging[level] = [ (domain, target, fmt) ]
        self._genDomains(is_debug)

    def _addLogging(self, domain, target, level=ALL, fmt=None, is_debug=0):
        self._checkDomain(domain)
        levels = self._getLevels(level, is_debug)
        targets = self._getTargets(target)

        if is_debug:
            _logging = self._debug_logging
        else:
            _logging = self._logging

        for level in levels:
            for target in targets:
                _logging.setdefault(level, [ ]).append((domain, target, fmt))
        self._genDomains(is_debug)

    def _delLogging(self, domain, target, level=ALL, fmt=None, is_debug=0):
        self._checkDomain(domain)
        levels = self._getLevels(level, is_debug)
        targets = self._getTargets(target)

        if is_debug:
            _logging = self._debug_logging
        else:
            _logging = self._logging

        for _level in levels:
            for target in targets:
                if _level not in _logging:
                    continue
                if (domain, target, fmt) in _logging[_level]:
                    _logging[_level].remove( (domain, target, fmt) )
                    if len(_logging[_level]) == 0:
                        del _logging[_level]
                        continue
                if level != self.ALL:
                    raise ValueError("No mathing logging for " \
                          "level %d, domain %s, target %s and format %s." % \
                          (_level, domain, target.__class__.__name__, fmt))
        self._genDomains(is_debug)

    def _isLoggingHere(self, level, is_debug=0):
        _dict = self._genDict(level, is_debug)
        if not _dict:
            return False

        point_domain = _dict["domain"] + "."

        if is_debug:
            _logging = self._debug_logging
        else:
            _logging = self._logging

        # do we need to log?
        for (domain, dummy, dummy) in _logging[level]:
            if domain == "*" or \
                   point_domain.startswith(domain) or \
                   fnmatch.fnmatchcase(_dict["domain"], domain):
                return True
        return False

    def _getClass(self, frame):
        """ Function to get calling class. Returns class or None. """
        # get class by first function argument, if there are any
        if frame.f_code.co_argcount > 0:
            selfname = frame.f_code.co_varnames[0]
            if selfname in frame.f_locals:
                _self = frame.f_locals[selfname]
                obj = self._getClass2(_self.__class__, frame.f_code)
                if obj:
                    return obj

        module = inspect.getmodule(frame.f_code)
        code = frame.f_code

        # function in module?
        if code.co_name in module.__dict__:
            if hasattr(module.__dict__[code.co_name], "func_code") and \
                   module.__dict__[code.co_name].__code__  == code:
                return None

        # class in module
        for (dummy, obj) in module.__dict__.items():
            if isinstance(obj, types.ClassType):
                if hasattr(obj, code.co_name):
                    value = getattr(obj, code.co_name)
                    if isinstance(value, types.FunctionType):
                        if value.__code__ == code:
                            return obj

        # nothing found
        return None

    def _getClass2(self, obj, code):
        """ Internal function to get calling class. Returns class or None. """
        for value in obj.__dict__.values():
            if isinstance(value, types.FunctionType):
                if value.__code__ == code:
                    return obj

        for base in obj.__bases__:
            _obj = self._getClass2(base, code)
            if _obj:
                return _obj
        return None

    # internal log class
    def _log(self, level, _format, *args, **kwargs):
        is_debug = 0
        if "is_debug" in kwargs:
            is_debug = kwargs["is_debug"]

        nl = 1
        if "nl" in kwargs:
            nl = kwargs["nl"]

        nofmt = 0
        if "nofmt" in kwargs:
            nofmt = kwargs["nofmt"]

        _dict = self._genDict(level, is_debug)
        if not _dict:
            return

        if len(args) > 1:
            _dict['message'] = _format % args
        elif len(args) == 1:  # needed for _format % _dict
            _dict['message'] = _format % args[0]
        else:
            _dict['message'] = _format

        point_domain = _dict["domain"] + "."

        if is_debug:
            _logging = self._debug_logging
        else:
            _logging = self._logging

        used_targets = [ ]
        # log to target(s)
        for (domain, target, _format) in _logging[level]:
            if target in used_targets:
                continue
            if domain == "*" \
                   or point_domain.startswith(domain+".") \
                   or fnmatch.fnmatchcase(_dict["domain"], domain):
                if not _format:
                    _format = self._format
                if "fmt" in kwargs:
                    _format = kwargs["fmt"]
                if nofmt:
                    target.write(_dict["message"], level, self, is_debug)
                else:
                    target.write(_format % _dict, level, self, is_debug)
                if nl: # newline
                    target.write("\n", level, self, is_debug)
                used_targets.append(target)

    # internal function to generate the dict, needed for logging
    def _genDict(self, level, is_debug=0):
        """ Internal function. """
        check_domains = [ ]
        simple_match = False

        if is_debug:
            _dict = self._debug_level
            _domains = self._debug_domains
            _label = self._debug_label
        else:
            _dict = self._level
            _domains = self._domains
            _label = self._label

        # no debug
        for domain in _dict:
            if domain == "*":
                # '*' matches everything: simple match
                if _dict[domain] >= level:
                    simple_match = True
                    if len(check_domains) > 0:
                        check_domains = [ ]
                    break
            else:
                if _dict[domain] >= level:
                    check_domains.append(domain)

        if not simple_match and len(check_domains) < 1:
            return None

        if level not in _domains:
            return None

        f = inspect.currentframe()

        # go outside of logger module as long as there is a lower frame
        while f and f.f_back and f.f_globals["__name__"] == self.__module__:
            f = f.f_back

        if not f:
            raise ValueError("Frame information not available.")

        # get module name
        module_name = f.f_globals["__name__"]

        # simple module match test for all entries of check_domain
        point_module = module_name + "."
        for domain in check_domains:
            if point_module.startswith(domain):
                # found domain in module name
                check_domains = [ ]
                break

        # get code
        co = f.f_code

        # optimization: bail out early if domain can not match at all
        _len = len(module_name)
        for domain in _domains[level]:
            i = domain.find("*")
            if i == 0:
                continue
            elif i > 0:
                d = domain[:i]
            else:
                d = domain
            if _len >= len(d):
                if not module_name.startswith(d):
                    return None
            else:
                if not d.startswith(module_name):
                    return None

        # generate _dict for format output
        level_str = ""
        if level in _label:
            level_str = _label[level]
        _dict = { 'file': co.co_filename,
                  'line': f.f_lineno,
                  'module': module_name,
                  'class': '',
                  'function': co.co_name,
                  'domain': '',
                  'label' : level_str,
                  'level' : level,
                  'date' : time.strftime(self._date_format, time.localtime()) }
        if _dict["function"] == "?":
            _dict["function"] = ""

        # domain match needed?
        domain_needed = False
        for domain in _domains[level]:
            # standard domain, matches everything
            if domain == "*":
                continue
            # domain is needed
            domain_needed = True
            break

        # do we need to get the class object?
        if self._format.find("%(domain)") >= 0 or \
               self._format.find("%(class)") >= 0 or \
               domain_needed or \
               len(check_domains) > 0:
            obj = self._getClass(f)
            if obj:
                _dict["class"] = obj.__name__

        # build domain string
        _dict["domain"] = "" + _dict["module"]
        if _dict["class"] != "":
            _dict["domain"] += "." + _dict["class"]
        if _dict["function"] != "":
            _dict["domain"] += "." + _dict["function"]

        if len(check_domains) < 1:
            return _dict

        point_domain = _dict["domain"] + "."
        for domain in check_domains:
            if point_domain.startswith(domain) or \
                   fnmatch.fnmatchcase(_dict["domain"], domain):
                return _dict

        return None

# ---------------------------------------------------------------------------

# Global logging object.
log = Logger()

# ---------------------------------------------------------------------------

"""
# Example
if __name__ == '__main__':
    log.setInfoLogLevel(log.INFO2)
    log.setDebugLogLevel(log.DEBUG5)
    for i in range(log.INFO1, log.INFO_MAX+1):
        log.setInfoLogLabel(i, "INFO%d: " % i)
    for i in range(log.DEBUG1, log.DEBUG_MAX+1):
        log.setDebugLogLabel(i, "DEBUG%d: " % i)

    log.setFormat("%(date)s %(module)s:%(line)d %(label)s"
                  "%(message)s")
    log.setDateFormat("%Y-%m-%d %H:%M:%S")

    fl = FileLog("/tmp/log", "a")
    log.addInfoLogging("*", fl)
    log.delDebugLogging("*", log.stdout)
    log.setDebugLogging("*", log.stdout, [ log.DEBUG1, log.DEBUG2 ] )
    log.addDebugLogging("*", fl)
#    log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s")
#    log.addDebugLogging("*", log.syslog, fmt="%(label)s%(message)s")

    log.debug10("debug10")
    log.debug9("debug9")
    log.debug8("debug8")
    log.debug7("debug7")
    log.debug6("debug6")
    log.debug5("debug5")
    log.debug4("debug4")
    log.debug3("debug3")
    log.debug2("debug2", fmt="%(file)s:%(line)d %(message)s")
    log.debug1("debug1", nofmt=1)
    log.info5("info5")
    log.info4("info4")
    log.info3("info3")
    log.info2("info2")
    log.info1("info1")
    log.warning("warning\n", nl=0)
    log.error("error ", nl=0)
    log.error("error", nofmt=1)
    log.fatal("fatal")
    log.info(log.INFO1, "nofmt info", nofmt=1)
    log.info(log.INFO2, "info2 fmt", fmt="%(file)s:%(line)d %(message)s")

    try:
        a = b
    except Exception as e:
        log.exception()
"""

# vim:ts=4:sw=4:showmatch:expandtab
fw_transaction.py000064400000014246151731527150010155 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""Transaction classes for firewalld"""

__all__ = [ "FirewallTransaction" ]

import traceback

from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

class FirewallTransaction(object):
    def __init__(self, fw):
        self.fw = fw
        self.rules = { } # [ ( backend.name, [ rule,.. ] ),.. ]
        self.pre_funcs = [ ] # [ (func, args),.. ]
        self.post_funcs = [ ] # [ (func, args),.. ]
        self.fail_funcs = [ ] # [ (func, args),.. ]
        self.modules = [ ] # [ module,.. ]

    def clear(self):
        self.rules.clear()
        del self.pre_funcs[:]
        del self.post_funcs[:]
        del self.fail_funcs[:]

    def add_rule(self, backend, rule):
        self.rules.setdefault(backend.name, [ ]).append(rule)

    def add_rules(self, backend, rules):
        for rule in rules:
            self.add_rule(backend, rule)

    def query_rule(self, backend, rule):
        return backend.name in self.rules and rule in self.rules[backend.name]

    def remove_rule(self, backend, rule):
        if backend.name in self.rules and rule in self.rules[backend.name]:
            self.rules[backend.name].remove(rule)

    def add_pre(self, func, *args):
        self.pre_funcs.append((func, args))

    def add_post(self, func, *args):
        self.post_funcs.append((func, args))

    def add_fail(self, func, *args):
        self.fail_funcs.append((func, args))

    def add_module(self, module):
        if module not in self.modules:
            self.modules.append(module)

    def remove_module(self, module):
        if module in self.modules:
            self.modules.remove(module)

    def add_modules(self, modules):
        for module in modules:
            self.add_module(module)

    def remove_modules(self, modules):
        for module in modules:
            self.remove_module(module)

    def prepare(self, enable):
        log.debug4("%s.prepare(%s, %s)" % (type(self), enable, "..."))

        rules = { }
        if not enable:
            # reverse rule order for cleanup
            for backend_name in self.rules:
                for rule in reversed(self.rules[backend_name]):
                    rules.setdefault(backend_name, [ ]).append(
                        self.fw.get_backend_by_name(backend_name).reverse_rule(rule))
        else:
            for backend_name in self.rules:
                rules.setdefault(backend_name, [ ]).extend(self.rules[backend_name])

        return rules, self.modules

    def execute(self, enable):
        log.debug4("%s.execute(%s)" % (type(self), enable))

        rules, modules = self.prepare(enable)

        # pre
        self.pre()

        # stage 1: apply rules
        error = False
        errorMsg = ""
        done = [ ]
        for backend_name in rules:
            try:
                self.fw.rules(backend_name, rules[backend_name])
            except Exception as msg:
                error = True
                errorMsg = msg
                log.debug1(traceback.format_exc())
                log.error(msg)
            else:
                done.append(backend_name)

        # stage 2: load modules
        if not error:
            module_return = self.fw.handle_modules(modules, enable)
            if module_return:
                # Debug log about issues loading modules, but don't error. The
                # modules may be builtin or CONFIG_MODULES=n, in which case
                # modprobe will fail. Or we may be running inside a container
                # that doesn't have sufficient privileges. Unfortunately there
                # is no way for us to know.
                (status, msg) = module_return
                if status:
                    log.debug1(msg)

        # error case: revert rules
        if error:
            undo_rules = { }
            for backend_name in done:
                undo_rules[backend_name] = [ ]
                for rule in reversed(rules[backend_name]):
                    undo_rules[backend_name].append(
                        self.fw.get_backend_by_name(backend_name).reverse_rule(rule))
            for backend_name in undo_rules:
                try:
                    self.fw.rules(backend_name, undo_rules[backend_name])
                except Exception as msg:
                    log.debug1(traceback.format_exc())
                    log.error(msg)
            # call failure functions
            for (func, args) in self.fail_funcs:
                try:
                    func(*args)
                except Exception as msg:
                    log.debug1(traceback.format_exc())
                    log.error("Calling fail func %s(%s) failed: %s" % \
                              (func, args, msg))

            raise FirewallError(errors.COMMAND_FAILED, errorMsg)

        # post
        self.post()

    def pre(self):
        log.debug4("%s.pre()" % type(self))

        for (func, args) in self.pre_funcs:
            try:
                func(*args)
            except Exception as msg:
                log.debug1(traceback.format_exc())
                log.error("Calling pre func %s(%s) failed: %s" % \
                          (func, args, msg))

    def post(self):
        log.debug4("%s.post()" % type(self))

        for (func, args) in self.post_funcs:
            try:
                func(*args)
            except Exception as msg:
                log.debug1(traceback.format_exc())
                log.error("Calling post func %s(%s) failed: %s" % \
                          (func, args, msg))
prog.py000064400000002746151731527150006105 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import subprocess


__all__ = ["runProg"]


def runProg(prog, argv=None, stdin=None):
    if argv is None:
        argv = []

    args = [prog] + argv

    input_string = None
    if stdin:
        with open(stdin, 'r') as handle:
            input_string = handle.read().encode()

    env = {'LANG': 'C'}
    try:
        process = subprocess.Popen(args, stdin=subprocess.PIPE,
                                   stderr=subprocess.STDOUT,
                                   stdout=subprocess.PIPE,
                                   close_fds=True, env=env)
    except OSError:
        return (255, '')

    (output, err_output) = process.communicate(input_string)
    output = output.decode('utf-8', 'replace')
    return (process.returncode, output)
fw_direct.py000064400000053766151731527150007114 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

__all__ = [ "FirewallDirect" ]

from firewall.fw_types import LastUpdatedOrderedDict
from firewall.core import ipXtables
from firewall.core import ebtables
from firewall.core.fw_transaction import FirewallTransaction
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError

############################################################################
#
# class Firewall
#
############################################################################

class FirewallDirect(object):
    def __init__(self, fw):
        self._fw = fw
        self.__init_vars()

    def __repr__(self):
        return '%s(%r, %r, %r)' % (self.__class__, self._chains, self._rules,
                                   self._rule_priority_positions)

    def __init_vars(self):
        self._chains = { }
        self._rules = { }
        self._rule_priority_positions = { }
        self._passthroughs = { }
        self._obj = None

    def cleanup(self):
        self.__init_vars()

    # transaction

    def new_transaction(self):
        return FirewallTransaction(self._fw)

    # configuration

    def set_permanent_config(self, obj):
        self._obj = obj

    def has_runtime_configuration(self):
        if len(self._chains) + len(self._rules) + len(self._passthroughs) > 0:
            return True
        return False

    def has_configuration(self):
        if self.has_runtime_configuration():
            return True
        if len(self._obj.get_all_chains()) + \
           len(self._obj.get_all_rules()) + \
           len(self._obj.get_all_passthroughs()) > 0:
            return True
        return False

    def apply_direct(self, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        # Apply permanent configuration and save the obj to be able to
        # remove permanent configuration settings within get_runtime_config
        # for use in firewalld reload.
        self.set_config((self._obj.get_all_chains(),
                         self._obj.get_all_rules(),
                         self._obj.get_all_passthroughs()),
                        transaction)

        if use_transaction is None:
            transaction.execute(True)

    def get_runtime_config(self):
        # Return only runtime changes
        # Remove all chains, rules and passthroughs that are in self._obj
        # (permanent config applied in firewalld _start.
        chains = { }
        rules = { }
        passthroughs = { }

        for table_id in self._chains:
            (ipv, table) = table_id
            for chain in self._chains[table_id]:
                if not self._obj.query_chain(ipv, table, chain):
                    chains.setdefault(table_id, [ ]).append(chain)

        for chain_id in self._rules:
            (ipv, table, chain) = chain_id
            for (priority, args) in self._rules[chain_id]:
                if not self._obj.query_rule(ipv, table, chain, priority, args):
                    if chain_id not in rules:
                        rules[chain_id] = LastUpdatedOrderedDict()
                    rules[chain_id][(priority, args)] = priority

        for ipv in self._passthroughs:
            for args in self._passthroughs[ipv]:
                if not self._obj.query_passthrough(ipv, args):
                    if ipv not in passthroughs:
                        passthroughs[ipv] = [ ]
                    passthroughs[ipv].append(args)

        return (chains, rules, passthroughs)

    def get_config(self):
        return (self._chains, self._rules, self._passthroughs)

    def set_config(self, conf, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        (_chains, _rules, _passthroughs) = conf
        for table_id in _chains:
            (ipv, table) = table_id
            for chain in _chains[table_id]:
                if not self.query_chain(ipv, table, chain):
                    try:
                        self.add_chain(ipv, table, chain,
                                       use_transaction=transaction)
                    except FirewallError as error:
                        log.warning(str(error))

        for chain_id in _rules:
            (ipv, table, chain) = chain_id
            for (priority, args) in _rules[chain_id]:
                if not self.query_rule(ipv, table, chain, priority, args):
                    try:
                        self.add_rule(ipv, table, chain, priority, args,
                                      use_transaction=transaction)
                    except FirewallError as error:
                        log.warning(str(error))

        for ipv in _passthroughs:
            for args in _passthroughs[ipv]:
                if not self.query_passthrough(ipv, args):
                    try:
                        self.add_passthrough(ipv, args,
                                             use_transaction=transaction)
                    except FirewallError as error:
                        log.warning(str(error))

        if use_transaction is None:
            transaction.execute(True)

    def _check_ipv(self, ipv):
        ipvs = ['ipv4', 'ipv6', 'eb']
        if ipv not in ipvs:
            raise FirewallError(errors.INVALID_IPV,
                                "'%s' not in '%s'" % (ipv, ipvs))

    def _check_ipv_table(self, ipv, table):
        self._check_ipv(ipv)

        tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in [ 'ipv4', 'ipv6' ] \
                                         else ebtables.BUILT_IN_CHAINS.keys()
        if table not in tables:
            raise FirewallError(errors.INVALID_TABLE,
                                "'%s' not in '%s'" % (table, tables))

    def _check_builtin_chain(self, ipv, table, chain):
        if ipv in ['ipv4', 'ipv6']:
            built_in_chains = ipXtables.BUILT_IN_CHAINS[table]
            if self._fw.nftables_enabled:
                our_chains = {}
            else:
                our_chains = self._fw.get_direct_backend_by_ipv(ipv).our_chains[table]
        else:
            built_in_chains = ebtables.BUILT_IN_CHAINS[table]
            our_chains = ebtables.OUR_CHAINS[table]
        if chain in built_in_chains:
            raise FirewallError(errors.BUILTIN_CHAIN,
                                "chain '%s' is built-in chain" % chain)
        if chain in our_chains:
            raise FirewallError(errors.BUILTIN_CHAIN,
                                "chain '%s' is reserved" % chain)
        if ipv in [ "ipv4", "ipv6" ]:
            if self._fw.zone.zone_from_chain(chain) is not None:
                raise FirewallError(errors.INVALID_CHAIN,
                                    "Chain '%s' is reserved" % chain)


    def _register_chain(self, table_id, chain, add):
        if add:
            self._chains.setdefault(table_id, [ ]).append(chain)
        else:
            self._chains[table_id].remove(chain)
            if len(self._chains[table_id]) == 0:
                del self._chains[table_id]

    def add_chain(self, ipv, table, chain, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if self._fw.may_skip_flush_direct_backends():
            transaction.add_pre(self._fw.flush_direct_backends)

        #TODO: policy="ACCEPT"
        self._chain(True, ipv, table, chain, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def remove_chain(self, ipv, table, chain, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        self._chain(False, ipv, table, chain, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def query_chain(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        self._check_builtin_chain(ipv, table, chain)
        table_id = (ipv, table)
        return (table_id in self._chains and
                chain in self._chains[table_id])

    def get_chains(self, ipv, table):
        self._check_ipv_table(ipv, table)
        table_id = (ipv, table)
        if table_id in self._chains:
            return self._chains[table_id]
        return [ ]

    def get_all_chains(self):
        r = [ ]
        for key in self._chains:
            (ipv, table) = key
            for chain in self._chains[key]:
                r.append((ipv, table, chain))
        return r


    def add_rule(self, ipv, table, chain, priority, args, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if self._fw.may_skip_flush_direct_backends():
            transaction.add_pre(self._fw.flush_direct_backends)

        self._rule(True, ipv, table, chain, priority, args, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def remove_rule(self, ipv, table, chain, priority, args,
                    use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        self._rule(False, ipv, table, chain, priority, args, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def query_rule(self, ipv, table, chain, priority, args):
        self._check_ipv_table(ipv, table)
        chain_id = (ipv, table, chain)
        return chain_id in self._rules and \
            (priority, args) in self._rules[chain_id]

    def get_rules(self, ipv, table, chain):
        self._check_ipv_table(ipv, table)
        chain_id = (ipv, table, chain)
        if chain_id in self._rules:
            return list(self._rules[chain_id].keys())
        return [ ]

    def get_all_rules(self):
        r = [ ]
        for key in self._rules:
            (ipv, table, chain) = key
            for (priority, args) in self._rules[key]:
                r.append((ipv, table, chain, priority, list(args)))
        return r

    def _register_rule(self, rule_id, chain_id, priority, enable, count):
        if enable:
            if chain_id not in self._rules:
                self._rules[chain_id] = LastUpdatedOrderedDict()
            self._rules[chain_id][rule_id] = priority
            if chain_id not in self._rule_priority_positions:
                self._rule_priority_positions[chain_id] = { }

            if priority in self._rule_priority_positions[chain_id]:
                self._rule_priority_positions[chain_id][priority] += count
            else:
                self._rule_priority_positions[chain_id][priority] = count
        else:
            del self._rules[chain_id][rule_id]
            if len(self._rules[chain_id]) == 0:
                del self._rules[chain_id]
            self._rule_priority_positions[chain_id][priority] -= count

    # DIRECT PASSTHROUGH (untracked)

    def passthrough(self, ipv, args):
        try:
            return self._fw.rule(self._fw.get_direct_backend_by_ipv(ipv).name, args)
        except Exception as msg:
            log.debug2(msg)
            raise FirewallError(errors.COMMAND_FAILED, msg)


    def _register_passthrough(self, ipv, args, enable):
        if enable:
            if ipv not in self._passthroughs:
                self._passthroughs[ipv] = [ ]
            self._passthroughs[ipv].append(args)
        else:
            self._passthroughs[ipv].remove(args)
            if len(self._passthroughs[ipv]) == 0:
                del self._passthroughs[ipv]

    def add_passthrough(self, ipv, args, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if self._fw.may_skip_flush_direct_backends():
            transaction.add_pre(self._fw.flush_direct_backends)

        self._passthrough(True, ipv, list(args), transaction)

        if use_transaction is None:
            transaction.execute(True)

    def remove_passthrough(self, ipv, args, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        self._passthrough(False, ipv, list(args), transaction)

        if use_transaction is None:
            transaction.execute(True)

    def query_passthrough(self, ipv, args):
        return ipv in self._passthroughs and \
            tuple(args) in self._passthroughs[ipv]

    def get_all_passthroughs(self):
        r = [ ]
        for ipv in self._passthroughs:
            for args in self._passthroughs[ipv]:
                r.append((ipv, list(args)))
        return r

    def get_passthroughs(self, ipv):
        r = [ ]
        if ipv in self._passthroughs:
            for args in self._passthroughs[ipv]:
                r.append(list(args))
        return r

    def split_value(self, rules, opts):
        """Split values combined with commas for options in opts"""

        out_rules = [ ]
        for rule in rules:
            processed = False
            for opt in opts:
                try:
                    i = rule.index(opt)
                except ValueError:
                    pass
                else:
                    if len(rule) > i and "," in rule[i+1]:
                        # For all items in the comma separated list in index
                        # i of the rule, a new rule is created with a single
                        # item from this list
                        processed = True
                        items = rule[i+1].split(",")
                        for item in items:
                            _rule = rule[:]
                            _rule[i+1] = item
                            out_rules.append(_rule)
            if not processed:
                out_rules.append(rule)

        return out_rules


    def _rule(self, enable, ipv, table, chain, priority, args, transaction):
        self._check_ipv_table(ipv, table)
        # Do not create zone chains if we're using nftables. Only allow direct
        # rules in the built in chains.
        if not self._fw.nftables_enabled \
           and ipv in [ "ipv4", "ipv6" ]:
            self._fw.zone.create_zone_base_by_chain(ipv, table, chain,
                                                    transaction)

        _chain = chain

        backend = self._fw.get_direct_backend_by_ipv(ipv)

        # if nftables is in use, just put the direct rules in the chain
        # specified by the user. i.e. don't append _direct.
        if not self._fw.nftables_enabled \
           and backend.is_chain_builtin(ipv, table, chain):
            _chain = "%s_direct" % (chain)
        elif self._fw.nftables_enabled and chain[-7:] == "_direct" \
             and backend.is_chain_builtin(ipv, table, chain[:-7]):
            # strip _direct suffix. If we're using nftables we don't bother
            # creating the *_direct chains for builtin chains.
            _chain = chain[:-7]

        chain_id = (ipv, table, chain)
        rule_id = (priority, args)

        if enable:
            if chain_id in self._rules and \
                    rule_id in self._rules[chain_id]:
                raise FirewallError(errors.ALREADY_ENABLED,
                                    "rule '%s' already is in '%s:%s:%s'" % \
                                    (args, ipv, table, chain))
        else:
            if chain_id not in self._rules or \
                    rule_id not in self._rules[chain_id]:
                raise FirewallError(errors.NOT_ENABLED,
                                    "rule '%s' is not in '%s:%s:%s'" % \
                                    (args, ipv, table, chain))

            # get priority of rule
            priority = self._rules[chain_id][rule_id]

        # If a rule gets added, the initial rule index position within the
        # ipv, table and chain combination (chain_id) is 1.
        # Tf the chain_id exists in _rule_priority_positions, there are already
        # other rules for this chain_id. The number of rules for a priority
        # less or equal to the priority of the new rule will increase the
        # index of the new rule. The index is the ip*tables -I insert rule
        # number.
        #
        # Example: We have the following rules for chain_id (ipv4, filter,
        # INPUT) already:
        #   ipv4, filter, INPUT, 1, -i, foo1, -j, ACCEPT
        #   ipv4, filter, INPUT, 2, -i, foo2, -j, ACCEPT
        #   ipv4, filter, INPUT, 2, -i, foo2_1, -j, ACCEPT
        #   ipv4, filter, INPUT, 3, -i, foo3, -j, ACCEPT
        # This results in the following _rule_priority_positions structure:
        #   _rule_priority_positions[(ipv4,filter,INPUT)][1] = 1
        #   _rule_priority_positions[(ipv4,filter,INPUT)][2] = 2
        #   _rule_priority_positions[(ipv4,filter,INPUT)][3] = 1
        # The new rule
        #   ipv4, filter, INPUT, 2, -i, foo2_2, -j, ACCEPT
        # has the same pritority as the second rule before and will be added
        # right after it.
        # The initial index is 1 and the chain_id is already in
        # _rule_priority_positions. Therefore the index will increase for
        # the number of rules in every rule position in
        # _rule_priority_positions[(ipv4,filter,INPUT)].keys()
        # where position is smaller or equal to the entry in keys.
        # With the example from above:
        # The priority of the new rule is 2. Therefore for all keys in
        # _rule_priority_positions[chain_id] where priority is 1 or 2, the
        # number of the rules will increase the index of the rule.
        # For _rule_priority_positions[chain_id][1]: index += 1
        # _rule_priority_positions[chain_id][2]: index += 2
        # index will be 4 in the end and the rule in the table chain
        # combination will be added at index 4.
        # If there are no rules in the table chain combination, a new rule
        # has index 1.

        index = 1
        count = 0
        if chain_id in self._rule_priority_positions:
            positions = sorted(self._rule_priority_positions[chain_id].keys())
            j = 0
            while j < len(positions) and priority >= positions[j]:
                index += self._rule_priority_positions[chain_id][positions[j]]
                j += 1

        # split the direct rule in some cases as iptables-restore can't handle
        # compound args.
        #
        args_list = [list(args)]
        args_list = self.split_value(args_list, [ "-s", "--source" ])
        args_list = self.split_value(args_list, [ "-d", "--destination" ])

        for _args in args_list:
            transaction.add_rule(backend, backend.build_rule(enable, table, _chain, index, tuple(_args)))
            index += 1
            count += 1

        self._register_rule(rule_id, chain_id, priority, enable, count)
        transaction.add_fail(self._register_rule,
                             rule_id, chain_id, priority, not enable, count)

    def _chain(self, add, ipv, table, chain, transaction):
        self._check_ipv_table(ipv, table)
        self._check_builtin_chain(ipv, table, chain)
        table_id = (ipv, table)

        if add:
            if table_id in self._chains and \
                    chain in self._chains[table_id]:
                raise FirewallError(errors.ALREADY_ENABLED,
                                    "chain '%s' already is in '%s:%s'" % \
                                    (chain, ipv, table))
        else:
            if table_id not in self._chains or \
                    chain not in self._chains[table_id]:
                raise FirewallError(errors.NOT_ENABLED,
                                    "chain '%s' is not in '%s:%s'" % \
                                    (chain, ipv, table))

        backend = self._fw.get_direct_backend_by_ipv(ipv)
        transaction.add_rules(backend, backend.build_chain_rules(add, table, chain))

        self._register_chain(table_id, chain, add)
        transaction.add_fail(self._register_chain, table_id, chain, not add)

    def _passthrough(self, enable, ipv, args, transaction):
        self._check_ipv(ipv)

        tuple_args = tuple(args)
        if enable:
            if ipv in self._passthroughs and \
               tuple_args in self._passthroughs[ipv]:
                raise FirewallError(errors.ALREADY_ENABLED,
                                    "passthrough '%s', '%s'" % (ipv, args))
        else:
            if ipv not in self._passthroughs or \
               tuple_args not in self._passthroughs[ipv]:
                raise FirewallError(errors.NOT_ENABLED,
                                    "passthrough '%s', '%s'" % (ipv, args))

        backend = self._fw.get_direct_backend_by_ipv(ipv)

        if enable:
            backend.check_passthrough(args)
            # try to find out if a zone chain should be used
            if ipv in [ "ipv4", "ipv6" ]:
                table, chain = backend.passthrough_parse_table_chain(args)
                if table and chain:
                    self._fw.zone.create_zone_base_by_chain(ipv, table, chain)
            _args = args
        else:
            _args = backend.reverse_passthrough(args)

        transaction.add_rule(backend, _args)

        self._register_passthrough(ipv, tuple_args, enable)
        transaction.add_fail(self._register_passthrough, ipv, tuple_args,
                             not enable)
fw_nm.py000064400000016022151731527150006234 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""Functions for NetworkManager interaction"""

__all__ = [ "check_nm_imported", "nm_is_imported",
            "nm_get_zone_of_connection", "nm_set_zone_of_connection",
            "nm_get_connections", "nm_get_connection_of_interface",
            "nm_get_bus_name", "nm_get_dbus_interface" ]

import gi
from gi.repository import GLib
try:
    gi.require_version('NM', '1.0')
except ValueError:
    _nm_imported = False
else:
    try:
        from gi.repository import NM
        _nm_imported = True
    except (ImportError, ValueError, GLib.Error):
        _nm_imported = False
_nm_client = None

from firewall import errors
from firewall.errors import FirewallError
from firewall.core.logger import log
import dbus

def check_nm_imported():
    """Check function to raise a MISSING_IMPORT error if the import of NM failed
    """
    if not _nm_imported:
        raise FirewallError(errors.MISSING_IMPORT, "gi.repository.NM = 1.0")

def nm_is_imported():
    """Returns true if NM has been properly imported
    @return True if import was successful, False otherwirse
    """
    return _nm_imported

def nm_get_client():
    """Returns the NM client object or None if the import of NM failed
    @return NM.Client instance if import was successful, None otherwise
    """
    global _nm_client
    if not _nm_client:
        _nm_client = NM.Client.new(None)
    return _nm_client

def nm_get_zone_of_connection(connection):
    """Get zone of connection from NM
    @param connection name
    @return zone string setting of connection, empty string if not set, None if connection is unknown
    """
    check_nm_imported()

    con = nm_get_client().get_connection_by_uuid(connection)
    if con is None:
        return None

    setting_con = con.get_setting_connection()
    if setting_con is None:
        return None

    try:
        if con.get_flags() & (NM.SettingsConnectionFlags.NM_GENERATED
                              | NM.SettingsConnectionFlags.NM_VOLATILE):
            return ""
    except AttributeError:
        # Prior to NetworkManager 1.12, we can only guess
        # that a connection was generated/volatile.
        if con.get_unsaved():
            return ""

    zone = setting_con.get_zone()
    if zone is None:
        zone = ""
    return zone

def nm_set_zone_of_connection(zone, connection):
    """Set the zone for a connection
    @param zone name
    @param connection name
    @return True if zone was set, else False
    """
    check_nm_imported()

    con = nm_get_client().get_connection_by_uuid(connection)
    if con is None:
        return False

    setting_con = con.get_setting_connection()
    if setting_con is None:
        return False

    if zone == "":
        zone = None
    setting_con.set_property("zone", zone)
    return con.commit_changes(True, None)

def nm_get_connections(connections, connections_name):
    """Get active connections from NM
    @param connections return dict
    @param connections_name return dict
    """

    connections.clear()
    connections_name.clear()

    check_nm_imported()

    active_connections = nm_get_client().get_active_connections()

    for active_con in active_connections:
        # ignore vpn devices for now
        if active_con.get_vpn():
            continue

        name = active_con.get_id()
        uuid = active_con.get_uuid()
        devices = active_con.get_devices()

        connections_name[uuid] = name
        for dev in devices:
            ip_iface = dev.get_ip_iface()
            if ip_iface:
                connections[ip_iface] = uuid

def nm_get_interfaces():
    """Get active interfaces from NM
    @returns list of interface names
    """

    check_nm_imported()

    active_interfaces = []

    for active_con in nm_get_client().get_active_connections():
        # ignore vpn devices for now
        if active_con.get_vpn():
            continue

        try:
            con = active_con.get_connection()
            if con.get_flags() & (NM.SettingsConnectionFlags.NM_GENERATED
                                  | NM.SettingsConnectionFlags.NM_VOLATILE):
                continue
        except AttributeError:
            # Prior to NetworkManager 1.12, we can only guess
            # that a connection was generated/volatile.
            if con.get_unsaved():
                continue

        for dev in active_con.get_devices():
            ip_iface = dev.get_ip_iface()
            if ip_iface:
                active_interfaces.append(ip_iface)

    return active_interfaces

def nm_get_interfaces_in_zone(zone):
    interfaces = []
    for interface in nm_get_interfaces():
        conn = nm_get_connection_of_interface(interface)
        if zone == nm_get_zone_of_connection(conn):
            interfaces.append(interface)

    return interfaces

def nm_get_device_by_ip_iface(interface):
    """Get device from NM which has the given IP interface
    @param interface name
    @returns NM.Device instance or None
    """
    check_nm_imported()

    for device in nm_get_client().get_devices():
        ip_iface = device.get_ip_iface()
        if ip_iface is None:
            continue
        if ip_iface == interface:
            return device

    return None

def nm_get_connection_of_interface(interface):
    """Get connection from NM that is using the interface
    @param interface name
    @returns connection that is using interface or None
    """
    check_nm_imported()

    device = nm_get_device_by_ip_iface(interface)
    if device is None:
        return None

    active_con = device.get_active_connection()
    if active_con is None:
        return None

    try:
        con = active_con.get_connection()
        if con.get_flags() & NM.SettingsConnectionFlags.NM_GENERATED:
            return None
    except AttributeError:
        # Prior to NetworkManager 1.12, we can only guess
        # that a connection was generated.
        if con.get_unsaved():
            return None

    return active_con.get_uuid()

def nm_get_bus_name():
    if not _nm_imported:
        return None
    try:
        bus = dbus.SystemBus()
        obj = bus.get_object(NM.DBUS_INTERFACE, NM.DBUS_PATH)
        name = obj.bus_name
        del obj, bus
        return name
    except Exception:
        log.debug2("Failed to get bus name of NetworkManager")
    return None

def nm_get_dbus_interface():
    if not _nm_imported:
        return ""
    return NM.DBUS_INTERFACE
helper.py000064400000001444151731527150006407 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""The helper maxnamelen"""

HELPER_MAXNAMELEN = 32
fw_helper.py000064400000003451151731527150007103 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2015-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""helper backend"""

__all__ = [ "FirewallHelper" ]

from firewall import errors
from firewall.errors import FirewallError

class FirewallHelper(object):
    def __init__(self, fw):
        self._fw = fw
        self._helpers = { }

    def __repr__(self):
        return '%s(%r)' % (self.__class__, self._helpers)

    # helpers

    def cleanup(self):
        self._helpers.clear()

    def check_helper(self, name):
        if name not in self.get_helpers():
            raise FirewallError(errors.INVALID_HELPER, name)

    def query_helper(self, name):
        return name in self.get_helpers()

    def get_helpers(self):
        return sorted(self._helpers.keys())

    def has_helpers(self):
        return len(self._helpers) > 0

    def get_helper(self, name):
        self.check_helper(name)
        return self._helpers[name]

    def add_helper(self, obj):
        self._helpers[obj.name] = obj

    def remove_helper(self, name):
        if name not in self._helpers:
            raise FirewallError(errors.INVALID_HELPER, name)
        del self._helpers[name]
fw_zone.py000064400000131171151731527150006600 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import time
import copy
from firewall.core.base import SHORTCUTS, DEFAULT_ZONE_TARGET, SOURCE_IPSET_TYPES
from firewall.core.fw_transaction import FirewallTransaction
from firewall.core.io.policy import Policy
from firewall.core.logger import log
from firewall.core.rich import Rich_Service, Rich_Port, Rich_Protocol, Rich_SourcePort, Rich_ForwardPort, \
                               Rich_IcmpBlock, Rich_IcmpType, Rich_Masquerade, Rich_Mark
from firewall.functions import checkIPnMask, checkIP6nMask, check_mac
from firewall import errors
from firewall.errors import FirewallError
from firewall.fw_types import LastUpdatedOrderedDict

class FirewallZone(object):
    ZONE_POLICY_PRIORITY = 0

    def __init__(self, fw):
        self._fw = fw
        self._zones = { }
        self._zone_policies = { }

    def __repr__(self):
        return '%s(%r)' % (self.__class__, self._zones)

    def cleanup(self):
        self._zones.clear()
        self._zone_policies.clear()

    def new_transaction(self):
        return FirewallTransaction(self._fw)

    def policy_name_from_zones(self, fromZone, toZone):
        return "zone_{fromZone}_{toZone}".format(fromZone=fromZone, toZone=toZone)

    # zones

    def get_zones(self):
        return sorted(self._zones.keys())

    def get_active_zones(self):
        active_zones = []
        for zone in self.get_zones():
            if self.list_interfaces(zone) or self.list_sources(zone):
                active_zones.append(zone)
        return active_zones

    def get_zone_of_interface(self, interface):
        interface_id = self.__interface_id(interface)
        for zone in self._zones:
            if interface_id in self._zones[zone].settings["interfaces"]:
                # an interface can only be part of one zone
                return zone
        return None

    def get_zone_of_source(self, source):
        source_id = self.__source_id(source)
        for zone in self._zones:
            if source_id in self._zones[zone].settings["sources"]:
                # a source_id can only be part of one zone
                return zone
        return None

    def get_zone(self, zone):
        z = self._fw.check_zone(zone)
        return self._zones[z]

    def policy_obj_from_zone_obj(self, z_obj, fromZone, toZone):
        p_obj = Policy()
        p_obj.derived_from_zone = z_obj.name
        p_obj.name = self.policy_name_from_zones(fromZone, toZone)
        p_obj.priority = self.ZONE_POLICY_PRIORITY
        p_obj.target = z_obj.target
        p_obj.ingress_zones = [fromZone]
        p_obj.egress_zones = [toZone]

        # copy zone permanent config to policy permanent config
        # WARN: This assumes the same attribute names.
        #
        for setting in ["services", "ports",
                        "masquerade", "forward_ports",
                        "source_ports",
                        "icmp_blocks", "rules",
                        "protocols"]:
            if fromZone == z_obj.name and toZone == "HOST" and \
               setting in ["services", "ports", "source_ports", "icmp_blocks", "protocols"]:
                # zone --> HOST
                setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting)))
            elif fromZone == "ANY" and toZone == z_obj.name and setting in ["masquerade"]:
                # any zone --> zone
                setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting)))
            elif fromZone == z_obj.name and toZone == "ANY" and \
                 setting in ["icmp_blocks", "forward_ports"]:
                # zone --> any zone
                setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting)))
            elif setting in ["rules"]:
                p_obj.rules = []
                for rule in z_obj.rules:
                    current_policy = self.policy_name_from_zones(fromZone, toZone)

                    if current_policy in self._rich_rule_to_policies(z_obj.name, rule):
                        p_obj.rules.append(copy.deepcopy(rule))

        return p_obj

    def add_zone(self, obj):
        obj.settings = { x : LastUpdatedOrderedDict()
                         for x in ["interfaces", "sources",
                                   "icmp_block_inversion",
                                   "forward"] }
        self._zones[obj.name] = obj
        self._zone_policies[obj.name] = []

        # Create policy objects, will need many:
        #   - (zone --> HOST) - ports, service, etc
        #   - (any zone --> zone) - masquerade
        #   - (zone --> any zone) - ICMP block, icmp block inversion
        #       - also includes forward-ports because it works on (nat,
        #       PREROUTING) and therefore applies to redirects to the local
        #       host or dnat to a different host.
        #       - also includes rich rule "mark" action for the same reason
        #
        for fromZone,toZone in [(obj.name, "HOST"),
                                ("ANY", obj.name), (obj.name, "ANY")]:
            p_obj = self.policy_obj_from_zone_obj(obj, fromZone, toZone)
            self._fw.policy.add_policy(p_obj)
            self._zone_policies[obj.name].append(p_obj.name)

        self.copy_permanent_to_runtime(obj.name)

    def copy_permanent_to_runtime(self, zone):
        obj = self._zones[zone]

        for arg in obj.interfaces:
            self.add_interface(zone, arg, allow_apply=False)
        for arg in obj.sources:
            self.add_source(zone, arg, allow_apply=False)
        if obj.forward:
            self.add_forward(zone)
        if obj.icmp_block_inversion:
            self.add_icmp_block_inversion(zone)

    def remove_zone(self, zone):
        obj = self._zones[zone]
        if obj.applied:
            self.unapply_zone_settings(zone)
        obj.settings.clear()
        del self._zones[zone]
        del self._zone_policies[zone]

    def apply_zones(self, use_transaction=None):
        for zone in self.get_zones():
            z_obj = self._zones[zone]
            if len(z_obj.interfaces) > 0 or len(z_obj.sources) > 0:
                log.debug1("Applying zone '%s'", zone)
                self.apply_zone_settings(zone, use_transaction=use_transaction)

    def set_zone_applied(self, zone, applied):
        obj = self._zones[zone]
        obj.applied = applied

    # zone from chain

    def zone_from_chain(self, chain):
        if "_" not in chain:
            # no zone chain
            return None
        splits = chain.split("_")
        if len(splits) < 2:
            return None
        _chain = None
        for x in SHORTCUTS:
            if splits[0] == SHORTCUTS[x]:
                _chain = x
        if _chain is not None:
            # next part needs to be zone name
            if splits[1] not in self.get_zones():
                return None
            if len(splits) == 2 or \
               (len(splits) == 3 and splits[2] in [ "pre", "log", "deny", "allow", "post" ]):
                return (splits[1], _chain)
        return None

    def policy_from_chain(self, chain):
        x = self.zone_from_chain(chain)
        if x is None:
            return None

        (zone, _chain) = x
        # derived from _get_table_chains_for_zone_dispatch()
        if _chain in ["PREROUTING", "FORWARD_IN"]:
            fromZone = zone
            toZone = "ANY"
        elif _chain in ["INPUT"]:
            fromZone = zone
            toZone = "HOST"
        elif _chain in ["POSTROUTING", "FORWARD_OUT"]:
            fromZone = "ANY"
            toZone = zone
        else:
            raise FirewallError(errors.INVALID_CHAIN, "chain '%s' can't be mapped to a policy" % (chain))

        return (self.policy_name_from_zones(fromZone, toZone), _chain)

    def create_zone_base_by_chain(self, ipv, table, chain,
                                  use_transaction=None):

        # Create zone base chains if the chain is reserved for a zone
        if ipv in [ "ipv4", "ipv6" ]:
            x = self.policy_from_chain(chain)
            if x is not None:
                (policy, _chain) = self.policy_from_chain(chain)
                if use_transaction is None:
                    transaction = self.new_transaction()
                else:
                    transaction = use_transaction

                self._fw.policy.gen_chain_rules(policy, True, table, _chain,
                                                transaction)

                if use_transaction is None:
                    transaction.execute(True)

    # settings

    # generate settings record with sender, timeout
    def __gen_settings(self, timeout, sender):
        ret = {
            "date": time.time(),
            "sender": sender,
            "timeout": timeout,
        }
        return ret

    def get_settings(self, zone):
        return self.get_zone(zone).settings

    def _zone_settings(self, enable, zone, transaction):
        settings = self.get_settings(zone)
        for key in settings:
            for args in settings[key]:
                if key == "interfaces":
                    self._interface(enable, zone, args, transaction)
                elif key == "sources":
                    self._source(enable, zone, args[0], args[1], transaction)
                elif key == "icmp_block_inversion":
                    continue
                elif key == "forward":
                    # no need to call this when applying the zone as the rules
                    # will be generated when adding the interfaces/sources
                    pass
                else:
                    log.warning("Zone '%s': Unknown setting '%s:%s', "
                                "unable to apply", zone, key, args)
        # ICMP-block-inversion is always applied
        if enable:
            self._icmp_block_inversion(enable, zone, transaction)

    def apply_zone_settings(self, zone, use_transaction=None):
        _zone = self._fw.check_zone(zone)
        obj = self._zones[_zone]
        if obj.applied:
            return
        obj.applied = True

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        for policy in self._zone_policies[_zone]:
            log.debug1("Applying policy (%s) derived from zone '%s'", policy, zone)
            self._fw.policy.apply_policy_settings(policy, use_transaction=transaction)

        self._zone_settings(True, _zone, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def unapply_zone_settings(self, zone, use_transaction=None):
        _zone = self._fw.check_zone(zone)
        obj = self._zones[_zone]
        if not obj.applied:
            return

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        for policy in self._zone_policies[_zone]:
            self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction)

        self._zone_settings(False, _zone, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def get_config_with_settings(self, zone):
        """
        :return: exported config updated with runtime settings
        """
        obj = self.get_zone(zone)
        conf_dict = self.get_config_with_settings_dict(zone)
        conf_list = []
        for i in range(16): # tuple based API has 16 elements
            if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict:
                # old API needs the empty elements as well. Grab it from the
                # class otherwise we don't know the type.
                conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0])))
            else:
                conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]])
        return tuple(conf_list)

    def get_config_with_settings_dict(self, zone):
        """
        :return: exported config updated with runtime settings
        """
        permanent = self.get_zone(zone).export_config_dict()
        if permanent["target"] == DEFAULT_ZONE_TARGET:
            permanent["target"] = "default"
        runtime = { "services": self.list_services(zone),
                    "ports": self.list_ports(zone),
                    "icmp_blocks": self.list_icmp_blocks(zone),
                    "masquerade": self.query_masquerade(zone),
                    "forward_ports": self.list_forward_ports(zone),
                    "interfaces": self.list_interfaces(zone),
                    "sources": self.list_sources(zone),
                    "rules_str": self.list_rules(zone),
                    "protocols": self.list_protocols(zone),
                    "source_ports": self.list_source_ports(zone),
                    "icmp_block_inversion": self.query_icmp_block_inversion(zone),
                    "forward": self.query_forward(zone),
                    }
        return self._fw.combine_runtime_with_permanent_settings(permanent, runtime)

    def set_config_with_settings_dict(self, zone, settings, sender):
        # stupid wrappers to convert rich rule string to rich rule object
        from firewall.core.rich import Rich_Rule
        def add_rule_wrapper(zone, rule_str, timeout=0, sender=None):
            self.add_rule(zone, Rich_Rule(rule_str=rule_str), timeout=0, sender=sender)
        def remove_rule_wrapper(zone, rule_str):
            self.remove_rule(zone, Rich_Rule(rule_str=rule_str))

        setting_to_fn = {
            "services": (self.add_service, self.remove_service),
            "ports": (self.add_port, self.remove_port),
            "icmp_blocks": (self.add_icmp_block, self.remove_icmp_block),
            "masquerade": (self.add_masquerade, self.remove_masquerade),
            "forward_ports": (self.add_forward_port, self.remove_forward_port),
            "interfaces": (self.add_interface, self.remove_interface),
            "sources": (self.add_source, self.remove_source),
            "rules_str": (add_rule_wrapper, remove_rule_wrapper),
            "protocols": (self.add_protocol, self.remove_protocol),
            "source_ports": (self.add_source_port, self.remove_source_port),
            "icmp_block_inversion": (self.add_icmp_block_inversion, self.remove_icmp_block_inversion),
            "forward": (self.add_forward, self.remove_forward),
        }

        old_settings = self.get_config_with_settings_dict(zone)
        (add_settings, remove_settings) = self._fw.get_added_and_removed_settings(old_settings, settings)

        for key in remove_settings:
            if isinstance(remove_settings[key], list):
                for args in remove_settings[key]:
                    if isinstance(args, tuple):
                        setting_to_fn[key][1](zone, *args)
                    else:
                        setting_to_fn[key][1](zone, args)
            else: # bool
                setting_to_fn[key][1](zone)

        for key in add_settings:
            if isinstance(add_settings[key], list):
                for args in add_settings[key]:
                    if key in ["interfaces", "sources"]:
                        # no timeout arg
                        setting_to_fn[key][0](zone, args, sender=sender)
                    else:
                        if isinstance(args, tuple):
                            setting_to_fn[key][0](zone, *args, timeout=0, sender=sender)
                        else:
                            setting_to_fn[key][0](zone, args, timeout=0, sender=sender)
            else: # bool
                if key in ["icmp_block_inversion"]:
                    # no timeout arg
                    setting_to_fn[key][0](zone, sender=sender)
                else:
                    setting_to_fn[key][0](zone, timeout=0, sender=sender)

    # INTERFACES

    def check_interface(self, interface):
        self._fw.check_interface(interface)

    def interface_get_sender(self, zone, interface):
        _zone = self._fw.check_zone(zone)
        _obj = self._zones[_zone]
        interface_id = self.__interface_id(interface)

        if interface_id in _obj.settings["interfaces"]:
            settings = _obj.settings["interfaces"][interface_id]
            if "sender" in settings and settings["sender"] is not None:
                return settings["sender"]

        return None

    def __interface_id(self, interface):
        self.check_interface(interface)
        return interface

    def add_interface(self, zone, interface, sender=None,
                      use_transaction=None, allow_apply=True):
        self._fw.check_panic()
        _zone = self._fw.check_zone(zone)
        _obj = self._zones[_zone]

        interface_id = self.__interface_id(interface)

        if interface_id in _obj.settings["interfaces"]:
            raise FirewallError(errors.ZONE_ALREADY_SET,
                                "'%s' already bound to '%s'" % (interface,
                                                                zone))
        if self.get_zone_of_interface(interface) is not None:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "'%s' already bound to a zone" % interface)

        log.debug1("Setting zone of interface '%s' to '%s'" % (interface,
                                                               _zone))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if not _obj.applied and allow_apply:
            self.apply_zone_settings(zone,
                                     use_transaction=transaction)
            transaction.add_fail(self.set_zone_applied, _zone, False)

        if allow_apply:
            self._interface(True, _zone, interface, transaction)

        self.__register_interface(_obj, interface_id, zone, sender)
        transaction.add_fail(self.__unregister_interface, _obj,
                                  interface_id)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __register_interface(self, _obj, interface_id, zone, sender):
        _obj.settings["interfaces"][interface_id] = \
            self.__gen_settings(0, sender)
        # add information whether we add to default or specific zone
        _obj.settings["interfaces"][interface_id]["__default__"] = \
            (not zone or zone == "")

    def change_zone_of_interface(self, zone, interface, sender=None):
        self._fw.check_panic()
        _old_zone = self.get_zone_of_interface(interface)
        _new_zone = self._fw.check_zone(zone)

        if _new_zone == _old_zone:
            return _old_zone

        if _old_zone is not None:
            self.remove_interface(_old_zone, interface)

        _zone = self.add_interface(zone, interface, sender)

        return _zone

    def change_default_zone(self, old_zone, new_zone, use_transaction=None):
        self._fw.check_panic()

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        self.apply_zone_settings(new_zone, transaction)
        self._interface(True, new_zone, "+", transaction, append=True)
        if old_zone is not None and old_zone != "":
            self._interface(False, old_zone, "+", transaction, append=True)

        if use_transaction is None:
            transaction.execute(True)

    def remove_interface(self, zone, interface,
                         use_transaction=None):
        self._fw.check_panic()
        zoi = self.get_zone_of_interface(interface)
        if zoi is None:
            raise FirewallError(errors.UNKNOWN_INTERFACE,
                                "'%s' is not in any zone" % interface)
        _zone = zoi if zone == "" else self._fw.check_zone(zone)
        if zoi != _zone:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "remove_interface(%s, %s): zoi='%s'" % \
                                (zone, interface, zoi))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        _obj = self._zones[_zone]
        interface_id = self.__interface_id(interface)
        transaction.add_post(self.__unregister_interface, _obj, interface_id)
        self._interface(False, _zone, interface, transaction)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __unregister_interface(self, _obj, interface_id):
        if interface_id in _obj.settings["interfaces"]:
            del _obj.settings["interfaces"][interface_id]

    def query_interface(self, zone, interface):
        return self.__interface_id(interface) in self.get_settings(zone)["interfaces"]

    def list_interfaces(self, zone):
        return self.get_settings(zone)["interfaces"].keys()

    # SOURCES

    def check_source(self, source, applied=False):
        if checkIPnMask(source):
            return "ipv4"
        elif checkIP6nMask(source):
            return "ipv6"
        elif check_mac(source):
            return ""
        elif source.startswith("ipset:"):
            self._check_ipset_type_for_source(source[6:])
            if applied:
                self._check_ipset_applied(source[6:])
            return self._ipset_family(source[6:])
        else:
            raise FirewallError(errors.INVALID_ADDR, source)

    def __source_id(self, source, applied=False):
        ipv = self.check_source(source, applied=applied)
        return (ipv, source)

    def add_source(self, zone, source, sender=None, use_transaction=None,
                   allow_apply=True):
        self._fw.check_panic()
        _zone = self._fw.check_zone(zone)
        _obj = self._zones[_zone]

        if check_mac(source):
            source = source.upper()

        source_id = self.__source_id(source, applied=allow_apply)

        if source_id in _obj.settings["sources"]:
            raise FirewallError(errors.ZONE_ALREADY_SET,
                            "'%s' already bound to '%s'" % (source, _zone))
        if self.get_zone_of_source(source) is not None:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "'%s' already bound to a zone" % source)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if not _obj.applied and allow_apply:
            self.apply_zone_settings(zone,
                                     use_transaction=transaction)
            transaction.add_fail(self.set_zone_applied, _zone, False)

        if allow_apply:
            self._source(True, _zone, source_id[0], source_id[1], transaction)

        self.__register_source(_obj, source_id, zone, sender)
        transaction.add_fail(self.__unregister_source, _obj, source_id)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __register_source(self, _obj, source_id, zone, sender):
        _obj.settings["sources"][source_id] = \
            self.__gen_settings(0, sender)
        # add information whether we add to default or specific zone
        _obj.settings["sources"][source_id]["__default__"] = (not zone or zone == "")

    def change_zone_of_source(self, zone, source, sender=None):
        self._fw.check_panic()
        _old_zone = self.get_zone_of_source(source)
        _new_zone = self._fw.check_zone(zone)

        if _new_zone == _old_zone:
            return _old_zone

        if check_mac(source):
            source = source.upper()

        if _old_zone is not None:
            self.remove_source(_old_zone, source)

        _zone = self.add_source(zone, source, sender)

        return _zone

    def remove_source(self, zone, source,
                      use_transaction=None):
        self._fw.check_panic()
        if check_mac(source):
            source = source.upper()
        zos = self.get_zone_of_source(source)
        if zos is None:
            raise FirewallError(errors.UNKNOWN_SOURCE,
                                "'%s' is not in any zone" % source)
        _zone = zos if zone == "" else self._fw.check_zone(zone)
        if zos != _zone:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "remove_source(%s, %s): zos='%s'" % \
                                (zone, source, zos))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        _obj = self._zones[_zone]
        source_id = self.__source_id(source)
        transaction.add_post(self.__unregister_source, _obj, source_id)
        self._source(False, _zone, source_id[0], source_id[1], transaction)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __unregister_source(self, _obj, source_id):
        if source_id in _obj.settings["sources"]:
            del _obj.settings["sources"][source_id]

    def query_source(self, zone, source):
        if check_mac(source):
            source = source.upper()
        return self.__source_id(source) in self.get_settings(zone)["sources"]

    def list_sources(self, zone):
        return [ k[1] for k in self.get_settings(zone)["sources"].keys() ]

    def _interface(self, enable, zone, interface, transaction, append=False):
        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue
            for policy in self._zone_policies[zone]:
                for (table, chain) in self._fw.policy._get_table_chains_for_zone_dispatch(policy):
                    rules = backend.build_zone_source_interface_rules(enable,
                                    zone, policy, interface, table, chain, append)
                    transaction.add_rules(backend, rules)

            # intra zone forward
            policy = self.policy_name_from_zones(zone, "ANY")
            # Skip adding wildcard/catch-all interface (for default
            # zone). Otherwise it would allow forwarding from interface
            # in default zone -> interface not in default zone (but in
            # a different zone).
            if self.get_settings(zone)["forward"] and interface not in ["+", "*"]:
                rules = backend.build_zone_forward_rules(enable, zone, policy, "filter", interface=interface)
                transaction.add_rules(backend, rules)

        # update policy dispatch for any policy using this zone in ingress
        # or egress
        for policy in self._fw.policy.get_policies_not_derived_from_zone():
            if zone not in self._fw.policy.list_ingress_zones(policy) and \
               zone not in self._fw.policy.list_egress_zones(policy):
                continue
            if policy in self._fw.policy.get_active_policies_not_derived_from_zone() and self._fw.policy.get_policy(policy).applied:
                # first remove the old set of interfaces using the current zone
                # settings.
                if not enable and len(self.list_interfaces(zone)) == 1:
                    self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction)
                else:
                    self._fw.policy._ingress_egress_zones(False, policy, transaction)
                    # after the transaction ends and therefore the interface
                    # has been added to the zone's settings, update the
                    # dependent policies
                    transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \
                                                   self._fw.policy._ingress_egress_zones_transaction(True, p), policy)
            elif enable:
                transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \
                                               self._fw.policy.apply_policy_settings(p), policy)

    # IPSETS

    def _ipset_family(self, name):
        if self._ipset_type(name) == "hash:mac":
            return None
        return self._fw.ipset.get_family(name, applied=False)

    def _ipset_type(self, name):
        return self._fw.ipset.get_type(name, applied=False)

    def _ipset_match_flags(self, name, flag):
        return ",".join([flag] * self._fw.ipset.get_dimension(name))

    def _check_ipset_applied(self, name):
        return self._fw.ipset.check_applied(name)

    def _check_ipset_type_for_source(self, name):
        _type = self._ipset_type(name)
        if _type not in SOURCE_IPSET_TYPES:
            raise FirewallError(
                errors.INVALID_IPSET,
                "ipset '%s' with type '%s' not usable as source" % \
                (name, _type))

    def _source(self, enable, zone, ipv, source, transaction):
        # For mac source bindings ipv is an empty string, the mac source will
        # be added for ipv4 and ipv6
        for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends():
            if not backend.policies_supported:
                continue
            for policy in self._zone_policies[zone]:
                for (table, chain) in self._fw.policy._get_table_chains_for_zone_dispatch(policy):
                    rules = backend.build_zone_source_address_rules(enable, zone,
                                            policy, source, table, chain)
                    transaction.add_rules(backend, rules)

            # intra zone forward
            policy = self.policy_name_from_zones(zone, "ANY")
            if self.get_settings(zone)["forward"]:
                rules = backend.build_zone_forward_rules(enable, zone, policy, "filter", source=source)
                transaction.add_rules(backend, rules)

        # update policy dispatch for any policy using this zone in ingress
        # or egress
        for policy in self._fw.policy.get_policies_not_derived_from_zone():
            if zone not in self._fw.policy.list_ingress_zones(policy) and \
               zone not in self._fw.policy.list_egress_zones(policy):
                continue
            if policy in self._fw.policy.get_active_policies_not_derived_from_zone() and self._fw.policy.get_policy(policy).applied:
                # first remove the old set of sources using the current zone
                # settings.
                if not enable and len(self.list_sources(zone)) == 1:
                    self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction)
                else:
                    self._fw.policy._ingress_egress_zones(False, policy, transaction)
                    # after the transaction ends and therefore the sources
                    # has been added to the zone's settings, update the
                    # dependent policies
                    transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \
                                                   self._fw.policy._ingress_egress_zones_transaction(True, p), policy)
            elif enable:
                transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \
                                               self._fw.policy.apply_policy_settings(p), policy)

    def add_service(self, zone, service, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_service(p_name, service, timeout, sender)
        return zone

    def remove_service(self, zone, service):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_service(p_name, service)
        return zone

    def query_service(self, zone, service):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_service(p_name, service)

    def list_services(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_services(p_name)

    def add_port(self, zone, port, protocol, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_port(p_name, port, protocol, timeout, sender)
        return zone

    def remove_port(self, zone, port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_port(p_name, port, protocol)
        return zone

    def query_port(self, zone, port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_port(p_name, port, protocol)

    def list_ports(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_ports(p_name)

    def add_source_port(self, zone, source_port, protocol, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_source_port(p_name, source_port, protocol, timeout, sender)
        return zone

    def remove_source_port(self, zone, source_port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_source_port(p_name, source_port, protocol)
        return zone

    def query_source_port(self, zone, source_port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_source_port(p_name, source_port, protocol)

    def list_source_ports(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_source_ports(p_name)

    def _rich_rule_to_policies(self, zone, rule):
        zone = self._fw.check_zone(zone)
        if type(rule.action) == Rich_Mark:
            return [self.policy_name_from_zones(zone, "ANY")]
        elif type(rule.element) in [Rich_Service, Rich_Port, Rich_Protocol,
                                    Rich_SourcePort]:
            return [self.policy_name_from_zones(zone, "HOST")]
        elif type(rule.element) in [Rich_IcmpBlock, Rich_IcmpType]:
            return [self.policy_name_from_zones(zone, "HOST"),
                    self.policy_name_from_zones(zone, "ANY")]
        elif type(rule.element) in [Rich_ForwardPort]:
            return [self.policy_name_from_zones(zone, "ANY")]
        elif type(rule.element) in [Rich_Masquerade]:
            return [self.policy_name_from_zones("ANY", zone)]
        elif rule.element is None:
            return [self.policy_name_from_zones(zone, "HOST")]
        else:
            raise FirewallError("Rich rule type (%s) not handled." % (type(rule.element)))

    def add_rule(self, zone, rule, timeout=0, sender=None):
        for p_name in self._rich_rule_to_policies(zone, rule):
            self._fw.policy.add_rule(p_name, rule, timeout, sender)
        return zone

    def remove_rule(self, zone, rule):
        for p_name in self._rich_rule_to_policies(zone, rule):
            self._fw.policy.remove_rule(p_name, rule)
        return zone

    def query_rule(self, zone, rule):
        ret = True
        for p_name in self._rich_rule_to_policies(zone, rule):
            ret = ret and self._fw.policy.query_rule(p_name, rule)
        return ret

    def list_rules(self, zone):
        zone = self._fw.check_zone(zone)
        ret = set()
        for p_name in [self.policy_name_from_zones(zone, "ANY"),
                       self.policy_name_from_zones(zone, "HOST"),
                       self.policy_name_from_zones("ANY", zone)]:
            ret.update(set(self._fw.policy.list_rules(p_name)))
        return list(ret)

    def add_protocol(self, zone, protocol, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_protocol(p_name, protocol, timeout, sender)
        return zone

    def remove_protocol(self, zone, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_protocol(p_name, protocol)
        return zone

    def query_protocol(self, zone, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_protocol(p_name, protocol)

    def list_protocols(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_protocols(p_name)

    def add_masquerade(self, zone, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones("ANY", zone)
        self._fw.policy.add_masquerade(p_name, timeout, sender)
        return zone

    def remove_masquerade(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones("ANY", zone)
        self._fw.policy.remove_masquerade(p_name)
        return zone

    def query_masquerade(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones("ANY", zone)
        return self._fw.policy.query_masquerade(p_name)

    def add_forward_port(self, zone, port, protocol, toport=None,
                         toaddr=None, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.add_forward_port(p_name, port, protocol, toport, toaddr,
                                         timeout, sender)
        return zone

    def remove_forward_port(self, zone, port, protocol, toport=None,
                            toaddr=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.remove_forward_port(p_name, port, protocol, toport, toaddr)
        return zone

    def query_forward_port(self, zone, port, protocol, toport=None,
                           toaddr=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        return self._fw.policy.query_forward_port(p_name, port, protocol, toport,
                                                  toaddr)

    def list_forward_ports(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        return self._fw.policy.list_forward_ports(p_name)

    def add_icmp_block(self, zone, icmp, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_icmp_block(p_name, icmp, timeout, sender)

        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.add_icmp_block(p_name, icmp, timeout, sender)
        return zone

    def remove_icmp_block(self, zone, icmp):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_icmp_block(p_name, icmp)

        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.remove_icmp_block(p_name, icmp)
        return zone

    def query_icmp_block(self, zone, icmp):
        zone = self._fw.check_zone(zone)
        p_name_host = self.policy_name_from_zones(zone, "HOST")
        p_name_fwd = self.policy_name_from_zones(zone, "ANY")
        return self._fw.policy.query_icmp_block(p_name_host, icmp) and \
               self._fw.policy.query_icmp_block(p_name_fwd, icmp)

    def list_icmp_blocks(self, zone):
        zone = self._fw.check_zone(zone)
        p_name_host = self.policy_name_from_zones(zone, "HOST")
        p_name_fwd = self.policy_name_from_zones(zone, "ANY")
        return sorted(set(self._fw.policy.list_icmp_blocks(p_name_host) +
                          self._fw.policy.list_icmp_blocks(p_name_fwd)))

    def add_icmp_block_inversion(self, zone, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_icmp_block_inversion(p_name, sender)

        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.add_icmp_block_inversion(p_name, sender)
        return zone

    def _icmp_block_inversion(self, enable, zone, transaction):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy._icmp_block_inversion(enable, p_name, transaction)

        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy._icmp_block_inversion(enable, p_name, transaction)

    def remove_icmp_block_inversion(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_icmp_block_inversion(p_name)

        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.remove_icmp_block_inversion(p_name)
        return zone

    def query_icmp_block_inversion(self, zone):
        zone = self._fw.check_zone(zone)
        p_name_host = self.policy_name_from_zones(zone, "HOST")
        p_name_fwd = self.policy_name_from_zones(zone, "ANY")
        return self._fw.policy.query_icmp_block_inversion(p_name_host) and \
               self._fw.policy.query_icmp_block_inversion(p_name_fwd)

    def _forward(self, enable, zone, transaction):
        p_name = self.policy_name_from_zones(zone, "ANY")

        for interface in self._zones[zone].settings["interfaces"]:
            for backend in self._fw.enabled_backends():
                if not backend.policies_supported:
                    continue
                rules = backend.build_zone_forward_rules(enable, zone, p_name, "filter", interface=interface)
                transaction.add_rules(backend, rules)

        for ipv,source in self._zones[zone].settings["sources"]:
            for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends():
                if not backend.policies_supported:
                    continue
                rules = backend.build_zone_forward_rules(enable, zone, p_name, "filter", source=source)
                transaction.add_rules(backend, rules)

    def __forward_id(self):
        return True

    def add_forward(self, zone, timeout=0, sender=None,
                    use_transaction=None):
        _zone = self._fw.check_zone(zone)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._zones[_zone]

        forward_id = self.__forward_id()
        if forward_id in _obj.settings["forward"]:
            raise FirewallError(errors.ALREADY_ENABLED,
                                "forward already enabled in '%s'" % _zone)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._forward(True, _zone, transaction)

        self.__register_forward(_obj, forward_id, timeout, sender)
        transaction.add_fail(self.__unregister_forward, _obj, forward_id)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __register_forward(self, _obj, forward_id, timeout, sender):
        _obj.settings["forward"][forward_id] = \
            self.__gen_settings(timeout, sender)

    def remove_forward(self, zone, use_transaction=None):
        _zone = self._fw.check_zone(zone)
        self._fw.check_panic()
        _obj = self._zones[_zone]

        forward_id = self.__forward_id()
        if forward_id not in _obj.settings["forward"]:
            raise FirewallError(errors.NOT_ENABLED,
                                "forward not enabled in '%s'" % _zone)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._forward(False, _zone, transaction)

        transaction.add_post(self.__unregister_forward, _obj, forward_id)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __unregister_forward(self, _obj, forward_id):
        if forward_id in _obj.settings["forward"]:
            del _obj.settings["forward"][forward_id]

    def query_forward(self, zone):
        return self.__forward_id() in self.get_settings(zone)["forward"]
fw_ifcfg.py000064400000005002151731527160006675 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2010-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""Functions to search for and change ifcfg files"""

__all__ = [ "search_ifcfg_of_interface", "ifcfg_set_zone_of_interface" ]

import os
import os.path

from firewall import config
from firewall.core.logger import log
from firewall.core.io.ifcfg import ifcfg

def search_ifcfg_of_interface(interface):
    """search ifcfg file for the interface in config.IFCFGDIR"""

    # Return quickly if config.IFCFGDIR does not exist
    if not os.path.exists(config.IFCFGDIR):
        return None

    for filename in sorted(os.listdir(config.IFCFGDIR)):
        if not filename.startswith("ifcfg-"):
            continue
        for ignored in [ ".bak", ".orig", ".rpmnew", ".rpmorig", ".rpmsave",
                         "-range" ]:
            if filename.endswith(ignored):
                continue
        if "." in filename:
            continue
        ifcfg_file = ifcfg("%s/%s" % (config.IFCFGDIR, filename))
        ifcfg_file.read()
        if ifcfg_file.get("DEVICE") == interface:
            return ifcfg_file

    # Wasn't found above, so assume filename matches the device we want
    filename = "%s/ifcfg-%s" % (config.IFCFGDIR, interface)
    if os.path.exists(filename):
        ifcfg_file = ifcfg(filename)
        ifcfg_file.read()
        return ifcfg_file

    return None

def ifcfg_set_zone_of_interface(zone, interface):
    """Set zone (ZONE=<zone>) in the ifcfg file that uses the interface
    (DEVICE=<interface>)"""

    if zone is None:
        zone = ""

    ifcfg_file = search_ifcfg_of_interface(interface)
    if ifcfg_file is not None and ifcfg_file.get("ZONE") != zone and not \
       (ifcfg_file.get("ZONE") is None and zone == ""):
        log.debug1("Setting ZONE=%s in '%s'" % (zone, ifcfg_file.filename))
        ifcfg_file.set("ZONE", zone)
        ifcfg_file.write()
ipset.py000064400000031161151731527160006254 0ustar00# -*- coding: utf-8 -*-
#
# Copyright (C) 2015-2016 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""The ipset command wrapper"""

__all__ = [ "ipset", "check_ipset_name", "remove_default_create_options" ]

import os.path
import ipaddress

from firewall import errors
from firewall.errors import FirewallError
from firewall.core.prog import runProg
from firewall.core.logger import log
from firewall.functions import tempFile, readfile
from firewall.config import COMMANDS

IPSET_MAXNAMELEN = 32
IPSET_TYPES = [
    # bitmap and set types are currently not supported
    # "bitmap:ip",
    # "bitmap:ip,mac",
    # "bitmap:port",
    # "list:set",

    "hash:ip",
    "hash:ip,port",
    "hash:ip,port,ip",
    "hash:ip,port,net",
    "hash:ip,mark",

    "hash:net",
    "hash:net,net",
    "hash:net,port",
    "hash:net,port,net",
    "hash:net,iface",

    "hash:mac",
]
IPSET_CREATE_OPTIONS = {
    "family": "inet|inet6",
    "hashsize": "value",
    "maxelem": "value",
    "timeout": "value in secs",
    #"counters": None,
    #"comment": None,
}
IPSET_DEFAULT_CREATE_OPTIONS = {
    "family": "inet",
    "hashsize": "1024",
    "maxelem": "65536",
}

class ipset(object):
    """ipset command wrapper class"""

    def __init__(self):
        self._command = COMMANDS["ipset"]
        self.name = "ipset"

    def __run(self, args):
        """Call ipset with args"""
        # convert to string list
        _args = ["%s" % item for item in args]
        log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args))
        (status, ret) = runProg(self._command, _args)
        if status != 0:
            raise ValueError("'%s %s' failed: %s" % (self._command,
                                                     " ".join(_args), ret))
        return ret

    def check_name(self, name):
        """Check ipset name"""
        if len(name) > IPSET_MAXNAMELEN:
            raise FirewallError(errors.INVALID_NAME,
                                "ipset name '%s' is not valid" % name)

    def set_supported_types(self):
        """Return types that are supported by the ipset command and kernel"""
        ret = [ ]
        output = ""
        try:
            output = self.__run(["--help"])
        except ValueError as ex:
            log.debug1("ipset error: %s" % ex)
        lines = output.splitlines()

        in_types = False
        for line in lines:
            #print(line)
            if in_types:
                splits = line.strip().split(None, 2)
                if splits[0] not in ret and splits[0] in IPSET_TYPES:
                    ret.append(splits[0])
            if line.startswith("Supported set types:"):
                in_types = True
        return ret

    def check_type(self, type_name):
        """Check ipset type"""
        if len(type_name) > IPSET_MAXNAMELEN or type_name not in IPSET_TYPES:
            raise FirewallError(errors.INVALID_TYPE,
                                "ipset type name '%s' is not valid" % type_name)

    def set_create(self, set_name, type_name, options=None):
        """Create an ipset with name, type and options"""
        self.check_name(set_name)
        self.check_type(type_name)

        args = [ "create", set_name, type_name ]
        if isinstance(options, dict):
            for key, val in options.items():
                args.append(key)
                if val != "":
                    args.append(val)
        return self.__run(args)

    def set_destroy(self, set_name):
        self.check_name(set_name)
        return self.__run([ "destroy", set_name ])

    def set_add(self, set_name, entry):
        args = [ "add", set_name, entry ]
        return self.__run(args)

    def set_delete(self, set_name, entry):
        args = [ "del", set_name, entry ]
        return self.__run(args)

    def test(self, set_name, entry, options=None):
        args = [ "test", set_name, entry ]
        if options:
            args.append("%s" % " ".join(options))
        return self.__run(args)

    def set_list(self, set_name=None, options=None):
        args = [ "list" ]
        if set_name:
            args.append(set_name)
        if options:
            args.extend(options)
        return self.__run(args).split("\n")

    def set_get_active_terse(self):
        """ Get active ipsets (only headers) """
        lines = self.set_list(options=["-terse"])

        ret = { }
        _name = _type = None
        _options = { }
        for line in lines:
            if len(line) < 1:
                continue
            pair = [ x.strip() for x in line.split(":", 1) ]
            if len(pair) != 2:
                continue
            elif pair[0] == "Name":
                _name = pair[1]
            elif pair[0] == "Type":
                _type = pair[1]
            elif pair[0] == "Header":
                splits = pair[1].split()
                i = 0
                while i < len(splits):
                    opt = splits[i]
                    if opt in [ "family", "hashsize", "maxelem", "timeout",
                                "netmask" ]:
                        if len(splits) > i:
                            i += 1
                            _options[opt] = splits[i]
                        else:
                            log.error("Malformed ipset list -terse output: %s",
                                      line)
                            return { }
                    i += 1
                if _name and _type:
                    ret[_name] = (_type,
                                  remove_default_create_options(_options))
                _name = _type = None
                _options.clear()
        return ret

    def save(self, set_name=None):
        args = [ "save" ]
        if set_name:
            args.append(set_name)
        return self.__run(args)

    def set_restore(self, set_name, type_name, entries,
                create_options=None, entry_options=None):
        self.check_name(set_name)
        self.check_type(type_name)

        temp_file = tempFile()

        if ' ' in set_name:
            set_name = "'%s'" % set_name
        args = [ "create", set_name, type_name, "-exist" ]
        if create_options:
            for key, val in create_options.items():
                args.append(key)
                if val != "":
                    args.append(val)
        temp_file.write("%s\n" % " ".join(args))
        temp_file.write("flush %s\n" % set_name)

        for entry in entries:
            if ' ' in entry:
                entry = "'%s'" % entry
            if entry_options:
                temp_file.write("add %s %s %s\n" % \
                                (set_name, entry, " ".join(entry_options)))
            else:
                temp_file.write("add %s %s\n" % (set_name, entry))
        temp_file.close()

        stat = os.stat(temp_file.name)
        log.debug2("%s: %s restore %s", self.__class__, self._command,
                   "%s: %d" % (temp_file.name, stat.st_size))

        args = [ "restore" ]
        (status, ret) = runProg(self._command, args,
                                stdin=temp_file.name)

        if log.getDebugLogLevel() > 2:
            try:
                readfile(temp_file.name)
            except Exception:
                pass
            else:
                i = 1
                for line in readfile(temp_file.name):
                    log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0)
                    if not line.endswith("\n"):
                        log.debug3("", nofmt=1)
                    i += 1

        os.unlink(temp_file.name)

        if status != 0:
            raise ValueError("'%s %s' failed: %s" % (self._command,
                                                     " ".join(args), ret))
        return ret

    def set_flush(self, set_name):
        args = [ "flush" ]
        if set_name:
            args.append(set_name)
        return self.__run(args)

    def rename(self, old_set_name, new_set_name):
        return self.__run([ "rename", old_set_name, new_set_name ])

    def swap(self, set_name_1, set_name_2):
        return self.__run([ "swap", set_name_1, set_name_2 ])

    def version(self):
        return self.__run([ "version" ])


def check_ipset_name(name):
    """Return true if ipset name is valid"""
    if len(name) > IPSET_MAXNAMELEN:
        return False
    return True

def remove_default_create_options(options):
    """ Return only non default create options """
    _options = options.copy()
    for opt in IPSET_DEFAULT_CREATE_OPTIONS:
        if opt in _options and \
           IPSET_DEFAULT_CREATE_OPTIONS[opt] == _options[opt]:
            del _options[opt]
    return _options

def normalize_ipset_entry(entry):
    """ Normalize IP addresses in entry """
    _entry = []
    for _part in entry.split(","):
        try:
            _part.index("/")
            _entry.append(str(ipaddress.ip_network(_part, strict=False)))
        except ValueError:
            _entry.append(_part)

    return ",".join(_entry)

def check_entry_overlaps_existing(entry, entries):
    """ Check if entry overlaps any entry in the list of entries """
    # Only check simple types
    if len(entry.split(",")) > 1:
        return

    try:
        entry_network = ipaddress.ip_network(entry, strict=False)
    except ValueError:
        # could not parse the new IP address, maybe a MAC
        return

    for itr in entries:
        if entry_network.overlaps(ipaddress.ip_network(itr, strict=False)):
            raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps with existing entry '{}'".format(entry, itr))

def check_for_overlapping_entries(entries):
    """ Check if any entry overlaps any entry in the list of entries """
    try:
        entries = [ipaddress.ip_network(x, strict=False) for x in entries]
    except ValueError:
        # at least one entry can not be parsed
        return

    if len(entries) == 0:
        return

    # We can take advantage of some facts of IPv4Network/IPv6Network and
    # how Python sorts the networks to quickly detect overlaps.
    #
    # Facts:
    #
    #   1. IPv{4,6}Network are normalized to remove host bits, e.g.
    #     10.1.1.0/16 will become 10.1.0.0/16.
    #
    #   2. IPv{4,6}Network objects are sorted by:
    #     a. IP address (network bits)
    #   then
    #     b. netmask (significant bits count)
    #
    # Because of the above we have these properties:
    #
    #   1. big networks (netA) are sorted before smaller networks (netB)
    #      that overlap the big network (netA)
    #     - e.g. 10.1.128.0/17 (netA) sorts before 10.1.129.0/24 (netB)
    #   2. same value addresses (network bits) are grouped together even
    #      if the number of network bits vary. e.g. /16 vs /24
    #     - recall that address are normalized to remove host bits
    #     - e.g. 10.1.128.0/17 (netA) sorts before 10.1.128.0/24 (netC)
    #   3. non-overlapping networks (netD, netE) are always sorted before or
    #      after networks that overlap (netB, netC) the current one (netA)
    #     - e.g. 10.1.128.0/17 (netA) sorts before 10.2.128.0/16 (netD)
    #     - e.g. 10.1.128.0/17 (netA) sorts after 9.1.128.0/17 (netE)
    #     - e.g. 9.1.128.0/17 (netE) sorts before 10.1.129.0/24 (netB)
    #
    # With this we know the sorted list looks like:
    #
    #   list: [ netE, netA, netB, netC, netD ]
    #
    #   netE = non-overlapping network
    #   netA = big network
    #   netB = smaller network that overlaps netA (subnet)
    #   netC = smaller network that overlaps netA (subnet)
    #   netD = non-overlapping network
    #
    #   If networks netB and netC exist in the list, they overlap and are
    #   adjacent to netA.
    #
    # Checking for overlaps on a sorted list is thus:
    #
    #   1. compare adjacent elements in the list for overlaps
    #
    # Recall that we only need to detect a single overlap. We do not need to
    # detect them all.
    #
    entries.sort()
    prev_network = entries.pop(0)
    for current_network in entries:
        if prev_network.overlaps(current_network):
            raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps entry '{}'".format(prev_network, current_network))
        prev_network = current_network