__pycache__/__init__.cpython-36.opt-1.pyc000064400000001227147205345250014111 0ustar003 @)f<@sjddlZdejkrfddlmZeedss      __pycache__/__init__.cpython-36.pyc000064400000001227147205345250013152 0ustar003 @)f<@sjddlZdejkrfddlmZeedss      __pycache__/direct.cpython-36.opt-1.pyc000064400000027263147205345250013634 0ustar003 @)f=@sddljZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZddlmZddlmZdd lmZdd lmZGd d d eZGd ddeZdS)N)config)LastUpdatedOrderedDict) splitArgsjoinArgs u2b_if_py2) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log) ipXtables)ebtables)errors) FirewallErrorc@s$eZdZddZddZddZdS)direct_ContentHandlercCstj||d|_dS)NF)r__init__direct)selfitemr/usr/lib/python3.6/direct.pyr(s zdirect_ContentHandler.__init__c Cstj||||jj|||dkr@|jr6ttjdd|_n>|dkr|js\tj ddS|d}|d}|d}|jj t |t |t |n|dkr6|jstj d dS|d}|dkrttj d ||d}|d}yt |d}Wn(tk rtj d|ddSXt |t |t ||g|_nH|dkrl|jsVtj ddS|d}t |g|_ntj d|dSdS)NrzMore than one direct tag.Tchainz$Parse Error: chain outside of directipvtablerulez#Parse Error: rule outside of directipv4ipv6ebz"'%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 Z PARSE_ERRORr error add_chainr INVALID_IPVint ValueError_rule _passthrough)rnameZattrsrrrrrrrr,sT          z"direct_ContentHandler.startElementcCstj|||dkrX|jrF|jjddt|jD|jj|jn tj dd|_nJ|dkr|jr|j jddt|jD|jj |j n tj d d|_ dS) NrcSsg|] }t|qSr)r).0xrrr dsz4direct_ContentHandler.endElement..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%appendrradd_ruler r r&add_passthrough)rr'rrrr+^s     z direct_ContentHandler.endElementN)__name__ __module__ __qualname__rrr+rrrrr's2rcs<eZdZdZddBgfddddddgfgfdddgfgffZdZdd d d gd d d d gd gd ZiZfddZddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!Z"S)CDirectz Direct class chainsrulesr passthroughsz(a(sss)a(sssias)a(sas))Nrrrr)rrrrcs0tt|j||_t|_t|_t|_dS)N)superr2rfilenamerr3r5r6)rr8) __class__rrrs zDirect.__init__cCsdS)Nr)rconfrZall_confrrr _check_configszDirect._check_configc Csg}g}x>|jD]4}x.|j|D] }|jtt|t|gq WqW|j|g}xR|jD]H}xB|j|D]4}|jt|d|d|d|dt|dfqnWq^W|j|g}x8|jD].}x(|j|D]}|jt|t|fqWqW|j|t|S)Nr)r3r,tuplelistr5r6)rretr)keyrrrrr export_configs$ $     zDirect.export_configcCs|j|j|xt|jD]x\}\}}|dkrNx||D]}|j|qr rRrL)rrrrrrMrAvaluerrrr-s     zDirect.add_rulecCs|j|||||f}|t|f}||jkrb||j|krb|j||=t|j|dkr|j|=n$tddj|||fd||fdS)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|jD]}|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||fddS)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||fddS)NrzPassthrough '%s' for ipv '%s'z',z not in list)rOr6rSrTr$rL)rrrMrrrremove_passthroughIs  zDirect.remove_passthroughcCs"|j|||jko ||j|kS)N)rOr6)rrrMrrrquery_passthroughSs zDirect.query_passthroughcCs.|j|||jkr|j|Std|dS)NzNo passthroughs for ipv '%s')rOr6r$)rrrrrget_passthroughsWs   zDirect.get_passthroughscCs|jS)N)r6)rrrrget_all_passthroughs^szDirect.get_all_passthroughscCs|j|jjds&ttjd|jt|}tj}|j |t |jdb}tj d}|j |y|j |Wn8tjk r}zttjd|jWYdd}~XnXWdQRXdS)Nz.xmlz'%s' is missing .xml suffixrbzNot a valid file: %s)rCr8endswithrr Z INVALID_NAMErsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_TYPEZ getException)rhandlerparserfsourcemsgrrrreadcs      z Direct.readc CsBtjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdxR|jD]H}|\}}x:|j|D],}|jd |jd |||d |jdqWqWx|jD]}|\}}}xx|j|D]j\}} t| d kr@q&|jd |jd |||d|d|jtjjt| |jd |jdq&Wq Wx||jD]r}xj|j|D]\} t| d krȐq|jd |jdd|i|jtjjt| |jd|jdqWqW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z r)rrrr<rz%d)rrrrrr)ospathexistsr8shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdiriorfr Z startDocumentrZignorableWhitespacer3Z simpleElementr5rTreZsaxutilsescaperr+r6Z endDocumentclose) rrlrjrhrArrrrrMrrrwriteusZ$                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.corer r r Zfirewall.errorsrrr2rrrrs        N__pycache__/direct.cpython-36.pyc000064400000027263147205345250012675 0ustar003 @)f=@sddljZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZddlmZddlmZdd lmZdd lmZGd d d eZGd ddeZdS)N)config)LastUpdatedOrderedDict) splitArgsjoinArgs u2b_if_py2) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log) ipXtables)ebtables)errors) FirewallErrorc@s$eZdZddZddZddZdS)direct_ContentHandlercCstj||d|_dS)NF)r__init__direct)selfitemr/usr/lib/python3.6/direct.pyr(s zdirect_ContentHandler.__init__c Cstj||||jj|||dkr@|jr6ttjdd|_n>|dkr|js\tj ddS|d}|d}|d}|jj t |t |t |n|dkr6|jstj d dS|d}|dkrttj d ||d}|d}yt |d}Wn(tk rtj d|ddSXt |t |t ||g|_nH|dkrl|jsVtj ddS|d}t |g|_ntj d|dSdS)NrzMore than one direct tag.Tchainz$Parse Error: chain outside of directipvtablerulez#Parse Error: rule outside of directipv4ipv6ebz"'%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 Z PARSE_ERRORr error add_chainr INVALID_IPVint ValueError_rule _passthrough)rnameZattrsrrrrrrrr,sT          z"direct_ContentHandler.startElementcCstj|||dkrX|jrF|jjddt|jD|jj|jn tj dd|_nJ|dkr|jr|j jddt|jD|jj |j n tj d d|_ dS) NrcSsg|] }t|qSr)r).0xrrr dsz4direct_ContentHandler.endElement..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%appendrradd_ruler r r&add_passthrough)rr'rrrr+^s     z direct_ContentHandler.endElementN)__name__ __module__ __qualname__rrr+rrrrr's2rcs<eZdZdZddBgfddddddgfgfdddgfgffZdZdd d d gd d d d gd gd ZiZfddZddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!Z"S)CDirectz Direct class chainsrulesr passthroughsz(a(sss)a(sssias)a(sas))Nrrrr)rrrrcs0tt|j||_t|_t|_t|_dS)N)superr2rfilenamerr3r5r6)rr8) __class__rrrs zDirect.__init__cCsdS)Nr)rconfrZall_confrrr _check_configszDirect._check_configc Csg}g}x>|jD]4}x.|j|D] }|jtt|t|gq WqW|j|g}xR|jD]H}xB|j|D]4}|jt|d|d|d|dt|dfqnWq^W|j|g}x8|jD].}x(|j|D]}|jt|t|fqWqW|j|t|S)Nr)r3r,tuplelistr5r6)rretr)keyrrrrr export_configs$ $     zDirect.export_configcCs|j|j|xt|jD]x\}\}}|dkrNx||D]}|j|qr rRrL)rrrrrrMrAvaluerrrr-s     zDirect.add_rulecCs|j|||||f}|t|f}||jkrb||j|krb|j||=t|j|dkr|j|=n$tddj|||fd||fdS)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|jD]}|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||fddS)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||fddS)NrzPassthrough '%s' for ipv '%s'z',z not in list)rOr6rSrTr$rL)rrrMrrrremove_passthroughIs  zDirect.remove_passthroughcCs"|j|||jko ||j|kS)N)rOr6)rrrMrrrquery_passthroughSs zDirect.query_passthroughcCs.|j|||jkr|j|Std|dS)NzNo passthroughs for ipv '%s')rOr6r$)rrrrrget_passthroughsWs   zDirect.get_passthroughscCs|jS)N)r6)rrrrget_all_passthroughs^szDirect.get_all_passthroughscCs|j|jjds&ttjd|jt|}tj}|j |t |jdb}tj d}|j |y|j |Wn8tjk r}zttjd|jWYdd}~XnXWdQRXdS)Nz.xmlz'%s' is missing .xml suffixrbzNot a valid file: %s)rCr8endswithrr Z INVALID_NAMErsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_TYPEZ getException)rhandlerparserfsourcemsgrrrreadcs      z Direct.readc CsBtjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdxR|jD]H}|\}}x:|j|D],}|jd |jd |||d |jdqWqWx|jD]}|\}}}xx|j|D]j\}} t| d kr@q&|jd |jd |||d|d|jtjjt| |jd |jdq&Wq Wx||jD]r}xj|j|D]\} t| d krȐq|jd |jdd|i|jtjjt| |jd|jdqWqW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z r)rrrr<rz%d)rrrrrr)ospathexistsr8shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdiriorfr Z startDocumentrZignorableWhitespacer3Z simpleElementr5rTreZsaxutilsescaperr+r6Z endDocumentclose) rrlrjrhrArrrrrMrrrwriteusZ$                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.corer r r Zfirewall.errorsrrr2rrrrs        N__pycache__/firewalld_conf.cpython-36.opt-1.pyc000064400000016616147205345250015340 0ustar003 @)f5 @s~ddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddddd d d d d ddddg Z GdddeZdS)N)config)log)b2uu2bPY2 DefaultZone MinimalMark CleanupOnExitCleanupModulesOnExitLockdown IPv6_rpfilterIndividualCalls LogDeniedAutomaticHelpersFirewallBackendFlushAllOnReload RFC3964_IPv4AllowZoneDriftingc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)firewalld_confcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfrr$/usr/lib/python3.6/firewalld_conf.py__init__&szfirewalld_conf.__init__cCsi|_g|_dS)N)rr)rrrrr,szfirewalld_conf.clearcCs|jjg|_dS)N)rrr)rrrrcleanup0s zfirewalld_conf.cleanupcCs|jj|jS)N)rgetstrip)rkeyrrrr4szfirewalld_conf.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)rr valueZ_keyrrrset7s  zfirewalld_conf.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)rsr r"rrr__str__=s zfirewalld_conf.__str__cCs|jyt|jd}Wn8tk rR}ztjd|j||jdtj|jdt tj |jdtj rpdnd|jdtj rdnd|jd tj rdnd|jd tjrdnd|jd tjrdnd|jd tj|jd tj|jdtj|jdtjr dnd|jdtjr"dnd|jdtjr:dndWYdd}~XnXx|D]}|shP|j}t|dks\|dd.krq\dd|jdD}t|dkrtjd|jq\nr|dtkrtjd|jq\nN|ddkrtjd|jq\n*|jj|ddk r:tjd|jq\|d|j|d<q\W|j|jdstjdtj|jdt tj|jd}y t|WnPttfk r|dk rtj d |r|ndtj |jdt tj YnX|jd}| s|j!d/krJ|dk r2tj d#|r(|ndtj |jdtj rDdnd|jd}| sj|j!d0kr|dk rtj d$|r|ndtj |jdtj rdnd|jd }| s|j!d1kr|dk rtj d%|r|ndtj |jd tj rdnd|jd }| s"|j!d2kr^|dk rFtj d&|r<|ndtj|jd tjrXdnd|jd }| s~|j!d3kr|dk rtj d'|r|ndtj|jd tjrdnd|jd }| s|tj"kr|dk rtj d(|tj|jd t tj|jd }| s&|j!tj#kr\|dk rJtj d)|r@|ndtj|jd t tj|jd}| s~|j!tj$kr|dk rtj d*|r|ndtj|jdt tj|jd}| s|j!d4kr |dk rtj d+|r|ndtj|jdt tj|jd}| s*|j!d5kr`|dk rNtj d,|rD|ndtj|jdt tj|jd}| s|j!d6kr|dk rtj d-|r|ndtj|jdt tjdS)7NrzFailed to load '%s': %srrr yesnor r r r rrrrrrr#;cSsg|] }|jqSr)r).0xrrr bsz'firewalld_conf.read..=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'falsetruez7CleanupOnExit '%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)%ropenr Exceptionrerrorr#rZ FALLBACK_ZONEstrZFALLBACK_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_DRIFTINGrlensplit valid_keysrrcloseint ValueError TypeErrorZwarninglowerZLOG_DENIED_VALUESZAUTOMATIC_HELPERS_VALUESZFIREWALL_BACKEND_VALUES)rfmsglineZpairr"rrrreadFs                                       zfirewalld_conf.readc :Cst|jdkrdSg}tjjtjs2tjtjdy.tj ddtjj |j tjj |j dd}Wn2t k r}ztjd|WYdd}~XnXd}d}ytj|j dd d }WnPt k r}z0tjj|j rtjd |j |fnd}WYdd}~Xn6Xx0|D]&}|sP|jd }t|dkrH|s2|jd d }n|ddkrpd}|j||jd n|jd}t|dkrd}|j|d q |dj} |dj} | |kr.| |jkr|j| | krd}|jd| |j| fd }n$| |jkrd }nd}|j|d |j| nd }q Wt|jdkrx^|jjD]P\} } | |krjqT| dkrxqT|s|jd d }|jd| | fd }qTW|r|j|j|stj|jdStjj|j r@ytj|j d|j WnBt k r>}z$tj|jtd|j |fWYdd}~XnXytj|j|j WnBt k r}z$tj|jtd|j |fWYdd}~XnXtj|j ddS)Nr,iZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)rFencodingzFailed to open '%s': %sr%Trr-r2r3z%s=%s rrz%s.oldzBackup of '%s' failed: %szFailed to create '%s': %si)rr) r:rospathexistsrZ ETC_FIREWALLDmkdirtempfileZNamedTemporaryFilebasenamerdirnamer7rr8ior6rwriter;rappendr&r=r!nameshutilZcopy2IOErrorZmovechmod) rdoneZ temp_filerCZmodifiedemptyrBrDpr r"rrrrSs                  $ $zfirewalld_conf.writeN) __name__ __module__ __qualname__rrrrr#r(rErSrrrrr%s r)Zos.pathrKrRrOrVZfirewallrZfirewall.core.loggerrZfirewall.functionsrrrr<objectrrrrrs  __pycache__/firewalld_conf.cpython-36.pyc000064400000016616147205345250014401 0ustar003 @)f5 @s~ddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddddd d d d d ddddg Z GdddeZdS)N)config)log)b2uu2bPY2 DefaultZone MinimalMark CleanupOnExitCleanupModulesOnExitLockdown IPv6_rpfilterIndividualCalls LogDeniedAutomaticHelpersFirewallBackendFlushAllOnReload RFC3964_IPv4AllowZoneDriftingc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)firewalld_confcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfrr$/usr/lib/python3.6/firewalld_conf.py__init__&szfirewalld_conf.__init__cCsi|_g|_dS)N)rr)rrrrr,szfirewalld_conf.clearcCs|jjg|_dS)N)rrr)rrrrcleanup0s zfirewalld_conf.cleanupcCs|jj|jS)N)rgetstrip)rkeyrrrr4szfirewalld_conf.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)rr valueZ_keyrrrset7s  zfirewalld_conf.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)rsr r"rrr__str__=s zfirewalld_conf.__str__cCs|jyt|jd}Wn8tk rR}ztjd|j||jdtj|jdt tj |jdtj rpdnd|jdtj rdnd|jd tj rdnd|jd tjrdnd|jd tjrdnd|jd tj|jd tj|jdtj|jdtjr dnd|jdtjr"dnd|jdtjr:dndWYdd}~XnXx|D]}|shP|j}t|dks\|dd.krq\dd|jdD}t|dkrtjd|jq\nr|dtkrtjd|jq\nN|ddkrtjd|jq\n*|jj|ddk r:tjd|jq\|d|j|d<q\W|j|jdstjdtj|jdt tj|jd}y t|WnPttfk r|dk rtj d |r|ndtj |jdt tj YnX|jd}| s|j!d/krJ|dk r2tj d#|r(|ndtj |jdtj rDdnd|jd}| sj|j!d0kr|dk rtj d$|r|ndtj |jdtj rdnd|jd }| s|j!d1kr|dk rtj d%|r|ndtj |jd tj rdnd|jd }| s"|j!d2kr^|dk rFtj d&|r<|ndtj|jd tjrXdnd|jd }| s~|j!d3kr|dk rtj d'|r|ndtj|jd tjrdnd|jd }| s|tj"kr|dk rtj d(|tj|jd t tj|jd }| s&|j!tj#kr\|dk rJtj d)|r@|ndtj|jd t tj|jd}| s~|j!tj$kr|dk rtj d*|r|ndtj|jdt tj|jd}| s|j!d4kr |dk rtj d+|r|ndtj|jdt tj|jd}| s*|j!d5kr`|dk rNtj d,|rD|ndtj|jdt tj|jd}| s|j!d6kr|dk rtj d-|r|ndtj|jdt tjdS)7NrzFailed to load '%s': %srrr yesnor r r r rrrrrrr#;cSsg|] }|jqSr)r).0xrrr bsz'firewalld_conf.read..=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'falsetruez7CleanupOnExit '%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)%ropenr Exceptionrerrorr#rZ FALLBACK_ZONEstrZFALLBACK_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_DRIFTINGrlensplit valid_keysrrcloseint ValueError TypeErrorZwarninglowerZLOG_DENIED_VALUESZAUTOMATIC_HELPERS_VALUESZFIREWALL_BACKEND_VALUES)rfmsglineZpairr"rrrreadFs                                       zfirewalld_conf.readc :Cst|jdkrdSg}tjjtjs2tjtjdy.tj ddtjj |j tjj |j dd}Wn2t k r}ztjd|WYdd}~XnXd}d}ytj|j dd d }WnPt k r}z0tjj|j rtjd |j |fnd}WYdd}~Xn6Xx0|D]&}|sP|jd }t|dkrH|s2|jd d }n|ddkrpd}|j||jd n|jd}t|dkrd}|j|d q |dj} |dj} | |kr.| |jkr|j| | krd}|jd| |j| fd }n$| |jkrd }nd}|j|d |j| nd }q Wt|jdkrx^|jjD]P\} } | |krjqT| dkrxqT|s|jd d }|jd| | fd }qTW|r|j|j|stj|jdStjj|j r@ytj|j d|j WnBt k r>}z$tj|jtd|j |fWYdd}~XnXytj|j|j WnBt k r}z$tj|jtd|j |fWYdd}~XnXtj|j ddS)Nr,iZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)rFencodingzFailed to open '%s': %sr%Trr-r2r3z%s=%s rrz%s.oldzBackup of '%s' failed: %szFailed to create '%s': %si)rr) r:rospathexistsrZ ETC_FIREWALLDmkdirtempfileZNamedTemporaryFilebasenamerdirnamer7rr8ior6rwriter;rappendr&r=r!nameshutilZcopy2IOErrorZmovechmod) rdoneZ temp_filerCZmodifiedemptyrBrDpr r"rrrrSs                  $ $zfirewalld_conf.writeN) __name__ __module__ __qualname__rrrrr#r(rErSrrrrr%s r)Zos.pathrKrRrOrVZfirewallrZfirewall.core.loggerrZfirewall.functionsrrrr<objectrrrrrs  __pycache__/functions.cpython-36.opt-1.pyc000064400000005256147205345250014370 0ustar003 @)fy@sddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZdd lmZddZdS)N)config) FirewallError)FirewallConfig) zone_reader)service_reader) ipset_reader)icmptype_reader) helper_reader) policy_reader)Direct)LockdownWhitelist)firewalld_confc -Cs|t|}t|jtjtjgdt|jtjtj gdt |j tj tj gdt|jtjtjgdt|jtjtjgdt|jtjtjgdd}x |jD]}x||dD]}tjj|sqxttj|D]}|j dryD||d||}|d kr||_!|j"|j#||d|Wqt$k rT}zt$|j%d ||j&fWYdd}~Xqt'k r}zt'd ||fWYdd}~XqXqWqWqWtjj(tj)r:y$t*tj)}|j+|j,|j-Wnpt$k r}zt$|j%d tj)|j&fWYdd}~Xn6t'k r8}zt'd tj)|fWYdd}~XnXtjj(tj.ry$t/tj.}|j+|j,|j-Wnpt$k r}zt$|j%d tj.|j&fWYdd}~Xn6t'k r}zt'd tj.|fWYdd}~XnXtjj(tj0rxyt1tj0}|j+Wnpt$k rB}zt$|j%d tj0|j&fWYdd}~Xn6t'k rv}zt'd tj0|fWYdd}~XnXdS) N)readeradddirs)ZipsethelperZicmptypeZservicezonepolicyrz.xmlrrrrz'%s': %s)rr)2rrZ add_ipsetrZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSr Z add_helperZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSrZ add_icmptypeZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESrZ add_serviceZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESrZadd_zoneZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr Zadd_policy_objectZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESkeysospathisdirsortedlistdirendswith fw_configZcheck_config_dictZexport_config_dictrcodemsg ExceptionisfileZFIREWALLD_DIRECTr read check_configZ export_configZLOCKDOWN_WHITELISTr ZFIREWALLD_CONFr ) fwrZreadersrZ_dirfileobjerrorrr&/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.directr Z#firewall.core.io.lockdown_whitelistr Zfirewall.core.io.firewalld_confr r!r&r&r&r's            __pycache__/functions.cpython-36.pyc000064400000005256147205345250013431 0ustar003 @)fy@sddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZdd lmZddZdS)N)config) FirewallError)FirewallConfig) zone_reader)service_reader) ipset_reader)icmptype_reader) helper_reader) policy_reader)Direct)LockdownWhitelist)firewalld_confc -Cs|t|}t|jtjtjgdt|jtjtj gdt |j tj tj gdt|jtjtjgdt|jtjtjgdt|jtjtjgdd}x |jD]}x||dD]}tjj|sqxttj|D]}|j dryD||d||}|d kr||_!|j"|j#||d|Wqt$k rT}zt$|j%d ||j&fWYdd}~Xqt'k r}zt'd ||fWYdd}~XqXqWqWqWtjj(tj)r:y$t*tj)}|j+|j,|j-Wnpt$k r}zt$|j%d tj)|j&fWYdd}~Xn6t'k r8}zt'd tj)|fWYdd}~XnXtjj(tj.ry$t/tj.}|j+|j,|j-Wnpt$k r}zt$|j%d tj.|j&fWYdd}~Xn6t'k r}zt'd tj.|fWYdd}~XnXtjj(tj0rxyt1tj0}|j+Wnpt$k rB}zt$|j%d tj0|j&fWYdd}~Xn6t'k rv}zt'd tj0|fWYdd}~XnXdS) N)readeradddirs)ZipsethelperZicmptypeZservicezonepolicyrz.xmlrrrrz'%s': %s)rr)2rrZ add_ipsetrZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSr Z add_helperZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSrZ add_icmptypeZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESrZ add_serviceZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESrZadd_zoneZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr Zadd_policy_objectZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESkeysospathisdirsortedlistdirendswith fw_configZcheck_config_dictZexport_config_dictrcodemsg ExceptionisfileZFIREWALLD_DIRECTr read check_configZ export_configZLOCKDOWN_WHITELISTr ZFIREWALLD_CONFr ) fwrZreadersrZ_dirfileobjerrorrr&/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.directr Z#firewall.core.io.lockdown_whitelistr Zfirewall.core.io.firewalld_confr r!r&r&r&r's            __pycache__/helper.cpython-36.opt-1.pyc000064400000013451147205345250013633 0ustar003 @)f @sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Helper helper_reader helper_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudp)log)errors) FirewallErrorcseZdZddddddd gffZdZd d gZd d dgd Zd ddgddgdZfddZddZ ddZ ddZ ddZ Z S)!rversionshort descriptionfamilymoduleportsz (sssssa(ss))-.N)rrhelpernameportprotocol)rrcs6tt|jd|_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|fqSr!)r).0ZpoZprr!r!r" Usz)Helper.encode_strings..N)rrrrrrr)rr!r!r"encode_stringsLs      zHelper.encode_stringscCs(ddg}||kr$ttjd||fdS)NZipv4Zipv6z'%s' not in '%s')rrZ INVALID_IPV)rZipvZipvsr!r!r" check_ipvWszHelper.check_ipvcCsz|dkr0xl|D]}t|dt|dqWnF|dkrv|jdsRttjd|t|jdddkrvttjd|dS) Nrrr nf_conntrack_z('%s' does not start with 'nf_conntrack_'rzModule name '%s' too short)r r startswithrrINVALID_MODULElenreplace)rritemZ 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@seZdZddZdS)helper_ContentHandlercCs>tj||||jj|||dkrd|kr8|d|j_d|kr\|jj|d|d|j_d|kr|djdstt j d|dt |dj dddkrtt j d |d|d|j_ nz|d krnp|d krnf|d kr:t|d t|d |d |d f}||jjkr$|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-rr r rappendr Zwarning)rrattrsentryr!r!r"r5ns>      z"helper_ContentHandler.startElementN)r0r1r2r5r!r!r!r"r4msr4c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid helper file: %s)rendswithrrZ INVALID_NAMErZ check_namefilenamepathr*r ETC_FIREWALLDZbuiltindefaultr4saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_HELPERZ getExceptionrr&) r=r>rhandlerparserrfsourcemsgr!r!r"rs8        (c CsP|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|j|d <|jr|jd kr|j|d <|jr<|jd kr<|j|d <|jd ||jd|jr|jd kr|jd|jdi|j|j|jd|jd|jr|jd kr|jd|jdi|j|j|jd|jdx>|jD]4} |jd|jd| d| dd|jdqW|jd |jd|j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrrrr z rrrrr()rr) r>r=rosexistsshutilZcopy2 Exceptionr errordirnamer*rr?mkdiriorBr Z startDocumentrrrr5ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr>_pathrrHdirpathrFrDr7rr!r!r"rs\                       )N)__all__Zxml.saxrArLrSrNZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r r r Zfirewall.core.loggerr rZfirewall.errorsrrr4rrr!r!r!r"s        G#__pycache__/helper.cpython-36.pyc000064400000013451147205345250012674 0ustar003 @)f @sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Helper helper_reader helper_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudp)log)errors) FirewallErrorcseZdZddddddd gffZdZd d gZd d dgd Zd ddgddgdZfddZddZ ddZ ddZ ddZ Z S)!rversionshort descriptionfamilymoduleportsz (sssssa(ss))-.N)rrhelpernameportprotocol)rrcs6tt|jd|_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|fqSr!)r).0ZpoZprr!r!r" Usz)Helper.encode_strings..N)rrrrrrr)rr!r!r"encode_stringsLs      zHelper.encode_stringscCs(ddg}||kr$ttjd||fdS)NZipv4Zipv6z'%s' not in '%s')rrZ INVALID_IPV)rZipvZipvsr!r!r" check_ipvWszHelper.check_ipvcCsz|dkr0xl|D]}t|dt|dqWnF|dkrv|jdsRttjd|t|jdddkrvttjd|dS) Nrrr nf_conntrack_z('%s' does not start with 'nf_conntrack_'rzModule name '%s' too short)r r startswithrrINVALID_MODULElenreplace)rritemZ 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@seZdZddZdS)helper_ContentHandlercCs>tj||||jj|||dkrd|kr8|d|j_d|kr\|jj|d|d|j_d|kr|djdstt j d|dt |dj dddkrtt j d |d|d|j_ nz|d krnp|d krnf|d kr:t|d t|d |d |d f}||jjkr$|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-rr r rappendr Zwarning)rrattrsentryr!r!r"r5ns>      z"helper_ContentHandler.startElementN)r0r1r2r5r!r!r!r"r4msr4c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid helper file: %s)rendswithrrZ INVALID_NAMErZ check_namefilenamepathr*r ETC_FIREWALLDZbuiltindefaultr4saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_HELPERZ getExceptionrr&) r=r>rhandlerparserrfsourcemsgr!r!r"rs8        (c CsP|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|j|d <|jr|jd kr|j|d <|jr<|jd kr<|j|d <|jd ||jd|jr|jd kr|jd|jdi|j|j|jd|jd|jr|jd kr|jd|jdi|j|j|jd|jdx>|jD]4} |jd|jd| d| dd|jdqW|jd |jd|j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrrrr z rrrrr()rr) r>r=rosexistsshutilZcopy2 Exceptionr errordirnamer*rr?mkdiriorBr Z startDocumentrrrr5ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr>_pathrrHdirpathrFrDr7rr!r!r"rs\                       )N)__all__Zxml.saxrArLrSrNZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r r r Zfirewall.core.loggerr rZfirewall.errorsrrr4rrr!r!r!r"s        G#__pycache__/icmptype.cpython-36.opt-1.pyc000064400000011635147205345250014210 0ustar003 @)f@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)IcmpTypeicmptype_readericmptype_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)errors) FirewallErrorcspeZdZdddddgffZdZddgZd d d d Zd dgd d gdZfddZddZ ddZ ddZ Z S)rversionshort description destinationz(sssas)_-N)rricmptypenameipv4ipv6)rrcs*tt|jd|_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)rrrrcleanup?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).0mrrr Lsz+IcmpType.encode_strings..N)rrrrr)rrrrencode_stringsEs   zIcmpType.encode_stringscCs2|dkr.x$|D]}|dkrttjd|qWdS)Nrrrz'%s' not from {'ipv4'|'ipv6'})rr)r r ZINVALID_DESTINATION)rritemZ 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@seZdZddZdS)icmptype_ContentHandlercCstj||||jj|||dkrTd|kr>tjd|dd|kr|d|j_nT|dkr^nJ|dkrhn@|dkrx6d D].}||krv||jd krv|jjj t |qvWdS)Nrrz'Ignoring deprecated attribute name='%s'rrrrrryestrue)rr)r+r,) r startElementr$Zparser_check_element_attrsr Zwarningrlowerrappendstr)rrattrsxrrrr-Ys"  z$icmptype_ContentHandler.startElementN)r&r'r(r-rrrrr*Xsr*c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz%s is missing .xml suffixFTz%s/%srbznot a valid icmptype file: %s)rendswithr r Z INVALID_NAMErZ check_namefilenamepath startswithr ETC_FIREWALLDZbuiltindefaultr*saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_ICMPTYPEZ getExceptionrr#) r7r8rhandlerparserrfsourcemsgrrrrms8        (c Cs.|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd |jr|jd i}x|jD]} d|| <qW|jd||jd |jd |jd |j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr z rrr+r)r8r7rosexistsshutilZcopy2 Exceptionr errordirnamer9rr:mkdirior=r Z startDocumentrr-ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr8_pathrrCdirpathrAr?r1r2rrrrs\                       )N)__all__Zxml.saxr<rGrNrIZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r Zfirewall.core.loggerr r Zfirewall.errorsr rr*rrrrrrs       3__pycache__/icmptype.cpython-36.pyc000064400000011635147205345250013251 0ustar003 @)f@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)IcmpTypeicmptype_readericmptype_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)errors) FirewallErrorcspeZdZdddddgffZdZddgZd d d d Zd dgd d gdZfddZddZ ddZ ddZ Z S)rversionshort description destinationz(sssas)_-N)rricmptypenameipv4ipv6)rrcs*tt|jd|_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)rrrrcleanup?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).0mrrr Lsz+IcmpType.encode_strings..N)rrrrr)rrrrencode_stringsEs   zIcmpType.encode_stringscCs2|dkr.x$|D]}|dkrttjd|qWdS)Nrrrz'%s' not from {'ipv4'|'ipv6'})rr)r r ZINVALID_DESTINATION)rritemZ 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@seZdZddZdS)icmptype_ContentHandlercCstj||||jj|||dkrTd|kr>tjd|dd|kr|d|j_nT|dkr^nJ|dkrhn@|dkrx6d D].}||krv||jd krv|jjj t |qvWdS)Nrrz'Ignoring deprecated attribute name='%s'rrrrrryestrue)rr)r+r,) r startElementr$Zparser_check_element_attrsr Zwarningrlowerrappendstr)rrattrsxrrrr-Ys"  z$icmptype_ContentHandler.startElementN)r&r'r(r-rrrrr*Xsr*c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz%s is missing .xml suffixFTz%s/%srbznot a valid icmptype file: %s)rendswithr r Z INVALID_NAMErZ check_namefilenamepath startswithr ETC_FIREWALLDZbuiltindefaultr*saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_ICMPTYPEZ getExceptionrr#) r7r8rhandlerparserrfsourcemsgrrrrms8        (c Cs.|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd |jr|jd i}x|jD]} d|| <qW|jd||jd |jd |jd |j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr z rrr+r)r8r7rosexistsshutilZcopy2 Exceptionr errordirnamer9rr:mkdirior=r Z startDocumentrr-ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr8_pathrrCdirpathrAr?r1r2rrrrs\                       )N)__all__Zxml.saxr<rGrNrIZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r Zfirewall.core.loggerr r Zfirewall.errorsr rr*rrrrrrs       3__pycache__/ifcfg.cpython-36.opt-1.pyc000064400000007721147205345250013435 0ustar003 @)f@s^dZdgZddlZddlZddlZddlZddlmZddl m Z m Z m Z Gddde ZdS)zifcfg file parserifcfgN)log)b2uu2bPY2c@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfr r /usr/lib/python3.6/ifcfg.py__init__#szifcfg.__init__cCsi|_g|_dS)N)rr)r r r r r )sz ifcfg.clearcCs|jjdS)N)rr )r r r r cleanup-sz ifcfg.cleanupcCs|jj|jS)N)rgetstrip)r keyr r r r0sz ifcfg.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)r rvalueZ_keyr r r set3s  z ifcfg.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)r srrr r r __str__9s z ifcfg.__str__cCsB|jyt|jd}Wn4tk rL}ztjd|j|WYdd}~XnXx|D]}|s^P|j}t|dksT|ddkrqTdd|jd dD}t|d krqTt|dd kr|dj d r|dj d r|ddd|d<|dd krqTn,|j j |ddk r tj d |j|jqT|d|j |d<qTW|jdS)NrzFailed to load '%s': %sr#;cSsg|] }|jqSr )r).0xr r r Qszifcfg.read..="rz%%s: Duplicate option definition: '%s')rr)r openr Exceptionrerrorrlensplit startswithendswithrrZwarningclose)r fmsglineZpairr r r readBs2   z ifcfg.readc :Cst|jdkrdSg}y.tjddtjj|jtjj|jdd}Wn2t k rv}zt j d|WYdd}~XnXd}d}yt j |jddd }WnNt k r}z0tjj|jrt j d |j|fnd}WYdd}~XndXx^|D]T}|sP|jd }t|dkr(|sD|jd d }q|d dkrPd}|j||jd q|jdd}t|dkr~d}|j|d q|d j} |dj} t| dkr| jdr| jdr| dd} | |kr@| |jkr|j| | krd}|jd| |j| fd }n$| |jkr"d }nd}|j|d |j| qd }qWt|jd krxF|jjD]8\} } | |krzqd|sd }|jd| | fd }qdW|r|j|j|stj|jdStjj|jr8ytj|jd|jWnBt k r6}z$tj|jtd|j|fWYdd}~XnXytj|j|jWnBt k r}z$tj|jtd|j|fWYdd}~XnXtj|jddS)NrZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)r2encodingzFailed to open '%s': %srTrrr"r#r$z%s=%s z%s.bakzBackup of '%s' failed: %szFailed to create '%s': %sir%)r)rtempfileZNamedTemporaryFileospathbasenamer dirnamer'rr(ior&existsrwriter*r+r,rappendrr-rnameshutilZcopy2IOErrorZmovechmod) r doneZ temp_filer/Zmodifiedemptyr.r0prrr r r r>_s               $ $z ifcfg.writeN) __name__ __module__ __qualname__rr rrrrr1r>r r r r r"s )__doc____all__Zos.pathr8r<r7rAZfirewall.core.loggerrZfirewall.functionsrrrobjectrr r r r s __pycache__/ifcfg.cpython-36.pyc000064400000007721147205345250012476 0ustar003 @)f@s^dZdgZddlZddlZddlZddlZddlmZddl m Z m Z m Z Gddde ZdS)zifcfg file parserifcfgN)log)b2uu2bPY2c@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfr r /usr/lib/python3.6/ifcfg.py__init__#szifcfg.__init__cCsi|_g|_dS)N)rr)r r r r r )sz ifcfg.clearcCs|jjdS)N)rr )r r r r cleanup-sz ifcfg.cleanupcCs|jj|jS)N)rgetstrip)r keyr r r r0sz ifcfg.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)r rvalueZ_keyr r r set3s  z ifcfg.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)r srrr r r __str__9s z ifcfg.__str__cCsB|jyt|jd}Wn4tk rL}ztjd|j|WYdd}~XnXx|D]}|s^P|j}t|dksT|ddkrqTdd|jd dD}t|d krqTt|dd kr|dj d r|dj d r|ddd|d<|dd krqTn,|j j |ddk r tj d |j|jqT|d|j |d<qTW|jdS)NrzFailed to load '%s': %sr#;cSsg|] }|jqSr )r).0xr r r Qszifcfg.read..="rz%%s: Duplicate option definition: '%s')rr)r openr Exceptionrerrorrlensplit startswithendswithrrZwarningclose)r fmsglineZpairr r r readBs2   z ifcfg.readc :Cst|jdkrdSg}y.tjddtjj|jtjj|jdd}Wn2t k rv}zt j d|WYdd}~XnXd}d}yt j |jddd }WnNt k r}z0tjj|jrt j d |j|fnd}WYdd}~XndXx^|D]T}|sP|jd }t|dkr(|sD|jd d }q|d dkrPd}|j||jd q|jdd}t|dkr~d}|j|d q|d j} |dj} t| dkr| jdr| jdr| dd} | |kr@| |jkr|j| | krd}|jd| |j| fd }n$| |jkr"d }nd}|j|d |j| qd }qWt|jd krxF|jjD]8\} } | |krzqd|sd }|jd| | fd }qdW|r|j|j|stj|jdStjj|jr8ytj|jd|jWnBt k r6}z$tj|jtd|j|fWYdd}~XnXytj|j|jWnBt k r}z$tj|jtd|j|fWYdd}~XnXtj|jddS)NrZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)r2encodingzFailed to open '%s': %srTrrr"r#r$z%s=%s z%s.bakzBackup of '%s' failed: %szFailed to create '%s': %sir%)r)rtempfileZNamedTemporaryFileospathbasenamer dirnamer'rr(ior&existsrwriter*r+r,rappendrr-rnameshutilZcopy2IOErrorZmovechmod) r doneZ temp_filer/Zmodifiedemptyr.r0prrr r r r>_s               $ $z ifcfg.writeN) __name__ __module__ __qualname__rr rrrrr1r>r r r r r"s )__doc____all__Zos.pathr8r<r7rAZfirewall.core.loggerrZfirewall.functionsrrrobjectrr r r r s __pycache__/io_object.cpython-36.opt-1.pyc000064400000027540147205345250014315 0ustar003 @)f5@sdZddddddddgZd d ljZd d ljjZd d lZd d lZd d lm Z d d l m Z d d l m Z d dl mZd dlmZejdkZGdddeZGdddeZGdddeZGdddeZGdddejjZGdddejZddZddZddZ ddZ!d S)z5Generic io_object handler, io specific check methods.PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_addressN) OrderedDict) functions)b2u)errors) FirewallError3c@s|eZdZdZfZdZgZiZiZddZ ddZ ddZ d d Z d d Z d dZddZddZddZddZddZdS)rz; Abstract IO_Object as base for icmptype, service and zone z()cCs"d|_d|_d|_d|_d|_dS)NF)filenamepathnamedefaultZbuiltin)selfr/usr/lib/python3.6/io_object.py__init__2s zIO_Object.__init__cCs6g}x(|jD]}|jtjt||dq Wt|S)Nr )IMPORT_EXPORT_STRUCTUREappendcopydeepcopygetattrtuple)rretxrrr export_config9s zIO_Object.export_configcCsXi}tdd|jD}x:|D]2}t||sAsz0IO_Object.export_config_dict..)dictrr isinstanceboolrr)rconf type_formatskeyrrrexport_config_dict?s  zIO_Object.export_config_dictcCs|j|xt|jD]~\}\}}t||tr~g}t}x,||D] }||krD|j||j|qDW~t||t j |qt||t j ||qWdS)N) check_config enumeraterr&listsetraddsetattrrr)rr(ielementZdummyZ_confZ_setr rrr import_configGs  zIO_Object.import_configc Cs~|j|xn|D]f}t||s0ttjdj|t||tr`t||tt j t j ||qt||t j ||qWdS)Nz-Internal error. '{}' is not a valid attribute) check_config_dicthasattrrr Z UNKNOWN_ERRORformatr&r.r1r fromkeysrr)rr(r*rrrimport_config_dictWs   "zIO_Object.import_config_dictcCszt|ts(ttjd|tdt|ft|dkr@ttjdx4|D],}|j rF||j krFttjd||fqFWdS)Nz'%s' not of type %s, but %srr"zname can't be emptyz'%s' is not allowed in '%s') r&strrr INVALID_TYPEtypelenZ INVALID_NAMEisalnumADDITIONAL_ALNUM_CHARS)rrcharrrr check_namecs     zIO_Object.check_namecCsjt|t|jkr0ttjdt|t|jfi}x&t|jD]\}\}}||||<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|jDkrDttjdj||j|||||j||||qWdS)NcSsg|]}|d|dfqS)r r"r)r#r rrrr$|sz/IO_Object.check_config_dict..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)rZdummy1Zdummy2Zdummy3rrrrDszIO_Object._check_configc Cs`t|t|s,ttjd|t|t|ft|trrt|dkrRttjd|x|D]}|j||dqXWnt|trt|t|krttjd|t|fxt |D]\}}|j|||qWnt|t r\t|j d\}}xn|j D]b\}}t|t|s,ttjd|t|t|ft|t|sttjd|t|t|fqWdS)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 r2valueZskeyZsvaluer*rrrrCs8      z!IO_Object._check_config_structurecCs|j}d}||jkrdd}|j|dk rdx:|j|D],}||krL|j|q4ttjd||fq4W||jkrd}x$|j|D]}||kr~|j|q~W|sttjd|x |D]}ttjd||fqWdS)NFTzMissing attribute %s for %szUnexpected element %sz%s: Unexpected attribute %s)ZgetNamesPARSER_REQUIRED_ELEMENT_ATTRSremoverr Z PARSE_ERRORPARSER_OPTIONAL_ELEMENT_ATTRS)rrattrsZ_attrsfoundr rrrparser_check_element_attrss,     z$IO_Object.parser_check_element_attrsN)__name__ __module__ __qualname____doc__rZDBUS_SIGNATUREr?rGrIrr!r+r4r9rAr,r5rDrCrLrrrrr)s"   !cs$eZdZfddZddZZS)UnexpectedElementErrorcstt|j||_dS)N)superrQrr)rr) __class__rrrszUnexpectedElementError.__init__cCs d|jS)NzUnexpected element '%s')r)rrrr__str__szUnexpectedElementError.__str__)rMrNrOrrT __classcell__rr)rSrrQs rQcs$eZdZfddZddZZS)MissingAttributeErrorcstt|j||_||_dS)N)rRrVrr attribute)rrrW)rSrrrszMissingAttributeError.__init__cCsd|j|jfS)Nz$Element '%s': missing '%s' attribute)rrW)rrrrrTszMissingAttributeError.__str__)rMrNrOrrTrUrr)rSrrVs rVcs$eZdZfddZddZZS)UnexpectedAttributeErrorcstt|j||_||_dS)N)rRrXrrrW)rrrW)rSrrrsz!UnexpectedAttributeError.__init__cCsd|j|jfS)Nz'Element '%s': unexpected attribute '%s')rrW)rrrrrTsz UnexpectedAttributeError.__str__)rMrNrOrrTrUrr)rSrrXs rXc@s4eZdZddZddZddZddZd d Zd S) rcCs||_d|_dS)Nr)item_element)rrYrrrrsz!IO_Object_ContentHandler.__init__cCs d|_dS)Nr)rZ)rrrr startDocumentsz&IO_Object_ContentHandler.startDocumentcCs d|_dS)Nr)rZ)rrrJrrr startElementsz%IO_Object_ContentHandler.startElementcCs*|dkr|j|j_n|dkr&|j|j_dS)Nshort description)rZrYr]r^)rrrrr endElements z#IO_Object_ContentHandler.endElementcCs|j|jdd7_dS)N  )rZreplace)rcontentrrr characterssz#IO_Object_ContentHandler.charactersN)rMrNrOrr[r\r_rdrrrrrs c@s<eZdZddZddZddZddZd d Zd d Zd S)rcCsNtjjj||j|_|j|_ig|_|jd|_ g|_ d|_ d|_ d|_ dS)Nr"zutf-8F)saxhandlerContentHandlerrwrite_writeflushZ_flushZ _ns_contextsZ_current_contextZ_undeclared_ns_mapsZ _encodingZ_pending_start_elementZ_short_empty_elements)routrrrrs zIO_Object_XMLGenerator.__init__cCs*trdd|jD}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 sz7IO_Object_XMLGenerator.startElement..N)rrEsaxutils XMLGeneratorr\)rrrJrrrr\sz#IO_Object_XMLGenerator.startElementcCstrX|jdt|x4|jD](\}}|jdt|tjt|fq W|jdnF|jd|x,|jD] \}}|jd|tj|fqpW|jddS)z* slightly modified startElement() 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)rnroignorableWhitespacer )rrcrrrrr-sz*IO_Object_XMLGenerator.ignorableWhitespaceN) rMrNrOrr\rqr_rdrrrrrrrs  cCstj|}|dkr$ttjd|n`|dkr>ttjd|nF|dkrXttjd|n,t|dkr|d|dkrttjd|dS) Nzport number in '%s' is too bigr"z'%s' is invalid port rangezport range '%s' is ambiguousr re)r Z getPortRangerr Z INVALID_PORTr=)ZportZ port_rangerrrr5s    cCs|dkrttjd|dS)Ntcpudpsctpdccpz)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'})rurvrwrx)rr INVALID_PROTOCOL)protocolrrrrDscCstj|sttj|dS)N)r Z checkProtocolrr ry)rzrrrrJs cCs$tj||s ttjd||fdS)Nz'%s' is not valid %s address)r rrr Z INVALID_ADDR)ZipvZaddrrrrrNs )"rP__all__Zxml.saxrfZxml.sax.saxutilsrnrsys collectionsr Zfirewallr Zfirewall.functionsr r Zfirewall.errorsrversionrobjectr ExceptionrQrVrXrgrhrrorrrrrrrrrs0           C__pycache__/io_object.cpython-36.pyc000064400000027540147205345250013356 0ustar003 @)f5@sdZddddddddgZd d ljZd d ljjZd d lZd d lZd d lm Z d d l m Z d d l m Z d dl mZd dlmZejdkZGdddeZGdddeZGdddeZGdddeZGdddejjZGdddejZddZddZddZ ddZ!d S)z5Generic io_object handler, io specific check methods.PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_addressN) OrderedDict) functions)b2u)errors) FirewallError3c@s|eZdZdZfZdZgZiZiZddZ ddZ ddZ d d Z d d Z d dZddZddZddZddZddZdS)rz; Abstract IO_Object as base for icmptype, service and zone z()cCs"d|_d|_d|_d|_d|_dS)NF)filenamepathnamedefaultZbuiltin)selfr/usr/lib/python3.6/io_object.py__init__2s zIO_Object.__init__cCs6g}x(|jD]}|jtjt||dq Wt|S)Nr )IMPORT_EXPORT_STRUCTUREappendcopydeepcopygetattrtuple)rretxrrr export_config9s zIO_Object.export_configcCsXi}tdd|jD}x:|D]2}t||sAsz0IO_Object.export_config_dict..)dictrr isinstanceboolrr)rconf type_formatskeyrrrexport_config_dict?s  zIO_Object.export_config_dictcCs|j|xt|jD]~\}\}}t||tr~g}t}x,||D] }||krD|j||j|qDW~t||t j |qt||t j ||qWdS)N) check_config enumeraterr&listsetraddsetattrrr)rr(ielementZdummyZ_confZ_setr rrr import_configGs  zIO_Object.import_configc Cs~|j|xn|D]f}t||s0ttjdj|t||tr`t||tt j t j ||qt||t j ||qWdS)Nz-Internal error. '{}' is not a valid attribute) check_config_dicthasattrrr Z UNKNOWN_ERRORformatr&r.r1r fromkeysrr)rr(r*rrrimport_config_dictWs   "zIO_Object.import_config_dictcCszt|ts(ttjd|tdt|ft|dkr@ttjdx4|D],}|j rF||j krFttjd||fqFWdS)Nz'%s' not of type %s, but %srr"zname can't be emptyz'%s' is not allowed in '%s') r&strrr INVALID_TYPEtypelenZ INVALID_NAMEisalnumADDITIONAL_ALNUM_CHARS)rrcharrrr check_namecs     zIO_Object.check_namecCsjt|t|jkr0ttjdt|t|jfi}x&t|jD]\}\}}||||<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|jDkrDttjdj||j|||||j||||qWdS)NcSsg|]}|d|dfqS)r r"r)r#r rrrr$|sz/IO_Object.check_config_dict..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)rZdummy1Zdummy2Zdummy3rrrrDszIO_Object._check_configc Cs`t|t|s,ttjd|t|t|ft|trrt|dkrRttjd|x|D]}|j||dqXWnt|trt|t|krttjd|t|fxt |D]\}}|j|||qWnt|t r\t|j d\}}xn|j D]b\}}t|t|s,ttjd|t|t|ft|t|sttjd|t|t|fqWdS)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 r2valueZskeyZsvaluer*rrrrCs8      z!IO_Object._check_config_structurecCs|j}d}||jkrdd}|j|dk rdx:|j|D],}||krL|j|q4ttjd||fq4W||jkrd}x$|j|D]}||kr~|j|q~W|sttjd|x |D]}ttjd||fqWdS)NFTzMissing attribute %s for %szUnexpected element %sz%s: Unexpected attribute %s)ZgetNamesPARSER_REQUIRED_ELEMENT_ATTRSremoverr Z PARSE_ERRORPARSER_OPTIONAL_ELEMENT_ATTRS)rrattrsZ_attrsfoundr rrrparser_check_element_attrss,     z$IO_Object.parser_check_element_attrsN)__name__ __module__ __qualname____doc__rZDBUS_SIGNATUREr?rGrIrr!r+r4r9rAr,r5rDrCrLrrrrr)s"   !cs$eZdZfddZddZZS)UnexpectedElementErrorcstt|j||_dS)N)superrQrr)rr) __class__rrrszUnexpectedElementError.__init__cCs d|jS)NzUnexpected element '%s')r)rrrr__str__szUnexpectedElementError.__str__)rMrNrOrrT __classcell__rr)rSrrQs rQcs$eZdZfddZddZZS)MissingAttributeErrorcstt|j||_||_dS)N)rRrVrr attribute)rrrW)rSrrrszMissingAttributeError.__init__cCsd|j|jfS)Nz$Element '%s': missing '%s' attribute)rrW)rrrrrTszMissingAttributeError.__str__)rMrNrOrrTrUrr)rSrrVs rVcs$eZdZfddZddZZS)UnexpectedAttributeErrorcstt|j||_||_dS)N)rRrXrrrW)rrrW)rSrrrsz!UnexpectedAttributeError.__init__cCsd|j|jfS)Nz'Element '%s': unexpected attribute '%s')rrW)rrrrrTsz UnexpectedAttributeError.__str__)rMrNrOrrTrUrr)rSrrXs rXc@s4eZdZddZddZddZddZd d Zd S) rcCs||_d|_dS)Nr)item_element)rrYrrrrsz!IO_Object_ContentHandler.__init__cCs d|_dS)Nr)rZ)rrrr startDocumentsz&IO_Object_ContentHandler.startDocumentcCs d|_dS)Nr)rZ)rrrJrrr startElementsz%IO_Object_ContentHandler.startElementcCs*|dkr|j|j_n|dkr&|j|j_dS)Nshort description)rZrYr]r^)rrrrr endElements z#IO_Object_ContentHandler.endElementcCs|j|jdd7_dS)N  )rZreplace)rcontentrrr characterssz#IO_Object_ContentHandler.charactersN)rMrNrOrr[r\r_rdrrrrrs c@s<eZdZddZddZddZddZd d Zd d Zd S)rcCsNtjjj||j|_|j|_ig|_|jd|_ g|_ d|_ d|_ d|_ dS)Nr"zutf-8F)saxhandlerContentHandlerrwrite_writeflushZ_flushZ _ns_contextsZ_current_contextZ_undeclared_ns_mapsZ _encodingZ_pending_start_elementZ_short_empty_elements)routrrrrs zIO_Object_XMLGenerator.__init__cCs*trdd|jD}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 sz7IO_Object_XMLGenerator.startElement..N)rrEsaxutils XMLGeneratorr\)rrrJrrrr\sz#IO_Object_XMLGenerator.startElementcCstrX|jdt|x4|jD](\}}|jdt|tjt|fq W|jdnF|jd|x,|jD] \}}|jd|tj|fqpW|jddS)z* slightly modified startElement() 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)rnroignorableWhitespacer )rrcrrrrr-sz*IO_Object_XMLGenerator.ignorableWhitespaceN) rMrNrOrr\rqr_rdrrrrrrrs  cCstj|}|dkr$ttjd|n`|dkr>ttjd|nF|dkrXttjd|n,t|dkr|d|dkrttjd|dS) Nzport number in '%s' is too bigr"z'%s' is invalid port rangezport range '%s' is ambiguousr re)r Z getPortRangerr Z INVALID_PORTr=)ZportZ port_rangerrrr5s    cCs|dkrttjd|dS)Ntcpudpsctpdccpz)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'})rurvrwrx)rr INVALID_PROTOCOL)protocolrrrrDscCstj|sttj|dS)N)r Z checkProtocolrr ry)rzrrrrJs cCs$tj||s ttjd||fdS)Nz'%s' is not valid %s address)r rrr Z INVALID_ADDR)ZipvZaddrrrrrNs )"rP__all__Zxml.saxrfZxml.sax.saxutilsrnrsys collectionsr Zfirewallr Zfirewall.functionsr r Zfirewall.errorsrversionrobjectr ExceptionrQrVrXrgrhrrorrrrrrrrrs0           C__pycache__/ipset.cpython-36.opt-1.pyc000064400000025614147205345250013504 0ustar003 @)fR@sdZdddgZddljZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZdd lmZmZdd lmZmZmZmZdd l m!Z!dd lm"Z"dd l#m$Z$GdddeZ%GdddeZ&ddZ'dddZ(dS)z$ipset io XML handler, reader, writerIPSet ipset_reader ipset_writerN)config) checkIPcheckIP6 checkIPnMask checkIP6nMask u2b_if_py2 check_mac check_portcheckInterface checkProtocol)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator) IPSET_TYPESIPSET_CREATE_OPTIONS)check_icmp_namecheck_icmp_typecheck_icmpv6_namecheck_icmpv6_type)log)errors) FirewallErrorcseZdZddd d!dddifddgffZdZd d d d gZd d dgdgd dZdgdgdZfddZddZ ddZ e ddZ ddZ fddZZS)"rversionshort descriptiontypeoptionsentriesz (ssssa{ss}as)_-:.Nname)rripsetoptionentryvalue)r(r)cs<tt|jd|_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=|jjd|_dS)NrF)rrrr r"r!clearr.)r/r1r1r2cleanupMs  z IPSet.cleanupcCs\t|j|_t|j|_t|j|_t|j|_dd|jjD|_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 ).0kvr1r1r2 ^sz(IPSet.encode_strings..cSsg|] }t|qSr1)r )r5er1r1r2 `sz(IPSet.encode_strings..N)r rrrr r!itemsr")r/r1r1r2encode_stringsVs    zIPSet.encode_stringsc Csd}d|kr|ddkrd}|jds6ttjd||ddjd}|jd}t|t|ksnt|d krttjd ||fxztt|D]h}||}||}|d krd |ko|dkrh|d krttjd |||f|jd } t| dkrttjd||||fx| D]J} |dkr2t|  sH|dkrt |  rttjd| |||fqWnh|dkr|dkrttjd||||f|dkrt } nt} nt } | |sttjd||||fq|dkr@d |kr|jd } t| dkrttjd||||f|dkr0t| d sJ|dkrft | d rfttjd| d|||f|dkrt | d  s|dkr>t | d  r>ttjd| d |||fn|j dr|dko|dko|dksttjd||||f|dkrt | s&|dkrt | rttjd||||fq|dkrvt | s`|dkrttjd||fq|dkrd|kr|jd} t| dkrttjd|| ddkr|dkrttjd||ft| d  rt| d  rttjd| d |fn| dd1kr~|dkrDttjd||ft| d  rt| d  rttjd!| d |fn^| dd2krt| d rttjd&| d|fn&t| d sttjd'| d |fnt|sttjd(||fq|d)kr|jd*rPyt|d+} Wn*tk rLttjd,||fYnXn8y t|} Wn*tk rttjd,||fYnX| dks| d-krttjd,||fq|d.krt| st|d/krttjd0||fqttjd|qWdS)3NZipv4familyinet6Zipv6zhash: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'tcpsctpudpudplitezinvalid protocol '%s' in '%s'zinvalid port '%s'in '%s'zinvalid port '%s' in '%s'ZmarkZ0xzinvalid mark '%s' in '%s'lZifacezinvalid interface '%s' in '%s')rCrD)rErFrGrH) startswithrr INVALID_IPSETsplitlenZ INVALID_ENTRYrangerrrr endswithr rrrrrr int ValueErrorr ) r*r!Z ipset_typer=flagsr;iflagitemZsplitsZ_splitZip_checkZint_valr1r1r2 check_entrybs@                                zIPSet.check_entrycCs|dkr |tkr ttjd||dkrx|jD]}|tkrNttjd||dkryt||}Wn,tk rttj d|||fYnX|d krttj d |||fq2|d kr2||dkr2ttj ||q2WdS)Nr z'%s' is not valid ipset typer!zipset invalid option '%s'timeouthashsizemaxelemz)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer=inetr>)rXrYrZ)r[r>) rrr INVALID_TYPEkeysrrLrQrR INVALID_VALUEINVALID_FAMILY)r/rrVZ all_configkey int_valuer1r1r2 _check_configs2   zIPSet._check_configcsrd|dkr6|dddkr6t|ddkr6ttjx&|dD]}tj||d|dq@Wtt|j|dS)NrX0r?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@seZdZddZddZdS)ipset_ContentHandlerc Cstj||||jj|||dkrpd|krX|dtkrLttjd|d|d|j_d|krl|d|j_ nz|dkr|nn|dkrnb|dkrd}d |kr|d }|d dkrttj d|d |jjdko|d dkrttj d|d |jjf|d dkr&| r&ttj d|d |d dkry t |}Wn.t k rnttj d|d |fYnX|dkrttj d|d |f|d d kr|dkrttj||d |jjkr||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!rwarning)r/r'attrsr+rar1r1r2rm>sd      z!ipset_ContentHandler.startElementcCs(tj|||dkr$|jjj|jdS)Nr*)r endElementrVr"appendZ_element)r/r'r1r1r2rpus zipset_ContentHandler.endElementN)rgrhrirmrpr1r1r1r2rl=s7rlc %Cst}|jds ttjd||dd|_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~d |jkrF|jd d krFt|jd krFtjd |j|jdd=d } t} x| t|jkr|j| | krtjd |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/%srbznot 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_namefilenamepathrKr ETC_FIREWALLDZbuiltindefaultrlsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionrLZ getExceptionr!rNr"rrnsetpoprWr addrr<) rtrur(handlerparserr'fsourcemsgrTZ entries_setr9r1r1r2rzs^        (  c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|jd |ji}|jr|jd kr|j|d <|jd ||jd |jrz|jd krz|jd|jdi|j|j|jd|jd |jr|jd kr|jd|jdi|j|j|jd|jd xZ|jjD]L\} } |jd| d kr|jd| | dn|jdd| i|jd qWxD|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: %siZwtzUTF-8)modeencodingr rrr( z rrr))r'r+r'r*)!rurtr'osexistsshutilZcopy2 ExceptionrerrordirnamerKrrvmkdirioryrZ startDocumentr rrmZignorableWhitespacerZ charactersrprr!r;Z simpleElementr"Z endDocumentclose) r(ru_pathr'rdirpathrr~ror`r+r*r1r1r2rsf                           )N))__doc____all__Zxml.saxrxrrrZfirewallrZfirewall.functionsrrrr r r r r rZfirewall.core.io.io_objectrrrrZfirewall.core.ipsetrrZfirewall.core.icmprrrrZfirewall.core.loggerrrZfirewall.errorsrrrlrrr1r1r1r2s&   ,   =5__pycache__/ipset.cpython-36.pyc000064400000025614147205345250012545 0ustar003 @)fR@sdZdddgZddljZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZdd lmZmZdd lmZmZmZmZdd l m!Z!dd lm"Z"dd l#m$Z$GdddeZ%GdddeZ&ddZ'dddZ(dS)z$ipset io XML handler, reader, writerIPSet ipset_reader ipset_writerN)config) checkIPcheckIP6 checkIPnMask checkIP6nMask u2b_if_py2 check_mac check_portcheckInterface checkProtocol)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator) IPSET_TYPESIPSET_CREATE_OPTIONS)check_icmp_namecheck_icmp_typecheck_icmpv6_namecheck_icmpv6_type)log)errors) FirewallErrorcseZdZddd d!dddifddgffZdZd d d d gZd d dgdgd dZdgdgdZfddZddZ ddZ e ddZ ddZ fddZZS)"rversionshort descriptiontypeoptionsentriesz (ssssa{ss}as)_-:.Nname)rripsetoptionentryvalue)r(r)cs<tt|jd|_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=|jjd|_dS)NrF)rrrr r"r!clearr.)r/r1r1r2cleanupMs  z IPSet.cleanupcCs\t|j|_t|j|_t|j|_t|j|_dd|jjD|_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 ).0kvr1r1r2 ^sz(IPSet.encode_strings..cSsg|] }t|qSr1)r )r5er1r1r2 `sz(IPSet.encode_strings..N)r rrrr r!itemsr")r/r1r1r2encode_stringsVs    zIPSet.encode_stringsc Csd}d|kr|ddkrd}|jds6ttjd||ddjd}|jd}t|t|ksnt|d krttjd ||fxztt|D]h}||}||}|d krd |ko|dkrh|d krttjd |||f|jd } t| dkrttjd||||fx| D]J} |dkr2t|  sH|dkrt |  rttjd| |||fqWnh|dkr|dkrttjd||||f|dkrt } nt} nt } | |sttjd||||fq|dkr@d |kr|jd } t| dkrttjd||||f|dkr0t| d sJ|dkrft | d rfttjd| d|||f|dkrt | d  s|dkr>t | d  r>ttjd| d |||fn|j dr|dko|dko|dksttjd||||f|dkrt | s&|dkrt | rttjd||||fq|dkrvt | s`|dkrttjd||fq|dkrd|kr|jd} t| dkrttjd|| ddkr|dkrttjd||ft| d  rt| d  rttjd| d |fn| dd1kr~|dkrDttjd||ft| d  rt| d  rttjd!| d |fn^| dd2krt| d rttjd&| d|fn&t| d sttjd'| d |fnt|sttjd(||fq|d)kr|jd*rPyt|d+} Wn*tk rLttjd,||fYnXn8y t|} Wn*tk rttjd,||fYnX| dks| d-krttjd,||fq|d.krt| st|d/krttjd0||fqttjd|qWdS)3NZipv4familyinet6Zipv6zhash: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'tcpsctpudpudplitezinvalid protocol '%s' in '%s'zinvalid port '%s'in '%s'zinvalid port '%s' in '%s'ZmarkZ0xzinvalid mark '%s' in '%s'lZifacezinvalid interface '%s' in '%s')rCrD)rErFrGrH) startswithrr INVALID_IPSETsplitlenZ INVALID_ENTRYrangerrrr endswithr rrrrrr int ValueErrorr ) r*r!Z ipset_typer=flagsr;iflagitemZsplitsZ_splitZip_checkZint_valr1r1r2 check_entrybs@                                zIPSet.check_entrycCs|dkr |tkr ttjd||dkrx|jD]}|tkrNttjd||dkryt||}Wn,tk rttj d|||fYnX|d krttj d |||fq2|d kr2||dkr2ttj ||q2WdS)Nr z'%s' is not valid ipset typer!zipset invalid option '%s'timeouthashsizemaxelemz)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer=inetr>)rXrYrZ)r[r>) rrr INVALID_TYPEkeysrrLrQrR INVALID_VALUEINVALID_FAMILY)r/rrVZ all_configkey int_valuer1r1r2 _check_configs2   zIPSet._check_configcsrd|dkr6|dddkr6t|ddkr6ttjx&|dD]}tj||d|dq@Wtt|j|dS)NrX0r?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@seZdZddZddZdS)ipset_ContentHandlerc Cstj||||jj|||dkrpd|krX|dtkrLttjd|d|d|j_d|krl|d|j_ nz|dkr|nn|dkrnb|dkrd}d |kr|d }|d dkrttj d|d |jjdko|d dkrttj d|d |jjf|d dkr&| r&ttj d|d |d dkry t |}Wn.t k rnttj d|d |fYnX|dkrttj d|d |f|d d kr|dkrttj||d |jjkr||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!rwarning)r/r'attrsr+rar1r1r2rm>sd      z!ipset_ContentHandler.startElementcCs(tj|||dkr$|jjj|jdS)Nr*)r endElementrVr"appendZ_element)r/r'r1r1r2rpus zipset_ContentHandler.endElementN)rgrhrirmrpr1r1r1r2rl=s7rlc %Cst}|jds ttjd||dd|_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~d |jkrF|jd d krFt|jd krFtjd |j|jdd=d } t} x| t|jkr|j| | krtjd |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/%srbznot 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_namefilenamepathrKr ETC_FIREWALLDZbuiltindefaultrlsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionrLZ getExceptionr!rNr"rrnsetpoprWr addrr<) rtrur(handlerparserr'fsourcemsgrTZ entries_setr9r1r1r2rzs^        (  c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|jd |ji}|jr|jd kr|j|d <|jd ||jd |jrz|jd krz|jd|jdi|j|j|jd|jd |jr|jd kr|jd|jdi|j|j|jd|jd xZ|jjD]L\} } |jd| d kr|jd| | dn|jdd| i|jd qWxD|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: %siZwtzUTF-8)modeencodingr rrr( z rrr))r'r+r'r*)!rurtr'osexistsshutilZcopy2 ExceptionrerrordirnamerKrrvmkdirioryrZ startDocumentr rrmZignorableWhitespacerZ charactersrprr!r;Z simpleElementr"Z endDocumentclose) r(ru_pathr'rdirpathrr~ror`r+r*r1r1r2rsf                           )N))__doc____all__Zxml.saxrxrrrZfirewallrZfirewall.functionsrrrr r r r r rZfirewall.core.io.io_objectrrrrZfirewall.core.ipsetrrZfirewall.core.icmprrrrZfirewall.core.loggerrrZfirewall.errorsrrrlrrr1r1r1r2s&   ,   =5__pycache__/lockdown_whitelist.cpython-36.opt-1.pyc000064400000022550147205345250016270 0ustar003 @)f1@sddljZddlZddlZddlZddlmZddlmZm Z m Z m Z ddl m Z ddlmZmZmZmZmZmZddlmZddlmZGdd d e ZGd d d e ZdS) N)config)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)uniqify checkUsercheckUid checkCommand checkContext u2b_if_py2)errors) FirewallErrorc@seZdZddZddZdS)!lockdown_whitelist_ContentHandlercCstj||d|_dS)NF)r__init__ whitelist)selfitemr(/usr/lib/python3.6/lockdown_whitelist.pyr%s z*lockdown_whitelist_ContentHandler.__init__c CsVtj||||jj|||dkr@|jr6ttjdd|_n|dkrr|js\tj ddS|d}|jj |n|dkr|jstj ddSd |kryt |d }Wn&t k rtj d |d dSX|jj |nd|kr|jj|dn\|d kr@|jstj d dSd |kr.tj ddS|jj|d ntj d|dSdS)NrzMore than one whitelist.Tcommandz)Parse Error: command outside of whitelistnameuserz&Parse Error: user outside of whitelistidz"Parse Error: %s is not a valid uidselinuxz)Parse Error: selinux outside of whitelistcontextzParse Error: no contextzUnknown XML element %s)r startElementrZparser_check_element_attrsrrrZ PARSE_ERRORrerror add_commandint ValueErroradd_uidadd_user add_context)rrZattrsruidrrrr)sJ        z.lockdown_whitelist_ContentHandler.startElementN)__name__ __module__ __qualname__rrrrrrr$srcs4eZdZdZddgfddgfddgfddgffZdZd gZd d gd d gd Zddd giZfddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!dBdCZ"Z#S)DLockdownWhitelistz LockdownWhitelist class commandscontextsusersuidsrz (asasasai)_Nrr)rrrrrrcs6tt|j||_d|_g|_g|_g|_g|_dS)N) superr)rfilenameparserr*r,r-r.)rr1) __class__rrrnszLockdownWhitelist.__init__cCs|d kr.x|D]}|j||dd |qWnv|dkrLt|sttj|nX|dkrjt|sttj|n:|dkrt|sttj|n|d krt |sttj |dS) Nr*r,r-r.rrrr%)r*r,r-r.) _check_configr rrINVALID_COMMANDr INVALID_CONTEXTr INVALID_USERr INVALID_UID)rrrZ all_configxrrrr6ys zLockdownWhitelist._check_configcCs4|jdd=|jdd=|jdd=|jdd=dS)N)r*r,r-r.)rrrrcleanups   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 sz4LockdownWhitelist.encode_strings..cSsg|] }t|qSr)r )r=r;rrrr>scSsg|] }t|qSr)r )r=r;rrrr>sN)r*r,r-)rrrrencode_stringssz LockdownWhitelist.encode_stringscCs@t|sttj|||jkr,|jj|nttjd|dS)Nz!Command "%s" already in whitelist)r rrr7r*appendALREADY_ENABLED)rrrrrrs   zLockdownWhitelist.add_commandcCs,||jkr|jj|nttjd|dS)NzCommand "%s" not in whitelist.)r*removerr NOT_ENABLED)rrrrrremove_commands z LockdownWhitelist.remove_commandcCs ||jkS)N)r*)rrrrr has_commandszLockdownWhitelist.has_commandcCsBx<|jD]2}|jdr.|j|ddr:dSq||krdSqWdS)N*r4TFr5)r*endswith startswith)rrZ_commandrrr match_commands  zLockdownWhitelist.match_commandcCs|jS)N)r*)rrrr get_commandsszLockdownWhitelist.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_uids zLockdownWhitelist.remove_uidcCs ||jkS)N)r.)rr%rrrhas_uidszLockdownWhitelist.has_uidcCs ||jkS)N)r.)rr%rrr match_uidszLockdownWhitelist.match_uidcCs|jS)N)r.)rrrrget_uidsszLockdownWhitelist.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_users zLockdownWhitelist.remove_usercCs ||jkS)N)r-)rrrrrhas_userszLockdownWhitelist.has_usercCs ||jkS)N)r-)rrrrr match_userszLockdownWhitelist.match_usercCs|jS)N)r-)rrrr get_usersszLockdownWhitelist.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)rrrrrremove_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|jjds&ttjd|jt|}tj}|j |y|j |jWn8tj k r}zttj d|j WYdd}~XnX~~tr|jdS)Nz.xmlz'%s' is missing .xml suffixzNot a valid file: %s)r<r1rGrrZ INVALID_NAMErsaxZ make_parserZsetContentHandlerparseZSAXParseExceptionZ INVALID_TYPEZ getExceptionrr?)rhandlerr2msgrrrread>s"   zLockdownWhitelist.readcCstjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdx6t|jD](}|jd |jd d |i|jdqWx:t|jD],}|jd |jd d t|i|jdqWx8t|jD]*}|jd |jd d |i|jdq0Wx8t|jD]*}|jd |jdd|i|jdqjW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z rrrrrr)ospathexistsr1shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdirioopenrZ startDocumentrZignorableWhitespacerr*Z simpleElementr.rKr-r,Z endElementZ endDocumentclose)rr[frZrr%rrrrrwriteQsB$         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 r r r rZfirewall.errorsrrr)rrrrs      3__pycache__/lockdown_whitelist.cpython-36.pyc000064400000022550147205345250015331 0ustar003 @)f1@sddljZddlZddlZddlZddlmZddlmZm Z m Z m Z ddl m Z ddlmZmZmZmZmZmZddlmZddlmZGdd d e ZGd d d e ZdS) N)config)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)uniqify checkUsercheckUid checkCommand checkContext u2b_if_py2)errors) FirewallErrorc@seZdZddZddZdS)!lockdown_whitelist_ContentHandlercCstj||d|_dS)NF)r__init__ whitelist)selfitemr(/usr/lib/python3.6/lockdown_whitelist.pyr%s z*lockdown_whitelist_ContentHandler.__init__c CsVtj||||jj|||dkr@|jr6ttjdd|_n|dkrr|js\tj ddS|d}|jj |n|dkr|jstj ddSd |kryt |d }Wn&t k rtj d |d dSX|jj |nd|kr|jj|dn\|d kr@|jstj d dSd |kr.tj ddS|jj|d ntj d|dSdS)NrzMore than one whitelist.Tcommandz)Parse Error: command outside of whitelistnameuserz&Parse Error: user outside of whitelistidz"Parse Error: %s is not a valid uidselinuxz)Parse Error: selinux outside of whitelistcontextzParse Error: no contextzUnknown XML element %s)r startElementrZparser_check_element_attrsrrrZ PARSE_ERRORrerror add_commandint ValueErroradd_uidadd_user add_context)rrZattrsruidrrrr)sJ        z.lockdown_whitelist_ContentHandler.startElementN)__name__ __module__ __qualname__rrrrrrr$srcs4eZdZdZddgfddgfddgfddgffZdZd gZd d gd d gd Zddd giZfddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!dBdCZ"Z#S)DLockdownWhitelistz LockdownWhitelist class commandscontextsusersuidsrz (asasasai)_Nrr)rrrrrrcs6tt|j||_d|_g|_g|_g|_g|_dS)N) superr)rfilenameparserr*r,r-r.)rr1) __class__rrrnszLockdownWhitelist.__init__cCs|d kr.x|D]}|j||dd |qWnv|dkrLt|sttj|nX|dkrjt|sttj|n:|dkrt|sttj|n|d krt |sttj |dS) Nr*r,r-r.rrrr%)r*r,r-r.) _check_configr rrINVALID_COMMANDr INVALID_CONTEXTr INVALID_USERr INVALID_UID)rrrZ all_configxrrrr6ys zLockdownWhitelist._check_configcCs4|jdd=|jdd=|jdd=|jdd=dS)N)r*r,r-r.)rrrrcleanups   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 sz4LockdownWhitelist.encode_strings..cSsg|] }t|qSr)r )r=r;rrrr>scSsg|] }t|qSr)r )r=r;rrrr>sN)r*r,r-)rrrrencode_stringssz LockdownWhitelist.encode_stringscCs@t|sttj|||jkr,|jj|nttjd|dS)Nz!Command "%s" already in whitelist)r rrr7r*appendALREADY_ENABLED)rrrrrrs   zLockdownWhitelist.add_commandcCs,||jkr|jj|nttjd|dS)NzCommand "%s" not in whitelist.)r*removerr NOT_ENABLED)rrrrrremove_commands z LockdownWhitelist.remove_commandcCs ||jkS)N)r*)rrrrr has_commandszLockdownWhitelist.has_commandcCsBx<|jD]2}|jdr.|j|ddr:dSq||krdSqWdS)N*r4TFr5)r*endswith startswith)rrZ_commandrrr match_commands  zLockdownWhitelist.match_commandcCs|jS)N)r*)rrrr get_commandsszLockdownWhitelist.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_uids zLockdownWhitelist.remove_uidcCs ||jkS)N)r.)rr%rrrhas_uidszLockdownWhitelist.has_uidcCs ||jkS)N)r.)rr%rrr match_uidszLockdownWhitelist.match_uidcCs|jS)N)r.)rrrrget_uidsszLockdownWhitelist.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_users zLockdownWhitelist.remove_usercCs ||jkS)N)r-)rrrrrhas_userszLockdownWhitelist.has_usercCs ||jkS)N)r-)rrrrr match_userszLockdownWhitelist.match_usercCs|jS)N)r-)rrrr get_usersszLockdownWhitelist.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)rrrrrremove_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|jjds&ttjd|jt|}tj}|j |y|j |jWn8tj k r}zttj d|j WYdd}~XnX~~tr|jdS)Nz.xmlz'%s' is missing .xml suffixzNot a valid file: %s)r<r1rGrrZ INVALID_NAMErsaxZ make_parserZsetContentHandlerparseZSAXParseExceptionZ INVALID_TYPEZ getExceptionrr?)rhandlerr2msgrrrread>s"   zLockdownWhitelist.readcCstjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdx6t|jD](}|jd |jd d |i|jdqWx:t|jD],}|jd |jd d t|i|jdqWx8t|jD]*}|jd |jd d |i|jdq0Wx8t|jD]*}|jd |jdd|i|jdqjW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z rrrrrr)ospathexistsr1shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdirioopenrZ startDocumentrZignorableWhitespacerr*Z simpleElementr.rKr-r,Z endElementZ endDocumentclose)rr[frZrr%rrrrrwriteQsB$         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 r r r rZfirewall.errorsrrr)rrrrs      3__pycache__/policy.cpython-36.opt-1.pyc000064400000051212147205345250013650 0ustar003 @)fϢ@s dddgZddljZddlZddlZddlZddlmZddlm Z m Z ddlm Z m Z m Z ddlmZmZmZdd lmZmZmZmZmZmZdd lmZdd lmZdd lmZdd lmZddZ ddZ!ddZ"ddZ#ddZ$GdddeZ%GdddeZ&dddZ'dddZ(dS) Policy policy_reader policy_writerN)config)checkIPcheckIP6)uniqifymax_policy_name_lenportStr)DEFAULT_POLICY_TARGETPOLICY_TARGETSDEFAULT_POLICY_PRIORITY) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol)rich)log)errors) FirewallErrorc Cs|dkr n|dkrn|dkr|jr`|jjrJtjdt|jd|_dStj|d|j_dS|d|jj kr|jj j |dntjd|dn|dkrN|jr|jjrtjdt|jd|_dStj |d|d |j_dSt |dt |d t|dd |d f}||jjkr4|jjj |ntjd |d|d nN|d kr|jr|jjrtjdt|jd|_dStj|d |j_nBt|d |d |jjkr|jjj |d ntjd |d n|dkrh|jr.|jjrtjdt|jd|_dStj|d|j_dS|d|jjkrT|jjj |dntjd|dn4|dkr|jr|jjrtjdt|jd|_dStj|d|j_dStjd|dn|dkr2|jr|jjrtjdt|jd|_dStj|j_n|jjr&tjdnd|j_nj|dkrd}d|krR|d}d}d|krh|d}|jr|jjrtjdt|jd|_dStj|d|d |||j_dSt |dt |d |rt ||r t| r t| r ttjd|t|dd |d t|d t|f}||jjkrL|jjj |n6tjd|d|d |rld|nd|r|d|ndn|dkr@|jr|jjrtjdt|jd|_dStj|d|d |j_dSt |dt |d t|dd |d f}||jj kr&|jj j |ntjd|d|d n\|dkr|jsftjdd|_dS|jj!rtjd t|jdSd!}d}d"|kr|d"}d}d#|kr|d#}d$|kr|d$j"dLkrd}tj#||||j_!n|dMkr|jstjd+d|_dS|jj$r0tjd,d|_dS|d'krHtj%|j_$nh|d(krxd} d-|krh|d-} tj&| |j_$n8|d)krtj'|j_$n |d*kr|d.} tj(| |j_$|jj$|_)n|d/kr^|jstjd0dS|jjrtjd1dSd} d2|kr*|d2} | dNkr*tjd;d|_dSd<|kr<|d<nd} tj*| | |j_|jj|_)n>|d=kr|js~tjd>dS|jj+rtjd?t|jd|_dStj,|j_+|jj+|_)n|d@kr,d} dA}dB|kr|dB} | dOkrtjdE|dBd|_dSdF|krt-|dF}tj.| |dG|_np|dHkr|j)sRtjdId|_dS|j)j/rxtjdJt|jd|_dS|d }tj0||j1dK|j)_/nd!SdS)PNshort descriptionservicez;Invalid rule: More than one element in rule '%s', ignoring.Tnamez#Service '%s' already set, ignoring.portprotocol-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-portzto-portzto-addrz#to-addr '%s' is not a valid addressz-Forward port %s/%s%s%s already set, ignoring.z >%sz @%sz source-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.Faddressipsetinvertyestrueacceptrejectdropmarkz$Invalid rule: Action outside of rulez"Invalid rule: More than one actiontypesetrz!Invalid rule: Log outside of rulezInvalid rule: More than one loglevelemergalertcriterrorwarningnoticeinfodebugzInvalid rule: Invalid log levelprefixauditz#Invalid rule: Audit outside of rulez9Invalid rule: More than one audit in rule '%s', ignoring.rulerfamilyipv4ipv6z&Invalid rule: Rule family "%s" invalidpriority)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_ruleelementrr3str _rule_errorr Rich_Serviceitemservicesappend Rich_Portrrr ports Rich_Protocolr protocolsRich_IcmpBlock icmp_blocks Rich_IcmpTypeRich_Masquerader Rich_ForwardPortrrrr INVALID_ADDR forward_portsRich_SourcePort source_portsr"lowerZRich_Destinationaction Rich_Accept Rich_Reject Rich_Drop Rich_Mark _limit_okZRich_Logr8Z Rich_Auditint Rich_Ruler>Z Rich_Limitget)objrattrsentryto_portZto_addrr%r#r$Z_typeZ_setr.r7r:r=rrc/usr/lib/python3.6/policy.pycommon_startElements                                                                            recCs|dkr|jsy|jjWn6tk rR}ztjd|t|jWYdd}~XnLXt|j|jjkr|jj j |j|jjj t|jntjdt|jd|_d|_n|d krd|_ dS) Nr9z%s: %sz Rule '%s' already set, ignoring.Fr(r)r*r+rr8)r(r)r*r+rr8) rCr@Zcheck Exceptionrr3rBrE rules_strrulesrGr[)r_rercrcrdcommon_endElements& rjcCst|trdnd}|dkrT|jrT|jj}x$|D]}||kr0ttjd|q0Wn|dkrx$|D]}t|dt|dqbWnb|dkrx|D] }t |qWn@|d kr|jr|jj } x$|D]} | | krttj d | qWn|d krx|D]} t| dt| d| d  r>| d  r>ttj d| | d rTt| d | d rt | d  rt| d  rttjd| d qWnT|dkrx&|D]}t|dt|dqWn|dkrx|D]} tj| d} |jr| jrt| jtjst| jtjr|jj } | jj| krLttj d | jjnH| jr|jj| jj}|jr| j|jkrttj d| j| jjfnL|jrt| jtjr|jj}| jj|krttjdj||j| jjqWdS)NrZZonerFz '%s' not among existing servicesrIrrKrMz"'%s' not among existing icmp typesrRz$'%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_ICMPTYPEINVALID_FORWARDrrrQrr]rArLrNrr:Z get_icmptyper"rDformat)r_rrE all_configZobj_typeZexisting_servicesrrprotoZexisting_icmptypesZicmptypefwd_portr9Zobj_richZictrcrcrdcommon_check_config2s                      rwcCs0d|ji}|j}|dk r ||d<|jd|dS)Nrr?r>)rr? simpleElement)handlerr>dr?rcrcrd_handler_add_rich_limitxs  r{c Cs|jrF|jdkrF|jd|jdi|j|j|jd|jd|jr|jdkr|jd|jdi|j|j|jd|jdx6t|jD](}|jd|jdd|i|jdqWx@t|j D]2}|jd|jd|d |d d |jdqWx8t|j D]*}|jd|jd d |i|jdqWx8t|j D]*}|jd|jdd|i|jdqLW|j r|jd|jdi|jdxt|j D]}|jd|d |d d }|dr|ddkr|d|d<|dr|ddkr|d|d<|jd||jdqWxBt|jD]4}|jd|jd|d |d d |jdq>WxT|jD]H}i}|jr|j|d<|jd krt|j|d<|jd|jd||jd|jrVi}|jjr|jj|d<|jjr|jj|d<|jjr$|jj|d<|jjr6d|d<|jd|jd||jd|jri}|jjrx|jj|d<|jjr|jj|d<|jjrd|d<|jd|jd ||jd|jrxd} i}t|jtjkrd} |jj|d<nbt|jtjkr(d} |jj|d<|jj |d <n0t|jtj!krNd } |jj"|d <n t|jtj#krfd} nt|jtj$krd} |jj|d<nt|jtj%krd!} |jj|d<nt|jtj&krd} |jj|d<|jj |d <|jj'dkr|jj'|d<|jj(dkrX|jj(|d<nFt|jtj)krBd} |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-j0r|jd|jd%||jd&t1||j-j0|jd'|jd%n|jd|jd%||jd|j2ri}|j2j0rx|jd|jd(i|jd&t1||j2j0|jd'|jd(n|jd|jd(||jd|j3rd} i}t|j3tj4krd)} n|t|j3tj5krd*} |j3jr<|j3j|d+<nNt|j3tj6krd,} n6t|j3tj7kr*d-} |j3j8|d.<nt-j9d/t|j3|j3j0r|jd|j| ||jd&t1||j3j0|jd'|j| n|jd|j| ||jd|jd|jd|jdqWdS)0Nr!z r rrrrrrk)rrrrz icmp-blockr rlzto-portrmzto-addrz forward-portz source-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'):rignorableWhitespace startElementZ characters endElementrrrFrxrIrKrMr rRrTrhr:r=rBraddrr}r$r%r"rAr,rrDrrHrrrJrrOrLrNrPrb to_addressrSrrZINVALID_OBJECTrr7r.r>r{r8rVrWrXrYrZr-r3) r_ryrrrZicmpZforwardr`r9rArVrcrcrd common_writers\                                                                                        rcsPeZdZd7ZdZeZdgZd8d9d:d;d dgfd dgfddgfddgfdd?gfd@ddgfddgffZdddgZ dddgdgddgdgdgdddgddddgddgddddddgdgdgdgdZ ddgdd gd!dgd"d#d$d!d%gd"d$d%gd&d'gd(gd)gd*Z fd+d,Z d-d.Z fd/d0Zfd1d2Zd3d4Zfd5d6ZZS)Ariirversionr!rrtargetrFrIrMr FrRrnrKrTr= ingress_zones egress_zones_r/Nrrrrr-)rrpolicyrrz icmp-blockz icmp-typer z forward-portr9rr"rz source-portrr8r(r)r*r+r>z ingress-zonez egress-zonezto-portzto-addrr:r#r}r%r$r7r.r,r?)rz forward-portr9rr"rr)r>cstt|jd|_d|_d|_t|_g|_g|_ g|_ g|_ d|_ g|_ g|_d|_g|_g|_d|_|j|_d|_g|_g|_dS)Nr!F)superr__init__rrrr rrFrIrKrMr rRrTrqrhrgappliedpriority_defaultr=Zderived_from_zonerr)self) __class__rcrdrs(zPolicy.__init__cCsd|_d|_d|_t|_|jdd=|jdd=|jdd=|jdd=d|_ |j dd=|j dd=d|_ |j dd=|jdd=d|_|j|_|jdd=|jdd=dS)Nr!F)rrrr rrFrIrKrMr rRrTrqrhrgrrr=rr)rrcrcrdcleanups$         zPolicy.cleanupcs"|dkr|jSttt||SdS)Nrn)rggetattrrr)rr)rrcrd __getattr__szPolicy.__getattr__csB|dkr,dd|D|_dd|jD|_ntt|j||dS)NrncSsg|]}tj|dqS))ro)rr]).0srcrcrd sz&Policy.__setattr__..cSsg|] }t|qSrc)rB)rrrcrcrdrs)rhrgrr __setattr__)rrr)rrcrdrszPolicy.__setattr__c Cst|||||dkr2|tkr.ttjd|n|dkrz||jksX||jksX||jkrvttjd||j|j|jfn|dkrhddg}|j r||j j 7}x|D]}||krttj d ||dkrt ddgt |@s|dkrt |t |grttj d ||dkr|dkr8d|kr8d|dksT|dkrd|krd|dkrttj d qWn|d kr|rd|krd|dkrttj d nxd|krd|dkrttj dxR|dD]F}|dkrސq|j j |}|j rd|j j|krttj dqWn|dkr4x|D]}tj|d}|jrt|jtjrd|kr|d|dkr|ttj d nxd|kr,d|dkrttj dxR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,|jrt|jtjrd|kr,d|dkr@|jjrttjdnt|dr,|jjs`ttjdd|dkr,x|dD]8}|j j |}|j rxd|j j|krxttj dqxWnv|jr,t|jtjr,d|kr,xR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,Wn|dkrx|D]} d|krnd|dkrnttj dnd|krDd|dkr| drttjdnt|drD| dsttjdd|dkrDxD|dD]8}|j j |}|j rd|j j|krttj dqWqDWdS)Nrz'%s' is invalid targetr=zQ%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %srrANYHOSTz'%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)rr)rr)rr)rr)rwr rrINVALID_TARGETpriority_reserved priority_max priority_minZINVALID_PRIORITYrq get_zonesZ INVALID_ZONEr-Zget_zoneZget_zone_config_dictrr]rArprOrPrrrrVrZ) rrrErtZexisting_zoneszoneZz_objr9r_rvrcrcrd _check_configs       "                           zPolicy._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|njd|kr|d|j d}n|}t |t krttjd|t |t f|j r||j j krttjddS)Nrz'%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.)rr check_name startswithrr INVALID_NAMEendswithcountfindlenr rqrZ NAME_CONFLICT)rrZ checked_name)rrcrdr,s*      zPolicy.check_namei)rr!)rr!)rr!)rr!)r!r!)r F)r!r!r!r!)r!r!)r=r)__name__ __module__ __qualname__rrr rrZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrrrrr __classcell__rcrc)rrdrZsr        ^c@s$eZdZddZddZddZdS)policy_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrr@rCr[)rrErcrcrdrHs zpolicy_ContentHandler.__init__cCstj||||jrdS|jj||t|||r6dS|dkrd|krR|d|j_d|krjt|d|j_d|kr|d}|t krt t j ||r||j_ n^|dkr|d|jjkr|jjj|dntjd|dn|dkr |d|jjkr|jjj|dntjd |dn|d kr|jsFtjd d |_dS|jjrltjd t|jd |_dSd}d|kr|djdkrd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dStjd|dSdS)Nrrr=rz ingress-zonerz(Ingress zone '%s' already set, ignoring.z egress-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')rrrCrEZparser_check_element_attrsrerr\r=r rrrrrrGrr3rr@rrBrUrZ Rich_Source)rrr`rr%rr}r$rcrcrdrNsf                 z"policy_ContentHandler.startElementcCstj||t||dS)N)rrrj)rrrcrcrdrs z policy_ContentHandler.endElementN)rrrrrrrcrcrcrdrGs@rFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid policy file: %s)rrrrrrrfilenamepathrr ETC_FIREWALLDZbuiltindefaultrsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_POLICYZ getException) rrZ no_check_namerryparserrfrmsgrcrcrdrs6        (c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|j|jkr0t|j|d <|j|d <|jd ||jdt||x8t|jD]*} |jd|jdd| i|jdqfWx8t|jD]*} |jd|jdd| i|jdqW|jd |jd|j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingr!rr=rrr|z z ingress-zonerz egress-zone)"rrrosexistsshutilZcopy2rfrr2dirnamerrrmkdiriorrZ startDocumentrr=rrBrrrrrrrxrrZ endDocumentclose) rr_pathrrdirpathrryr`rrcrcrdrsN             )F)N))__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r Zfirewall.core.baser r r Zfirewall.core.io.io_objectrrrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrerjrwr{rrrrrrcrcrcrds4        F[nL __pycache__/policy.cpython-36.pyc000064400000051212147205345250012711 0ustar003 @)fϢ@s dddgZddljZddlZddlZddlZddlmZddlm Z m Z ddlm Z m Z m Z ddlmZmZmZdd lmZmZmZmZmZmZdd lmZdd lmZdd lmZdd lmZddZ ddZ!ddZ"ddZ#ddZ$GdddeZ%GdddeZ&dddZ'dddZ(dS) Policy policy_reader policy_writerN)config)checkIPcheckIP6)uniqifymax_policy_name_lenportStr)DEFAULT_POLICY_TARGETPOLICY_TARGETSDEFAULT_POLICY_PRIORITY) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol)rich)log)errors) FirewallErrorc Cs|dkr n|dkrn|dkr|jr`|jjrJtjdt|jd|_dStj|d|j_dS|d|jj kr|jj j |dntjd|dn|dkrN|jr|jjrtjdt|jd|_dStj |d|d |j_dSt |dt |d t|dd |d f}||jjkr4|jjj |ntjd |d|d nN|d kr|jr|jjrtjdt|jd|_dStj|d |j_nBt|d |d |jjkr|jjj |d ntjd |d n|dkrh|jr.|jjrtjdt|jd|_dStj|d|j_dS|d|jjkrT|jjj |dntjd|dn4|dkr|jr|jjrtjdt|jd|_dStj|d|j_dStjd|dn|dkr2|jr|jjrtjdt|jd|_dStj|j_n|jjr&tjdnd|j_nj|dkrd}d|krR|d}d}d|krh|d}|jr|jjrtjdt|jd|_dStj|d|d |||j_dSt |dt |d |rt ||r t| r t| r ttjd|t|dd |d t|d t|f}||jjkrL|jjj |n6tjd|d|d |rld|nd|r|d|ndn|dkr@|jr|jjrtjdt|jd|_dStj|d|d |j_dSt |dt |d t|dd |d f}||jj kr&|jj j |ntjd|d|d n\|dkr|jsftjdd|_dS|jj!rtjd t|jdSd!}d}d"|kr|d"}d}d#|kr|d#}d$|kr|d$j"dLkrd}tj#||||j_!n|dMkr|jstjd+d|_dS|jj$r0tjd,d|_dS|d'krHtj%|j_$nh|d(krxd} d-|krh|d-} tj&| |j_$n8|d)krtj'|j_$n |d*kr|d.} tj(| |j_$|jj$|_)n|d/kr^|jstjd0dS|jjrtjd1dSd} d2|kr*|d2} | dNkr*tjd;d|_dSd<|kr<|d<nd} tj*| | |j_|jj|_)n>|d=kr|js~tjd>dS|jj+rtjd?t|jd|_dStj,|j_+|jj+|_)n|d@kr,d} dA}dB|kr|dB} | dOkrtjdE|dBd|_dSdF|krt-|dF}tj.| |dG|_np|dHkr|j)sRtjdId|_dS|j)j/rxtjdJt|jd|_dS|d }tj0||j1dK|j)_/nd!SdS)PNshort descriptionservicez;Invalid rule: More than one element in rule '%s', ignoring.Tnamez#Service '%s' already set, ignoring.portprotocol-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-portzto-portzto-addrz#to-addr '%s' is not a valid addressz-Forward port %s/%s%s%s already set, ignoring.z >%sz @%sz source-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.Faddressipsetinvertyestrueacceptrejectdropmarkz$Invalid rule: Action outside of rulez"Invalid rule: More than one actiontypesetrz!Invalid rule: Log outside of rulezInvalid rule: More than one loglevelemergalertcriterrorwarningnoticeinfodebugzInvalid rule: Invalid log levelprefixauditz#Invalid rule: Audit outside of rulez9Invalid rule: More than one audit in rule '%s', ignoring.rulerfamilyipv4ipv6z&Invalid rule: Rule family "%s" invalidpriority)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_ruleelementrr3str _rule_errorr Rich_Serviceitemservicesappend Rich_Portrrr ports Rich_Protocolr protocolsRich_IcmpBlock icmp_blocks Rich_IcmpTypeRich_Masquerader Rich_ForwardPortrrrr INVALID_ADDR forward_portsRich_SourcePort source_portsr"lowerZRich_Destinationaction Rich_Accept Rich_Reject Rich_Drop Rich_Mark _limit_okZRich_Logr8Z Rich_Auditint Rich_Ruler>Z Rich_Limitget)objrattrsentryto_portZto_addrr%r#r$Z_typeZ_setr.r7r:r=rrc/usr/lib/python3.6/policy.pycommon_startElements                                                                            recCs|dkr|jsy|jjWn6tk rR}ztjd|t|jWYdd}~XnLXt|j|jjkr|jj j |j|jjj t|jntjdt|jd|_d|_n|d krd|_ dS) Nr9z%s: %sz Rule '%s' already set, ignoring.Fr(r)r*r+rr8)r(r)r*r+rr8) rCr@Zcheck Exceptionrr3rBrE rules_strrulesrGr[)r_rercrcrdcommon_endElements& rjcCst|trdnd}|dkrT|jrT|jj}x$|D]}||kr0ttjd|q0Wn|dkrx$|D]}t|dt|dqbWnb|dkrx|D] }t |qWn@|d kr|jr|jj } x$|D]} | | krttj d | qWn|d krx|D]} t| dt| d| d  r>| d  r>ttj d| | d rTt| d | d rt | d  rt| d  rttjd| d qWnT|dkrx&|D]}t|dt|dqWn|dkrx|D]} tj| d} |jr| jrt| jtjst| jtjr|jj } | jj| krLttj d | jjnH| jr|jj| jj}|jr| j|jkrttj d| j| jjfnL|jrt| jtjr|jj}| jj|krttjdj||j| jjqWdS)NrZZonerFz '%s' not among existing servicesrIrrKrMz"'%s' not among existing icmp typesrRz$'%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_ICMPTYPEINVALID_FORWARDrrrQrr]rArLrNrr:Z get_icmptyper"rDformat)r_rrE all_configZobj_typeZexisting_servicesrrprotoZexisting_icmptypesZicmptypefwd_portr9Zobj_richZictrcrcrdcommon_check_config2s                      rwcCs0d|ji}|j}|dk r ||d<|jd|dS)Nrr?r>)rr? simpleElement)handlerr>dr?rcrcrd_handler_add_rich_limitxs  r{c Cs|jrF|jdkrF|jd|jdi|j|j|jd|jd|jr|jdkr|jd|jdi|j|j|jd|jdx6t|jD](}|jd|jdd|i|jdqWx@t|j D]2}|jd|jd|d |d d |jdqWx8t|j D]*}|jd|jd d |i|jdqWx8t|j D]*}|jd|jdd|i|jdqLW|j r|jd|jdi|jdxt|j D]}|jd|d |d d }|dr|ddkr|d|d<|dr|ddkr|d|d<|jd||jdqWxBt|jD]4}|jd|jd|d |d d |jdq>WxT|jD]H}i}|jr|j|d<|jd krt|j|d<|jd|jd||jd|jrVi}|jjr|jj|d<|jjr|jj|d<|jjr$|jj|d<|jjr6d|d<|jd|jd||jd|jri}|jjrx|jj|d<|jjr|jj|d<|jjrd|d<|jd|jd ||jd|jrxd} i}t|jtjkrd} |jj|d<nbt|jtjkr(d} |jj|d<|jj |d <n0t|jtj!krNd } |jj"|d <n t|jtj#krfd} nt|jtj$krd} |jj|d<nt|jtj%krd!} |jj|d<nt|jtj&krd} |jj|d<|jj |d <|jj'dkr|jj'|d<|jj(dkrX|jj(|d<nFt|jtj)krBd} |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-j0r|jd|jd%||jd&t1||j-j0|jd'|jd%n|jd|jd%||jd|j2ri}|j2j0rx|jd|jd(i|jd&t1||j2j0|jd'|jd(n|jd|jd(||jd|j3rd} i}t|j3tj4krd)} n|t|j3tj5krd*} |j3jr<|j3j|d+<nNt|j3tj6krd,} n6t|j3tj7kr*d-} |j3j8|d.<nt-j9d/t|j3|j3j0r|jd|j| ||jd&t1||j3j0|jd'|j| n|jd|j| ||jd|jd|jd|jdqWdS)0Nr!z r rrrrrrk)rrrrz icmp-blockr rlzto-portrmzto-addrz forward-portz source-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'):rignorableWhitespace startElementZ characters endElementrrrFrxrIrKrMr rRrTrhr:r=rBraddrr}r$r%r"rAr,rrDrrHrrrJrrOrLrNrPrb to_addressrSrrZINVALID_OBJECTrr7r.r>r{r8rVrWrXrYrZr-r3) r_ryrrrZicmpZforwardr`r9rArVrcrcrd common_writers\                                                                                        rcsPeZdZd7ZdZeZdgZd8d9d:d;d dgfd dgfddgfddgfdd?gfd@ddgfddgffZdddgZ dddgdgddgdgdgdddgddddgddgddddddgdgdgdgdZ ddgdd gd!dgd"d#d$d!d%gd"d$d%gd&d'gd(gd)gd*Z fd+d,Z d-d.Z fd/d0Zfd1d2Zd3d4Zfd5d6ZZS)Ariirversionr!rrtargetrFrIrMr FrRrnrKrTr= ingress_zones egress_zones_r/Nrrrrr-)rrpolicyrrz icmp-blockz icmp-typer z forward-portr9rr"rz source-portrr8r(r)r*r+r>z ingress-zonez egress-zonezto-portzto-addrr:r#r}r%r$r7r.r,r?)rz forward-portr9rr"rr)r>cstt|jd|_d|_d|_t|_g|_g|_ g|_ g|_ d|_ g|_ g|_d|_g|_g|_d|_|j|_d|_g|_g|_dS)Nr!F)superr__init__rrrr rrFrIrKrMr rRrTrqrhrgappliedpriority_defaultr=Zderived_from_zonerr)self) __class__rcrdrs(zPolicy.__init__cCsd|_d|_d|_t|_|jdd=|jdd=|jdd=|jdd=d|_ |j dd=|j dd=d|_ |j dd=|jdd=d|_|j|_|jdd=|jdd=dS)Nr!F)rrrr rrFrIrKrMr rRrTrqrhrgrrr=rr)rrcrcrdcleanups$         zPolicy.cleanupcs"|dkr|jSttt||SdS)Nrn)rggetattrrr)rr)rrcrd __getattr__szPolicy.__getattr__csB|dkr,dd|D|_dd|jD|_ntt|j||dS)NrncSsg|]}tj|dqS))ro)rr]).0srcrcrd sz&Policy.__setattr__..cSsg|] }t|qSrc)rB)rrrcrcrdrs)rhrgrr __setattr__)rrr)rrcrdrszPolicy.__setattr__c Cst|||||dkr2|tkr.ttjd|n|dkrz||jksX||jksX||jkrvttjd||j|j|jfn|dkrhddg}|j r||j j 7}x|D]}||krttj d ||dkrt ddgt |@s|dkrt |t |grttj d ||dkr|dkr8d|kr8d|dksT|dkrd|krd|dkrttj d qWn|d kr|rd|krd|dkrttj d nxd|krd|dkrttj dxR|dD]F}|dkrސq|j j |}|j rd|j j|krttj dqWn|dkr4x|D]}tj|d}|jrt|jtjrd|kr|d|dkr|ttj d nxd|kr,d|dkrttj dxR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,|jrt|jtjrd|kr,d|dkr@|jjrttjdnt|dr,|jjs`ttjdd|dkr,x|dD]8}|j j |}|j rxd|j j|krxttj dqxWnv|jr,t|jtjr,d|kr,xR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,Wn|dkrx|D]} d|krnd|dkrnttj dnd|krDd|dkr| drttjdnt|drD| dsttjdd|dkrDxD|dD]8}|j j |}|j rd|j j|krttj dqWqDWdS)Nrz'%s' is invalid targetr=zQ%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %srrANYHOSTz'%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)rr)rr)rr)rr)rwr rrINVALID_TARGETpriority_reserved priority_max priority_minZINVALID_PRIORITYrq get_zonesZ INVALID_ZONEr-Zget_zoneZget_zone_config_dictrr]rArprOrPrrrrVrZ) rrrErtZexisting_zoneszoneZz_objr9r_rvrcrcrd _check_configs       "                           zPolicy._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|njd|kr|d|j d}n|}t |t krttjd|t |t f|j r||j j krttjddS)Nrz'%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.)rr check_name startswithrr INVALID_NAMEendswithcountfindlenr rqrZ NAME_CONFLICT)rrZ checked_name)rrcrdr,s*      zPolicy.check_namei)rr!)rr!)rr!)rr!)r!r!)r F)r!r!r!r!)r!r!)r=r)__name__ __module__ __qualname__rrr rrZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrrrrr __classcell__rcrc)rrdrZsr        ^c@s$eZdZddZddZddZdS)policy_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrr@rCr[)rrErcrcrdrHs zpolicy_ContentHandler.__init__cCstj||||jrdS|jj||t|||r6dS|dkrd|krR|d|j_d|krjt|d|j_d|kr|d}|t krt t j ||r||j_ n^|dkr|d|jjkr|jjj|dntjd|dn|dkr |d|jjkr|jjj|dntjd |dn|d kr|jsFtjd d |_dS|jjrltjd t|jd |_dSd}d|kr|djdkrd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dStjd|dSdS)Nrrr=rz ingress-zonerz(Ingress zone '%s' already set, ignoring.z egress-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')rrrCrEZparser_check_element_attrsrerr\r=r rrrrrrGrr3rr@rrBrUrZ Rich_Source)rrr`rr%rr}r$rcrcrdrNsf                 z"policy_ContentHandler.startElementcCstj||t||dS)N)rrrj)rrrcrcrdrs z policy_ContentHandler.endElementN)rrrrrrrcrcrcrdrGs@rFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid policy file: %s)rrrrrrrfilenamepathrr ETC_FIREWALLDZbuiltindefaultrsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_POLICYZ getException) rrZ no_check_namerryparserrfrmsgrcrcrdrs6        (c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|j|jkr0t|j|d <|j|d <|jd ||jdt||x8t|jD]*} |jd|jdd| i|jdqfWx8t|jD]*} |jd|jdd| i|jdqW|jd |jd|j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingr!rr=rrr|z z ingress-zonerz egress-zone)"rrrosexistsshutilZcopy2rfrr2dirnamerrrmkdiriorrZ startDocumentrr=rrBrrrrrrrxrrZ endDocumentclose) rr_pathrrdirpathrryr`rrcrcrdrsN             )F)N))__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r Zfirewall.core.baser r r Zfirewall.core.io.io_objectrrrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrerjrwr{rrrrrrcrcrcrds4        F[nL __pycache__/service.cpython-36.opt-1.pyc000064400000020377147205345250014021 0ustar003 @)f2@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Serviceservice_readerservice_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_address)log)errors) FirewallErrorc seZdZd d!d"dd#gfddgfdddifddgfd d$gfd dgfd dgff Zd d gZddddZddgddgdgdgddgddgdgdgdZfddZddZddZ ddZ Z S)%rversionshort descriptionportsmodules destination protocols source_portsincludeshelpers_-N)rrservicenameportprotocolvalueipv4ipv6r)rr!r"modulerz source-portincludehelpercsNtt|jd|_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) rrrrrrrclearrrr)r+r-r-r.cleanupQs      zService.cleanupcCst|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jjD|_dd|jD|_dd|j D|_ dd|j D|_ d d|j D|_ 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|fqSr-)r).0poprr-r-r. dsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1mr-r-r.r4escSsi|]\}}t|t|qSr-)r)r1kvr-r-r. fsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1r3r-r-r.r4gscSs g|]\}}t|t|fqSr-)r)r1r2r3r-r-r.r4hscSsg|] }t|qSr-)r)r1sr-r-r.r4jscSsg|] }t|qSr-)r)r1r9r-r-r.r4ksN) rrrrrrritemsrrrr)r+r-r-r.encode_strings]s    zService.encode_stringscCs:|dkrJx>|D]6}|ddkr8t|dt|dqt|dqWn|dkrjx|D] }t|qXWn|dkrx|D]}t|dt|dqxWn|dkrx|D]*}|dkrttjd |t|||qWn^|d kr6xR|D]J}|jd r|jd d}d |kr|jd d}t |dkrttj |qWdS)Nrrrrrrr$r%z'%s' not in {'ipv4'|'ipv6'}r nf_conntrack_rr)r$r%) r r r rrZINVALID_DESTINATIONr startswithreplacelenZINVALID_MODULE)r+ritemZ 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@seZdZddZdS)service_ContentHandlercCs0tj||||jj|||dkrTd|krxRdD]J}||krt|||||jjkr&tjd|n|||jj|<qWn|dkr|d}|jdr~|jdd}d|kr~|jdd}||jjkr|jjj |n tjd|n|dkr|d|jjkr|jjj |dntjd|dn@|dkr,|d|jjkr|jjj |dntjd|ddS)Nrr z'Ignoring deprecated attribute name='%s'rrrr!rr"z#Port '%s/%s' already set, ignoring.z$Protocol '%s' already set, ignoring.r#z source-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_attrsrZwarningrr r rappendr rrrrr?r@rrr)r+r attrsentryxr&r-r-r.rJs                       z#service_ContentHandler.startElementN)rErFrGrJr-r-r-r.rIsrIc Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid service file: %s)rendswithrrZ INVALID_NAMEr Z check_namefilenamepathr?r ETC_FIREWALLDZbuiltindefaultrIsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_SERVICEZ getExceptionrr;) rSrTrhandlerparserr fsourcemsgr-r-r.rs8        (cCsr|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd x>|jD]4} |jd |jd| d| dd|jd qWx4|jD]*} |jd |jdd| i|jd qWx>|jD]4} |jd |jd| d| dd|jd qs    (   mQ__pycache__/service.cpython-36.pyc000064400000020377147205345250013062 0ustar003 @)f2@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Serviceservice_readerservice_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_address)log)errors) FirewallErrorc seZdZd d!d"dd#gfddgfdddifddgfd d$gfd dgfd dgff Zd d gZddddZddgddgdgdgddgddgdgdgdZfddZddZddZ ddZ Z S)%rversionshort descriptionportsmodules destination protocols source_portsincludeshelpers_-N)rrservicenameportprotocolvalueipv4ipv6r)rr!r"modulerz source-portincludehelpercsNtt|jd|_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) rrrrrrrclearrrr)r+r-r-r.cleanupQs      zService.cleanupcCst|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jjD|_dd|jD|_dd|j D|_ dd|j D|_ d d|j D|_ 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|fqSr-)r).0poprr-r-r. dsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1mr-r-r.r4escSsi|]\}}t|t|qSr-)r)r1kvr-r-r. fsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1r3r-r-r.r4gscSs g|]\}}t|t|fqSr-)r)r1r2r3r-r-r.r4hscSsg|] }t|qSr-)r)r1sr-r-r.r4jscSsg|] }t|qSr-)r)r1r9r-r-r.r4ksN) rrrrrrritemsrrrr)r+r-r-r.encode_strings]s    zService.encode_stringscCs:|dkrJx>|D]6}|ddkr8t|dt|dqt|dqWn|dkrjx|D] }t|qXWn|dkrx|D]}t|dt|dqxWn|dkrx|D]*}|dkrttjd |t|||qWn^|d kr6xR|D]J}|jd r|jd d}d |kr|jd d}t |dkrttj |qWdS)Nrrrrrrr$r%z'%s' not in {'ipv4'|'ipv6'}r nf_conntrack_rr)r$r%) r r r rrZINVALID_DESTINATIONr startswithreplacelenZINVALID_MODULE)r+ritemZ 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@seZdZddZdS)service_ContentHandlercCs0tj||||jj|||dkrTd|krxRdD]J}||krt|||||jjkr&tjd|n|||jj|<qWn|dkr|d}|jdr~|jdd}d|kr~|jdd}||jjkr|jjj |n tjd|n|dkr|d|jjkr|jjj |dntjd|dn@|dkr,|d|jjkr|jjj |dntjd|ddS)Nrr z'Ignoring deprecated attribute name='%s'rrrr!rr"z#Port '%s/%s' already set, ignoring.z$Protocol '%s' already set, ignoring.r#z source-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_attrsrZwarningrr r rappendr rrrrr?r@rrr)r+r attrsentryxr&r-r-r.rJs                       z#service_ContentHandler.startElementN)rErFrGrJr-r-r-r.rIsrIc Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid service file: %s)rendswithrrZ INVALID_NAMEr Z check_namefilenamepathr?r ETC_FIREWALLDZbuiltindefaultrIsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_SERVICEZ getExceptionrr;) rSrTrhandlerparserr fsourcemsgr-r-r.rs8        (cCsr|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd x>|jD]4} |jd |jd| d| dd|jd qWx4|jD]*} |jd |jdd| i|jd qWx>|jD]4} |jd |jd| d| dd|jd qs    (   mQ__pycache__/zone.cpython-36.opt-1.pyc000064400000031307147205345250013327 0ustar003 @)fM@sdddgZddljZddlZddlZddlZddlmZddlm Z m Z m Z m Z m Z mZmZddlmZmZddlmZmZmZmZdd lmZmZmZmZdd lmZdd lm Z dd lm!Z!dd l"m#Z#GdddeZ$GdddeZ%dddZ&dddZ'dS)Zone zone_reader zone_writerN)config) checkIPnMask checkIP6nMaskcheckInterfaceuniqifymax_zone_name_len u2b_if_py2 check_mac)DEFAULT_ZONE_TARGET ZONE_TARGETS)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)common_startElementcommon_endElementcommon_check_config common_writer)rich)log)errors) FirewallErrorcsfeZdZdZd@dAdBdCdDd dgfd dEgfd dgfdFd dGgfddgfddgfddgfddgfddHgfdIdJfZdddgZddddgddgdgdgdddgdgddddgddgddddddgdgddZddddgd gd!d"gd#d$gd%d&d'd#d(gd%d'd(gd)d*gd+gd,gd- Zed.d/Z fd0d1Z d2d3Z d4d5Z fd6d7Z fd8d9Zd:d;Zfdd?ZZS)Krz Zone class versionshort descriptionUNUSEDFtargetservicesports icmp_blocks masquerade forward_ports interfacessources rules_str protocols source_portsicmp_block_inversionforward_-/Nnameportprotocolvalueset)rrzoneservicer1z icmp-blockz icmp-typer,z forward-port interfacerulesource destinationr2z source-portrZauditZacceptrejectZdropZmarklimitzicmp-block-inversion immutableZenabledzto-portzto-addrfamilyZpriorityaddressmacinvertipsetprefixleveltypeZburst) r5r$z forward-portr8r9r:rr;r<cCs8x&ttjD]\}\}}||kr |Sq WttjddS)Nz index_of()) enumeraterIMPORT_EXPORT_STRUCTURErrZ UNKNOWN_ERROR)elementiZelZdummyrJ/usr/lib/python3.6/zone.pyindex_ofdsz Zone.index_ofcstt|jd|_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_configrulesr(r+combinedapplied)self) __class__rJrKrNks,z Zone.__init__cCsd|_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)rSrJrJrKcleanups*          z Zone.cleanupcCst|j|_t|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jD|_dd|jD|_dd|j D|_ dd|j D|_ dd|j D|_ d d|j D|_ d d|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.cSsg|] }t|qSrJ)r ).0srJrJrK sz'Zone.encode_strings..cSs g|]\}}t|t|fqSrJ)r )rVpoprrJrJrKrXscSsg|] }t|qSrJ)r )rVrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSs0g|](\}}}}t|t|t|t|fqSrJ)r )rVZp1Zp2Zp3Zp4rJrJrKrXscSs g|]\}}t|t|fqSrJ)r )rVrYrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXsN)r rrrr r!r"r)r#r%r*r&r'rPr()rSrJrJrKencode_stringss     zZone.encode_stringscsN|dkr8dd|D|_tt|j|dd|jDntt|j||dS)Nr(cSsg|]}tj|dqS))Zrule_str)rZ Rich_Rule)rVrWrJrJrKrXsz$Zone.__setattr__..cSsg|] }t|qSrJ)str)rVrWrJrJrKrXs)rPrMr __setattr__)rSr0r3)rTrJrKr]s zZone.__setattr__cstt|j}|d=|S)Nr)rMrexport_config_dict)rSZconf)rTrJrKr^szZone.export_config_dictcCsLt|||||dkr.|tkr*ttj|n|dkrxl|D]d}t|sTttj||jr}||j krq||jj |jkrttjdj ||qWqWdS)Nr r&z)interface '{}' already bound to zone '{}'r'zipset:z&source '{}' already bound to zone '{}')rrrrINVALID_TARGETrZINVALID_INTERFACErOZ get_zonesr0Zget_zoner&formatrrr startswith INVALID_ADDRr')rSritemZ all_configr7r5r9rJrJrK _check_configs6       zZone._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|nnd|kr|d|j d}n|}t |t krttjd|t |t |j f|j r||j jkrttjddS)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_NAMEendswithcountfindlenr rQrOZget_policy_objectsZ NAME_CONFLICT)rSr0Z checked_name)rTrJrKrfs,      zZone.check_namec Csd|_d|_d|_d|_d|_x$|jD]}||jkr&|jj|q&Wx$|jD]}||jkrL|jj|qLWx$|jD]}||jkrr|jj|qrWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qW|j rd|_ |j rd|_ x(|jD]}||jkr&|jj|q&Wx(|jD]}||jkrP|jj|qPWx,|jD]"} |jj| |jjt| qzW|jrd|_dS)NTr)rQfilenamerrrr&appendr'r!r"r)r#r,r$r%r*rPr(r\r+) rSr5r7r9r6r1protoZicmpr,r8rJrJrKcombinesL                  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$eZdZddZddZddZdS)zone_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrN_rule _rule_errorZ _limit_ok)rSrcrJrJrKrN s zzone_ContentHandler.__init__c Cstj||||jrdS|jj||t|||r6dS|dkrd|krVtjd|dd|krj|d|j_d|krtjd|dd|kr|d}|t krt t j ||dkr|t kr||j_n|d kr|jjrtjd nd |j_n|d krh|jrtjd d |_dSd|kr.tjdd |_dS|d|jjkrT|jjj|dntjd|dn8|dkrf|jr |jjrtjdt|jd |_dSd}d|kr|djd$krd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dSd|krBd|krBtjddSd|krdd|krdtjddSd|kr~tjd|dd|krtjddSd|krt|d rt|d rt|d rt t j|dd|kr$d|d}||jjkr|jjj|ntjd |dd|kr|d}||jjkrT|jjj|ntjd |dn:|d!kr|jjrtjd"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.FrAyestruer?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\lowerrZ Rich_Sourcerrr rbr'r+) rSr0attrsr rAZaddrr@rBentryrJrJrKr{&s                                       z zone_ContentHandler.startElementcCstj||t||dS)N)r endElementr)rSr0rJrJrKrs zzone_ContentHandler.endElementN)rprqrrrNr{rrJrJrJrKrvsprvFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid zone file: %s)rrhrrrgr0rfrlpathrar ETC_FIREWALLDZbuiltindefaultrvsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_ZONEZ getExceptionrr[) rlrZ no_check_namer5handlerparserr0fr9msgrJrJrKrs:        (c Cs\|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jtkr*|j|d <|jd ||jd t||x8t|jD]*} |jd|jdd| i|jd qVWx\t|jD]N} |jdd| kr|jdd| ddin|jdd| i|jd qW|jr |jd|jdi|jd |jr2|jd|jdi|jd |jd |jd |j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr r5 z r7r0zipset:r9rBr?zicmp-block-inversionr,)"rrlr0osexistsshutilZcopy2 ExceptionrerrordirnamerarrmkdiriorrZ startDocumentrr r r{ZignorableWhitespacerr r&Z simpleElementr'r+r,rZ endDocumentclose) r5r_pathr0rdirpathrrr}r7r9rJrJrKrs`                     )F)N)(__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r r r Zfirewall.core.baser rZfirewall.core.io.io_objectrrrrZfirewall.core.io.policyrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrrvrrrJrJrJrKs$   $    x| __pycache__/zone.cpython-36.pyc000064400000031307147205345250012370 0ustar003 @)fM@sdddgZddljZddlZddlZddlZddlmZddlm Z m Z m Z m Z m Z mZmZddlmZmZddlmZmZmZmZdd lmZmZmZmZdd lmZdd lm Z dd lm!Z!dd l"m#Z#GdddeZ$GdddeZ%dddZ&dddZ'dS)Zone zone_reader zone_writerN)config) checkIPnMask checkIP6nMaskcheckInterfaceuniqifymax_zone_name_len u2b_if_py2 check_mac)DEFAULT_ZONE_TARGET ZONE_TARGETS)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)common_startElementcommon_endElementcommon_check_config common_writer)rich)log)errors) FirewallErrorcsfeZdZdZd@dAdBdCdDd dgfd dEgfd dgfdFd dGgfddgfddgfddgfddgfddHgfdIdJfZdddgZddddgddgdgdgdddgdgddddgddgddddddgdgddZddddgd gd!d"gd#d$gd%d&d'd#d(gd%d'd(gd)d*gd+gd,gd- Zed.d/Z fd0d1Z d2d3Z d4d5Z fd6d7Z fd8d9Zd:d;Zfdd?ZZS)Krz Zone class versionshort descriptionUNUSEDFtargetservicesports icmp_blocks masquerade forward_ports interfacessources rules_str protocols source_portsicmp_block_inversionforward_-/Nnameportprotocolvalueset)rrzoneservicer1z icmp-blockz icmp-typer,z forward-port interfacerulesource destinationr2z source-portrZauditZacceptrejectZdropZmarklimitzicmp-block-inversion immutableZenabledzto-portzto-addrfamilyZpriorityaddressmacinvertipsetprefixleveltypeZburst) r5r$z forward-portr8r9r:rr;r<cCs8x&ttjD]\}\}}||kr |Sq WttjddS)Nz index_of()) enumeraterIMPORT_EXPORT_STRUCTURErrZ UNKNOWN_ERROR)elementiZelZdummyrJ/usr/lib/python3.6/zone.pyindex_ofdsz Zone.index_ofcstt|jd|_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_configrulesr(r+combinedapplied)self) __class__rJrKrNks,z Zone.__init__cCsd|_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)rSrJrJrKcleanups*          z Zone.cleanupcCst|j|_t|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jD|_dd|jD|_dd|j D|_ dd|j D|_ dd|j D|_ d d|j D|_ d d|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.cSsg|] }t|qSrJ)r ).0srJrJrK sz'Zone.encode_strings..cSs g|]\}}t|t|fqSrJ)r )rVpoprrJrJrKrXscSsg|] }t|qSrJ)r )rVrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSs0g|](\}}}}t|t|t|t|fqSrJ)r )rVZp1Zp2Zp3Zp4rJrJrKrXscSs g|]\}}t|t|fqSrJ)r )rVrYrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXsN)r rrrr r!r"r)r#r%r*r&r'rPr()rSrJrJrKencode_stringss     zZone.encode_stringscsN|dkr8dd|D|_tt|j|dd|jDntt|j||dS)Nr(cSsg|]}tj|dqS))Zrule_str)rZ Rich_Rule)rVrWrJrJrKrXsz$Zone.__setattr__..cSsg|] }t|qSrJ)str)rVrWrJrJrKrXs)rPrMr __setattr__)rSr0r3)rTrJrKr]s zZone.__setattr__cstt|j}|d=|S)Nr)rMrexport_config_dict)rSZconf)rTrJrKr^szZone.export_config_dictcCsLt|||||dkr.|tkr*ttj|n|dkrxl|D]d}t|sTttj||jr}||j krq||jj |jkrttjdj ||qWqWdS)Nr r&z)interface '{}' already bound to zone '{}'r'zipset:z&source '{}' already bound to zone '{}')rrrrINVALID_TARGETrZINVALID_INTERFACErOZ get_zonesr0Zget_zoner&formatrrr startswith INVALID_ADDRr')rSritemZ all_configr7r5r9rJrJrK _check_configs6       zZone._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|nnd|kr|d|j d}n|}t |t krttjd|t |t |j f|j r||j jkrttjddS)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_NAMEendswithcountfindlenr rQrOZget_policy_objectsZ NAME_CONFLICT)rSr0Z checked_name)rTrJrKrfs,      zZone.check_namec Csd|_d|_d|_d|_d|_x$|jD]}||jkr&|jj|q&Wx$|jD]}||jkrL|jj|qLWx$|jD]}||jkrr|jj|qrWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qW|j rd|_ |j rd|_ x(|jD]}||jkr&|jj|q&Wx(|jD]}||jkrP|jj|qPWx,|jD]"} |jj| |jjt| qzW|jrd|_dS)NTr)rQfilenamerrrr&appendr'r!r"r)r#r,r$r%r*rPr(r\r+) rSr5r7r9r6r1protoZicmpr,r8rJrJrKcombinesL                  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$eZdZddZddZddZdS)zone_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrN_rule _rule_errorZ _limit_ok)rSrcrJrJrKrN s zzone_ContentHandler.__init__c Cstj||||jrdS|jj||t|||r6dS|dkrd|krVtjd|dd|krj|d|j_d|krtjd|dd|kr|d}|t krt t j ||dkr|t kr||j_n|d kr|jjrtjd nd |j_n|d krh|jrtjd d |_dSd|kr.tjdd |_dS|d|jjkrT|jjj|dntjd|dn8|dkrf|jr |jjrtjdt|jd |_dSd}d|kr|djd$krd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dSd|krBd|krBtjddSd|krdd|krdtjddSd|kr~tjd|dd|krtjddSd|krt|d rt|d rt|d rt t j|dd|kr$d|d}||jjkr|jjj|ntjd |dd|kr|d}||jjkrT|jjj|ntjd |dn:|d!kr|jjrtjd"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.FrAyestruer?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\lowerrZ Rich_Sourcerrr rbr'r+) rSr0attrsr rAZaddrr@rBentryrJrJrKr{&s                                       z zone_ContentHandler.startElementcCstj||t||dS)N)r endElementr)rSr0rJrJrKrs zzone_ContentHandler.endElementN)rprqrrrNr{rrJrJrJrKrvsprvFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid zone file: %s)rrhrrrgr0rfrlpathrar ETC_FIREWALLDZbuiltindefaultrvsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_ZONEZ getExceptionrr[) rlrZ no_check_namer5handlerparserr0fr9msgrJrJrKrs:        (c Cs\|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jtkr*|j|d <|jd ||jd t||x8t|jD]*} |jd|jdd| i|jd qVWx\t|jD]N} |jdd| kr|jdd| ddin|jdd| i|jd qW|jr |jd|jdi|jd |jr2|jd|jdi|jd |jd |jd |j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr r5 z r7r0zipset:r9rBr?zicmp-block-inversionr,)"rrlr0osexistsshutilZcopy2 ExceptionrerrordirnamerarrmkdiriorrZ startDocumentrr r r{ZignorableWhitespacerr r&Z simpleElementr'r+r,rZ endDocumentclose) r5r_pathr0rdirpathrrr}r7r9rJrJrKrs`                     )F)N)(__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r r r Zfirewall.core.baser rZfirewall.core.io.io_objectrrrrZfirewall.core.io.policyrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrrvrrrJrJrJrKs$   $    x| __init__.py000064400000003074147205345250006670 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2012 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # # 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) direct.py000064400000036740147205345250006411 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # 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 firewalld_conf.py000064400000032774147205345250010120 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2012 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # 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) functions.py000064400000011171147205345250007136 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2018 Red Hat, Inc. # # Authors: # Eric Garver # # 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 . # 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)) helper.py000064400000020263147205345250006407 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # __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 icmptype.py000064400000015244147205345250006765 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # __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 ifcfg.py000064400000014345147205345250006212 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # """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_object.py000064400000032422147205345250007065 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # """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)) ipset.py000064400000051205147205345250006254 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2015-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # """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 lockdown_whitelist.py000064400000030647147205345250011053 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # 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 policy.py000064400000121317147205345250006431 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 service.py000064400000031325147205345250006571 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # __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 zone.py000064400000046600147205345250006106 0ustar00# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # 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 . # __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