2020# You should have received a copy of the GNU General Public License
2121# along with this program. If not, see <http://www.gnu.org/licenses/>.
2222
23- from __future__ import absolute_import , division , print_function
23+ from __future__ import absolute_import , division , print_function , unicode_literals
2424
2525__metaclass__ = type
2626
280280"""
281281
282282from ansible .module_utils .basic import AnsibleModule
283+ from ansible .module_utils .six import string_types
283284import re
284285import os
285286
287+ try :
288+ import ipaddress
289+
290+ HAS_IPADDRESS = True
291+ except ImportError :
292+ HAS_IPADDRESS = False
293+
294+ try :
295+ from firewall .functions import check_mac
296+
297+ HAS_CHECK_MAC = True
298+ except ImportError :
299+ HAS_CHECK_MAC = False
300+
301+ def check_mac (mac ):
302+ return False
303+
304+
286305try :
287306 import firewall .config
288307
315334 NM_IMPORTED = False
316335
317336
337+ # The argument to ip_interface must be a unicode string
338+ # Must be "cast" in python2, python3 does not need this
339+ def ip_interface (entry , module ):
340+ try :
341+ entry_str = unicode (entry )
342+ except NameError : # unicode is not defined in python3
343+ entry_str = entry
344+ try :
345+ return ipaddress .ip_interface (entry_str )
346+ except ValueError :
347+ module .fail_json (msg = "Invalid IP address - " + entry )
348+
349+
318350def try_get_connection_of_interface (interface ):
319351 try :
320352 return nm_get_connection_of_interface (interface )
@@ -343,6 +375,42 @@ def try_set_zone_of_interface(module, _zone, interface):
343375 return (False , False )
344376
345377
378+ # Check that all of the ipset entries are ipv4, ipv6, or mac addresses
379+ # if not, fail the module
380+ # if they are, return "ipv4", "ipv6", or "mac"
381+ def get_ipset_entries_type (ipset_entries , module ):
382+ addr_type = None
383+ is_mixed_addr_types = False
384+ for entry in ipset_entries :
385+ if check_mac (entry ):
386+ if addr_type is None :
387+ addr_type = "mac"
388+ elif addr_type != "mac" :
389+ is_mixed_addr_types = True
390+ else :
391+ if HAS_IPADDRESS :
392+ addr = ip_interface (entry , module )
393+ else :
394+ module .fail_json (msg = "No IP address library found" )
395+ if addr .version == 4 :
396+ if addr_type is None :
397+ addr_type = "ipv4"
398+ elif addr_type != "ipv4" :
399+ is_mixed_addr_types = True
400+ elif addr .version == 6 :
401+ if addr_type is None :
402+ addr_type = "ipv6"
403+ elif addr_type != "ipv6" :
404+ is_mixed_addr_types = True
405+ else :
406+ module .fail_json (msg = "Invalid IP address - " + entry )
407+ if is_mixed_addr_types :
408+ module .fail_json (
409+ msg = "Address types cannot be mixed in ipset entries - " + str (ipset_entries )
410+ )
411+ return addr_type
412+
413+
346414# Above: adapted from firewall-cmd source code
347415
348416
@@ -613,13 +681,14 @@ def set_service(
613681 else :
614682 self .module .fail_json (msg = "INVALID SERVICE - " + item )
615683
616- def _create_ipset (self , ipset , ipset_type ):
684+ def _create_ipset (self , ipset , ipset_type , ipset_options ):
617685 if not ipset_type :
618686 self .module .fail_json (msg = "ipset_type needed when creating a new ipset" )
619687
620688 fw_ipset = None
621689 fw_ipset_settings = FirewallClientIPSetSettings ()
622690 fw_ipset_settings .setType (ipset_type )
691+ fw_ipset_settings .setOptions (ipset_options )
623692 if not self .module .check_mode :
624693 self .fw .config ().addIPSet (ipset , fw_ipset_settings )
625694 fw_ipset = self .fw .config ().getIPSetByName (ipset )
@@ -628,6 +697,14 @@ def _create_ipset(self, ipset, ipset_type):
628697 return fw_ipset , fw_ipset_settings
629698
630699 def set_ipset (self , ipset , description , short , ipset_type , ipset_entries ):
700+ addr_type = get_ipset_entries_type (ipset_entries , self .module )
701+ if addr_type is None and ipset_entries :
702+ self .module .fail_json (msg = "Invalid IP address - " + str (ipset_entries ))
703+ ipset_options = {}
704+ if addr_type == "ipv6" :
705+ ipset_options = {
706+ "family" : "inet6" ,
707+ }
631708 ipset_exists = ipset in self .fw .config ().getIPSetNames ()
632709 fw_ipset = None
633710 fw_ipset_settings = None
@@ -641,7 +718,9 @@ def set_ipset(self, ipset, description, short, ipset_type, ipset_entries):
641718 % (ipset , fw_ipset_settings .getType ())
642719 )
643720 elif self .state == "present" :
644- fw_ipset , fw_ipset_settings = self ._create_ipset (ipset , ipset_type )
721+ fw_ipset , fw_ipset_settings = self ._create_ipset (
722+ ipset , ipset_type , ipset_options
723+ )
645724 self .changed = True
646725 ipset_exists = True
647726 if self .state == "present" :
@@ -1256,6 +1335,12 @@ def set_service(
12561335 self .change ("--zone" , self .zone , op + item )
12571336
12581337 def set_ipset (self , ipset , description , short , ipset_type , ipset_entries ):
1338+ addr_type = get_ipset_entries_type (ipset_entries , self .module )
1339+ if addr_type is None and ipset_entries :
1340+ self .module .fail_json (msg = "Invalid IP address - " + str (ipset_entries ))
1341+ ipset_options = []
1342+ if addr_type == "ipv6" :
1343+ ipset_options = ["--option" , "family=inet6" ]
12591344 present = self .check_state (["present" , "absent" ], "ipset" )
12601345 known_ipsets = self .cmd ("--get-ipsets" ).split ()
12611346 ipset_exists = ipset in known_ipsets
@@ -1280,7 +1365,9 @@ def set_ipset(self, ipset, description, short, ipset_type, ipset_entries):
12801365 self .module .fail_json (
12811366 msg = "ipset_type needed when creating a new ipset"
12821367 )
1283- self .change ("--new-ipset" , ipset , "--type=%s" % ipset_type )
1368+ self .change (
1369+ "--new-ipset" , ipset , "--type=%s" % ipset_type , * ipset_options
1370+ )
12841371
12851372 existing_description = self .cmd ("--ipset" , ipset , "--get-description" )
12861373 if description is not None and description != existing_description :
@@ -1635,6 +1722,10 @@ def get_forward_port(module):
16351722def parse_forward_port (module , item ):
16361723 type_string = "forward_port"
16371724
1725+ _port = None
1726+ _protocol = None
1727+ _to_port = None
1728+ _to_addr = None
16381729 if isinstance (item , dict ):
16391730 if "port" not in item :
16401731 module .fail_json (
@@ -1653,7 +1744,7 @@ def parse_forward_port(module, item):
16531744 else :
16541745 _to_port = None
16551746 _to_addr = item .get ("toaddr" )
1656- elif isinstance (item , str ):
1747+ elif isinstance (item , string_types ):
16571748 args = item .split (";" )
16581749 if len (args ) == 3 :
16591750 __port , _to_port , _to_addr = args
0 commit comments