ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/SuSEFirewallExpertRules.ycp

/**
 * Copyright 2004, Novell, Inc.  All rights reserved.
 *
 * File:	modules/SuSEFirewallExpertRules.ycp
 * Package:	SuSEFirewall configuration
 * Summary:	Interface manipulation of /etc/sysconfig/SuSEFirewall (expert rules)
 * Authors:	Lukas Ocilka <locilka@suse.cz>
 * Flags:	Unstable
 *
 * $id$
 *
 * Module for handling SuSEfirewall2 Expert Rules.
 */

{
    module "SuSEFirewallExpertRules";
    textdomain "base";

    import "SuSEFirewall";
    import "Netmask";
    import "IP";

    /***
     * Firewall Expert Rulezz
     *
     * ATTENTION: You have to call SuSEFirewall::Read() to read the configuration
     * into the memory and call SuSEFirewall::Write() to write the configuration
     * and restart the firewall service.
     */

    /**
     * List of all possible protocols for expert rulezz.
     * _rpc_ expects RPC service name as the destination port then.
     */
    list <string> allowed_expert_protocols = ["udp", "tcp", "icmp", "all", "_rpc_"];

    /**
     * Returns list of all protocols accepted by the expert rules.
     *
     * @return	list <string> of protocols
     * @see list <string> allowed_expert_protocols
     */
    global list <string> GetAllExpertRulesProtocols () {
	return allowed_expert_protocols;
    }

    // used to identify the IPv4 in regexp
    string type_ip4 = "[0123456789]+\.[0123456789]+\.[0123456789]+\.[0123456789]+";

    /**
     * Returns whether the netmask bits are valid.
     *
     * @return boolean whether valid
     */
    boolean ValidNetmaskBits (integer netmask_bits) {
	return (netmask_bits > 1 && netmask_bits <= 32);
    }

    /**
     * Function checks the network definition used for firewall expert rules.
     *
     * @example
     * IsValidNetwork("192.168.0.1")               -> true
     * IsValidNetwork("192.168.0.355")             -> false
     * IsValidNetwork("192.168.0.0/24")            -> true
     * IsValidNetwork("192.168.0.1/32")            -> true
     * IsValidNetwork("192.168.0.1/0")             -> false
     * IsValidNetwork("192.168.0.0/255.255.0.0")   -> true
     * IsValidNetwork("192.168.0.0/255.255.333.0") -> false
     * IsValidNetwork("192.168.0.0/255.255.224.0") -> true
     * IsValidNetwork("0/0")                       -> true
     *
     * @see `man iptables`
     * @param string network
     * @return boolean if it is a valid network definition
     */
    global boolean IsValidNetwork (string network) {
	// A.B.C.D (IP)
	if (regexpmatch(network, "^" + type_ip4 + "$")) {
	    return IP::Check4(network);
	}

	// A.B.C.D/1 - A.B.C.D/32 (IP with a numeric netmask)
	else if (regexpmatch(network, "^" + type_ip4 + "/[01234567890]+$")) {
	    string part_ip   = regexpsub (network, "^(" + type_ip4 + ")/[01234567890]+$", "\\1");
	    string part_bits = regexpsub (network, "^" + type_ip4 + "(/[01234567890])+$", "\\1");
	    
	    return (IP::Check4(part_ip) && ValidNetmaskBits(tointeger(part_bits)));
	}

	// 0/0 (all)
	else if (network == "0/0") {
	    return true;
	}

	// A.B.C.D/E.F.G.H (IP with Netmask)
	else if (regexpmatch(network, "^" + type_ip4 + "/" + type_ip4 + "$")) {
	    string part_ip      = regexpsub (network, "^(" + type_ip4 + ")/" + type_ip4 + "$", "\\1");
	    string part_netmask = regexpsub (network, "^" + type_ip4 + "/(" + type_ip4 + ")$", "\\1");
	    
	    return (IP::Check4(part_ip) && Netmask::Check4(part_netmask));
	}
	
	// The rest
	else {
	    y2warning("Unknown network type: %1", network);
	    return false;
	}
    }
    
    /**
     * Returns string of valid network definition.
     *
     * @return string describing the valid network.
     */
    global string ValidNetwork () {
	// TRANSLATORS: description of the valid network definition
	return _("A valid network definition can contain the IP,
IP/Netmask, IP/Netmask_Bits, or 0/0 for all networks.

Examples:
IP: 192.168.0.1
IP/Netmask: 192.168.0.0/255.255.255.0
IP/Netmask_Bits: 192.168.0.0/24 or 192.168.0.1/32
");
    }

    /**
     * Adjusts parameters to the acceptable representation
     *
     * @param	map <string, string> params
     * @return	map <string, string> modified params
     */
    map <string, string> AdjustParameters (map <string, string> params) {
	if (params["network"]:"" == "") {
	    y2warning("No network defined, using '0/0' instead!");
	    params["network"]  = "0/0";
	}
	if (params["protocol"]:"" == "") {
	    y2warning("No protocol defined, using 'all' instead!");
	    params["protocol"] = "all";
	}
	params["protocol"] = tolower(params["protocol"]:"");
	
	return params;
    }

    /**
     * Returns list of rules (maps) describing protocols and ports that are allowed
     * to be accessed from listed hosts. "network" and "protocol" are needed arguments,
     * "dport" and "sport" are optional. Undefined values are returned as empty strings.
     *
     * "network" is either an IP, IP/Netmask or IP/Netmask_Bits where the connection
     * originates; "protocol" defines the transport protocol; "dport" is the destination
     * port on the current host; "sport" is the source port on the client.
     *
     * Port can be port number, port name, port range. Protocol can be 'tcp', 'udp',
     * 'icmp', 'all' or '_rpc_' (dport is then a RPC service name, e.g., ypbind).
     *
     * @see IsValidNetwork()
     *
     * @struct This might return, e.g., [
     *     // All requests from 80.44.11.22 to TCP port 22
     *	   $[ "network" : "80.44.11.22",   "protocol" : "tcp", "dport" : "22",  "sport" : ""   ],
     *
     *     // All requests from network 80.44.11.0/24 to UDP port 53 originating on port 53
     *	   $[ "network" : "80.44.11.0/24", "protocol" : "udp", "dport" : "53",  "sport" : "53" ],
     *
     *     // All requests from network 0/0 (everywhere) to TCP port 443
     *	   $[ "network" : "0/0",           "protocol" : "tcp", "dport" : "443", "sport" : ""   ],
     * ]
     *
     * @param string zone
     * @return list <map <string, string> > of rules
     *
     * @example
     * GetListOfAcceptRules("EXT") -> $[]
     */
    global list <map <string, string> > GetListOfAcceptRules (string zone) {
	zone = toupper(zone);

	// Check the zone
	if (! contains(SuSEFirewall::GetKnownFirewallZones(), zone)) {
	    y2error("Unknown firewall zone: %1", zone);
	    return nil;
	}

	//
	// FW_SERVICES_ACCEPT_EXT, FW_SERVICES_ACCEPT_INT, FW_SERVICES_ACCEPT_DMZ
	// Format: space separated list of net,protocol[,dport][,sport]
	//
	list <map <string, string> > rules = maplist (
	    string one_rule,
	    splitstring(SuSEFirewall::GetAcceptExpertRules(zone), " +"),
	{
	    // comma separated
	    list <string> rule_splitted = splitstring(one_rule, ",");
	    return $[
		"network"  : rule_splitted[0]:"",
		"protocol" : rule_splitted[1]:"",
		"dport"    : rule_splitted[2]:"",
		"sport"    : rule_splitted[3]:"",
	    ];
	});
	
	// filtering out empty rules
	rules = filter (map <string, string> one_rule, rules, {
	    return ! (
		one_rule["network"]:""  == "" &&
		one_rule["protocol"]:"" == "" &&
		one_rule["dport"]:""    == "" &&
		one_rule["sport"]:""    == ""
	    );
	});
	
	return rules;
    }

    /**
     * Adds a new accept-rule. Possible keys for parameters are "network",
     * "protocol", "dport" and "sport". Needed are "network" and "protocol".
     *
     * @param string zone
     * @param map <string, string> params
     * @return boolean if successful
     *
     * @see GetListOfAcceptRules()
     * @see RemoveAcceptRule()
     *
     * @example
     * AddNewAcceptRule (
     *     "EXT",
     *     $["network":"192.168.0.1/255.255.240.0", "protocol":"tcp", "sport":"22"]
     * ) -> true
     */
    global boolean AddNewAcceptRule (string zone, map <string, string> params) {
	zone = toupper(zone);

	// Check the zone
	if (! contains(SuSEFirewall::GetKnownFirewallZones(), zone)) {
	    y2error("Unknown firewall zone: %1", zone);
	    return nil;
	}
	
	// Get all current rules
	string current_rules = SuSEFirewall::GetAcceptExpertRules(zone);
	if (current_rules == nil) {
	    y2error("Impossible to set new AcceptExpertRule for zone %1", zone);
	    return false;
	}

	// Adjusting params
	params = AdjustParameters(params);

	// Creating new record
	string new_rule = params["network"]:"" + "," + params["protocol"]:"";

	// either 'dport' or 'sport'
	if (params["dport"]:"" != "" || params["sport"]:"" != "") {
	    // 'dport' can be empty even if 'sport' is set
	    new_rule = new_rule + "," + params["dport"]:"";

	    if (params["sport"]:"" != "") {
		new_rule = new_rule + "," + params["sport"]:"";
	    }
	}

	if (new_rule == "0/0,all") {
	    y2warning("Adding rule '%1' that allows everything from all networks!", new_rule);
	}
	
	current_rules = current_rules + (size(current_rules) > 0 ? " ":"") + new_rule;
	
	return SuSEFirewall::SetAcceptExpertRules(zone, current_rules);
    }
    
    /**
     * Removes a single expert firewall rule.
     *
     * @param string zone
     * @param map <string, string> params
     * @return if successful
     *
     * @see GetListOfAcceptRules() for possible keys in map
     * @see AddNewAcceptRule()
     *
     * @example
     * RemoveAcceptRule (
     *     "EXT",
     *     $["network":"192.168.0.1/255.255.240.0", "protocol":"tcp", "sport":"22"]
     * ) -> true
     */
    global boolean RemoveAcceptRule (string zone, map <string, string> params) {
	zone = toupper(zone);

	// Check the zone
	if (! contains(SuSEFirewall::GetKnownFirewallZones(), zone)) {
	    y2error("Unknown firewall zone: %1", zone);
	    return nil;
	}

	string current_rules = SuSEFirewall::GetAcceptExpertRules(zone);
	if (current_rules == nil) {
	    y2error("Impossible remove any AcceptExpertRule for zone %1", zone);
	    return false;
	}

	// Creating record to be removed
	string remove_rule = params["network"]:"" + "," + params["protocol"]:"";
	if (params["dport"]:"" != "") remove_rule = remove_rule + "," + params["dport"]:"";
	if (params["sport"]:"" != "") remove_rule = remove_rule + "," + params["sport"]:"";

	// Filtering out the record
	list <string> current_rules_list = splitstring (current_rules, " \n");
	current_rules_list = filter (string one_rule, current_rules_list, {
	    return (one_rule != remove_rule && one_rule != "" && one_rule != ",");
	});
	current_rules = mergestring (current_rules_list, " ");
	
	return SuSEFirewall::SetAcceptExpertRules(zone, current_rules);
    }

    /**
     * Deletes Custom Rule defined by the ID of the rule.
     * The ID is an order of list returned by GetListOfAcceptRules().
     * ID starts at number 0.
     * Every time you delete some rule, the list is, of course, regenerated.
     *
     * @param string zone
     * @param integer rule_id
     * @return boolean if successful
     *
     * @example
     * 	DeleteRuleID (0) -> true
     *
     * @see GetListOfAcceptRules()
     */
    global boolean DeleteRuleID (string zone, integer rule_id) {
	// Check the zone
	if (! contains(SuSEFirewall::GetKnownFirewallZones(), zone)) {
	    y2error("Unknown firewall zone: %1", zone);
	    return nil;
	}

	string current_rules = SuSEFirewall::GetAcceptExpertRules(zone);
	if (current_rules == nil) {
	    y2error("Impossible remove any AcceptExpertRule for zone %1", zone);
	    return false;
	}

	list <string> current_rules_list = splitstring (current_rules, " \n");
	if (current_rules_list[rule_id]:nil != nil) {
	    current_rules_list = remove (current_rules_list, rule_id);
	    current_rules = mergestring (current_rules_list, " ");
	    SuSEFirewall::SetAcceptExpertRules (zone, current_rules);
	    return true;
	} else {
	    y2error ("Cannot remove %1, such entry does not exist.", rule_id);
	    return false;
	}
    }

/* EOF */
}

ACC SHELL 2018