PK!Dv 66snd-rawmidi.ko.xznu[7zXZִF!t/֌6]?Eh=ڜ.+ɒ s)q9 y\2K֠'v:F xd?ASS=tpOC)OAuBf`nŋV D!Jtw/R;oOz/\fz#sPˡ >RݯlqWh5ww|6na;1 ?[1pQϙVfJ Wgy/ =J;9@f ~ڒ۵MNFiuÐ=HITڬ@ܱpXQ eYcwT@CIv-j<%[aX)ߗf܎`1%~0jL# O/H!ϯĨl_mNK{U B0ڷ ЀkR u!;% K,.!(p.J=:N Uaa( 5AX[yi{jfɐ\Y%r K?|;u|M>\ͩn>%gW WIPr /k"v? d"$I@QhDRͧf*g\3ŀOnRHe?qm0u o`{KGC ař}IZZg ة"mK)]‘„}g uEW4?^@QݓbY`U~)J9FGkt} {kzݲSlҲ'bb_w1 P܉ʩRUsl%1mbo\G4t+/zƂ9q 3VqDr1jp) gw" ZS3H)WiVZw$Ƕ ObH1@`|}#ΎH~b.β|"J+QH>iW2gnܜ^lplʌ.|>*١"Sdz` a_VA )JJǘJ+Z)dky5y. +zV8rW}BX@'#7ZN /ya]n2% 4a4E$XA3;#CV4|g&8 $ !o 5xIv&|v)Y''^6̺U 95r(? 3J}hC0?-~wwщo^ଯ(M k=Tз!^?h:ܚGO1Y(/8Y.CŇ*ON7*m`Uu]͛ruRګ "ZƂvvh9~9@NULF]n#ǜziăeL v^qIx{ZR4^m;jt^#X7v2g΁#ht3 qo?z9Z9u#35j b^jV@isFlg$'AbHcΙRTcm[xߋf2g?g[iF :CYUX [H6]2NxP\'-DŌm vOү /k~IylX# ,) 47"0MC^y6W40:[Aq W9txX~KݖP߃-(+x#\l]X̠2Y $*&ʌs-їkm8jI S%f˶X9"۴wiW,}Bk <"m܇#DsӞ 5Naors1ptetpw1/-XR~&b,wq,P- ](-50 S ˌufQN䵏p1Rr~lEK rZC;V=/].wI {N/{%~)(:lrQcC-f5ht76NK"̔DSB!w*Nfp羑:V6=RVU_ >LØ.rkQfE3;/*ͨ8'(+Dax-e'H9j {f4o¶P״Sz?Nu P2$½oUz }Kli'+>R/W3;5t;=})UBwzk.\*ooIvhQNnAܚH{Dzr]׋1!Bo #r'[Lx?˩ TN 2Q$֦{LW.W͎Z՛P?pbtv^ 贞6lG{#D.%ؠSar$JB Co KPA;9BhBi8|`fZ,d eF+.&A%[RP ^¯?9W"JΧvfQFm"mpQ䣍7`$xX.$r_SS)vDIA!I?k4nCAWT~~ʑMo{>ϞXaяk Hjw%`~2Rc6,0*_ĺ'FOrc5ٮ#PݎSi5EU ϹZMfzXo<F>ܸ*y. ћB<9-Ž8glBߤcOXpvp5:`,cؙ  :Y_HLmk*Shqy/nq.Gn<1g/{JL!w$ٍ>OWҰ FG;~^}(aV`+2*:i0İR JLօoqELJ7mHΛG5A F?3b W0l: Eջ?<- f &}^|Zc(t?Go[}ueHxrthųEn6P謁ʾۣy7Ǝ^fh܆JrT$iCv,ѾӟÑQ @x 3(.IV 1 ʘPѓ2aW5Ya/ͿZlmPӕĶ6L*wIDJV:O8!xc"ki|13W1 0_v^N \YA!7ŻX¼sRԟe.WRok"&7/ ÐIYz8f8'm #7w>$2k3}*Sh*=g{AG',Up2_C!aC3Gg/'}cg$-11̤v&j?Nb 튣`=›D9`%d R W,i<̎뫎,xy۔Ne%{i%S|:~͝gP])$.7 1#P&pPR_YKAL|A}0t D:7gb: Si,%M)ǐjYQl-3A;s-ռ Tj<fAҢ40g*Kx3#"!UwKS *pd̗ f"(Ld^w]FD$E֑-n苙Q(*˔24 uIf(RtWĉ CD jO&d49Fy.BY0Th)7U*spEhl,豬a] [/$RY!q ',eG?ݭ_U#_x(j{XK4إwLF'-8u?1Z&WbԂ8~ JU+ki6>)gLq|,b|a{Y? 3-ז1A~D+Kg)Iz-!Z ?r,H1f'\l2vS,T0LLM:Iz/2Ow筇FΒhJ=pG@^l{"=#;_L cZdV40H]RX giciC}0wXq`p"6K RmS)qma3!xd酻-Fv*%^=m֤;VE R+ !xlܐ} ʪF l#ѪD.tyrW ?O DɟҞZ+O.!X/Źyȍzt½/GxbLo{? Ctj7)[٪4߻]?"hPLP Hg.ՉΗs 㪖4+QYH@ H?R.@jEzHI&uNE[˟]MdQBt1'~o ǃK:lS8l,{kY3F~) R0SI_jRۮ;c440VƱ۲ыD $#0 _ j&~q$x +``}JeCL.4NnB8PS2FoDf6uA`ESN=4C<2 qpDėDzVn_0? PE[ ֮^׼u-{9k\1F]!(?X<!i8e#eX#p]"`Ht9- x>aW@` q-%#kJzYꃔBN6  *Xh_ɍ ?S>pJhpTxOx_'ZE%uO@3YUeYyr%>q0+AuwOЍ#oeA\s59H>!t4P珯{r$UsEEV/0bgU&$tr4,A WMQm.5yfc{id-)JWVa?Ōp#ܷ,?5%ȂАUj2c >B&*jrʿL7ZoG#NA$Z`Ńgˑ 0%`L%4=+#$ Mv˙͆U Z6zL3d68O<̄0/(vWWͩ%In*zN>+?ޕ0`"]ߒ"ItS 9W4Q ̽m#?:?)"l^z`Ϙ߃ $u&"Q0'igA͛U:L-յ+`|' k[=6ÔId̀Rj~'SB fi;ƴ~!jRY$@ȧ3f[-O#ɝ.Lmk;lQ O-WХI:Ci=-n|eM%Eghc}?r`T9uDJWu2A؍`N:;y(l *+vqى:Q/~׍Q+@6ϷJ nFEvwEꞒ)e[>xToaWՁORߡw ,F' l8 sy7?mT|A-fxh+z]W#FF'qsB˴i";"CK:2 +Cy,Z6eiH_ ێX*~LF+M#Ɔ Y^&>6F{ZM_kcAQ 3;wU rFp6-7\HjA2P[q6W3O䋲%!?;ٻp Ф9ᥲɬoj۾s, }kݢEN ̙v_O7Z0VW$ ? C20/0Ve_ݪUMrn7֤VJ_LJdԾeWjhNM'˩5xvIyx)%l&o@iֳݧ=.L0}#؆Ǥ /Rr% N@ߺ%{mb sXh-ҊztaM$KjI$ Miv [#(]Q)]<=>^Wux藎AYd8,Vr g1W ZMny.H x4ç/f5puzFVJ!Fw|7 ](BrJ]x o^XX!`Z䜰}#E^ Mz5%h{6Jɪido1>ԭ6p0\*N1& ͱ cHG4|䕚>~5^2p0bU lnHhgޢ"-WG.InG=M:I.?~*Qɢ뻧9D n9XɛYa2kŝǿ ȃ3|;ٕhK}t3:Ժ2hπ> ~鮛PԊ:6 5]OeT7q5-`UYY7F3f \Cw{:t[XLnauwtZUyL/- hU}𻷚;@=&p J,̈UԻ*tς9;4@j֩,&4$A A2K؍A3˃8Ҡ[KXRUܐ5HV.w-'' ex%05D%9&*C!)zf!DZצWQށNjkx_)a$+j!iH"Z>/kr+M d@!$aQܞ {89_4/ Ƀӄ?G_;^١`4~-;C_)r5,RXT:d_Oć+p$˅H<''H/YgA-lv-_t72/DYvѼ{ QN[Ie݋.ͮ5rR;z,bpV7vp#ðoCLK\xx76yPJC_g2D-Bټ#08\{ )A񢛎3>E|JhxKPñH~Bt Ad`7^ =ɀEKk("kk^vA@K~("Lt<ሁ3%sB ӏ]gIQM5aE6 m 5=f6/ dy%gyAy<68gcJ[=Fy [ҺPdq#rxuÒ ]yp&9FRDt%1\}d-r xCx+Y{Z!0p* Zƭl9b[Vo^-3JR뮄W;S(QR<vd~sT~P3hlPࢋl'm=%=H#rU=!eóO8}4H9>QY*wѰ6^@!;HR5FJOn(pꦓ=NWOTt+Dr6c3*@XtKo|:&X9v)^UIo͑oO?XbsN]:M:48Dc< `Xbb77PydljKr:rvd9"efwM5K"MIf<[`לO]!QY˜OnX1?k;{{+S?c>ᤇy+8O-w/M.|1,0PsVf*o$8igt (8|ۺeo2?I?3oDg[,co}^c93rwk05rT=8&9e# Y/`gS8 Ɛ7%/P$EM/% V0u<&ts|}EBꄃ7,ƥ8#{6QZLJv+79e;СX#/'ʤ 6k$ٯ >l &7$ǡ{l!GA%MȹB|z۔Q20jnor S #J]-NϿ(](FI y[M69l*ܑSk ȎҶ7 piG= OjߞszJq<`=_G!3b~α  a >";4(`G??C7 &m;܀ĸK ܊O*+ܿ9N:%)FlفQ9eVbPi!ĝJbb6q;siQt/zlJz)&v2X4FYO\iWq^lۢo)pl$O>)%Y b@,av&Pzn$=M, ^nN`rN88Ɉ/CՀL,0߳AںETm%8qHTro Kͻ$1V$1Yda@,ؽ8A/* 菭 3(ꕞ53}s GhO(֜py8.`:';vMQe4tq"D͊>qPD:G fg@:_\ļ*ϧ6[@|*F;4hr) `U0<: 6Lb6H!`g3cl6\b/ZT }/ [yS\.R^rd˗9hIU<﬑O˯.Li":K c,jS2}Rg>yHnRTB*5Ft䐯(էž*^C?YG=[l;v)XY`&1Uc0'o-U>62NA*Y4pZh3c$y JR6 -J`8/Bx)Dk *&\;X$|L`"HToe.9G}z3NƇQ@`^0kW-O@DX5RmtIu=NJEChِh !sdNk#6`]l; 'O͇bh.c+WE #{ A[D1Dfۙ&͉c(U baGF.8_!a+xh3u< |(W8\@݄9YOH.AiRK&)E%V宅4 j~ǝ,<*S6cwX?$nZݦKMO*%~U(p.@OD'.ݒha49Pʤ39R&Z|:0*G̔uœK$;?Io(1ydoJURHaeiu%ȱ=d M|Ϭf e:S]军nχW[_'Zu] 14pq(~o m(dY,JQJE;3 XcKi3,XMYsrYJ6|g@Ē un-gW}U6MXʇq8J_WVy|WO,jP~.)/'eQ޴v!PW){N Ip>mU>c^|KT幁NDaxrLΈ 0ӡfbnAzFUX7iRq]A2QI<,DGcםqOG&5,FR#zw^6p`]ٿao2r3d$^Ul_m8^$цtq\ˌ=/nb Q$vd/ԐN]$6LmRg|6߸Xj&;V78"0K'K1oeړNUݿD5]"HںT *I|̌*'sTR.`ٵmvj*eK½כ?4Y HP*5]ˍ"n ,Ist ^ ^y $t1Z}PWrOAT),'SNR!pt7}ma'1! `a]7 Crc,M|jt@א/ʌMPo.53mVm\yv7Svs2%f%fBLcA,'-n޳T$ d좙 E=,M; {lU5h`2-w+$@zK2{bVu=i-\ wL?GL%ꕿ!u 3.߇λ/_mkvY +$%.Vhfd$#Z- -OJl%%iJM{f T2ulFdΨ =!Q'"In^Tؤ'=pS>ux'HrlE{"5G]"T6]Ul"W~If- G5NQę[cbgEL9r#޺h gx&2SWn4x=Qh/{]OGu{np5:O,7CLD-+"("`伎N';+FU|J`Bxp;/\' }~U}slt1jYLƵIqp>c5dDl1O?&Obv G$hGp 6!!7 $M#`'Ax'nt0gpzg3̀Z|Tպ &8Mt#=WO,f'whV;W őÚSԬX-k][Y=řΰrq7b;pL8c]pn%YFUTXOYm#=(BTGܽ=|`oQXD]L;G` 8+&8Q jU<޽(sR%ry}d&L9*%^LSrD!@3M*=E):CG\7hj"NHʴ檴/*_mI4Npn;P@R/^|@7r&bH$ɸಏzi?6Vb@:m[ !V G^ :1g3,V!M.?ٺ򬵢Ogߩ yIC$%؏u^ە_l` Ipd}j5k698F2.j`0טу*%m+ 6G2wW%ϻ} oUi S8V,OIu|^RSG?I:2;,?*=q O5 m%FH Z aUނg:,G#& FNlI"b‰X fK`q0ܶ4 Ae♉nҹ{Ŧ}/L 2`}u7-QqoWNa=~P |HNXAJ7][adxۃpC|R^jwĿ &Mfڹ4K{8h,<$^.myG3 a\D;w);^ug]!z#Z~`Y^I/AϋwZh&/ )i9۞8)zzEoSh{PΓ&y ]UKQryh܉4ރCux 6&c؂b|ᏊS('g8$h+hkZ|֦\ŠU/ֶN+ԽOhDGc*tiw8G& @({2 36!ṍcpxdC'oYq[钑4hwhn[tYֻ0RBo^(*Z1qOR6.htwW?^L&z@h]JdaaˈZ֛Q-f1̦;ij|L *즉 µkLقK|[Ȝ5ҾsHZ FڌZ`ĹO ႜmV֍-;'s_O̬}c ݧ9E)*Z̲D|iv0>>P4$}dt&&F\W+yxj _\ARӀPHa=}WRՍV"ؖ r+ؿb&,sK9d"u;Hxð}n+X JWD~;#:jEuW<6 $ͶSk2z3v<_#KنTsldT1 Ş KZFKR8XfЩolj9 6M`s 1 쫻/FGW*˽@}hA ~[@mqEo+NEo 4c ~a)Yi W(́! a韓),a{Î.qh sF_ 3QHqn7;jgToOF܊TA4󰛻sRs:jaB3YAN?wBd%ۿGpLFq})42EX*`'k?:oA_HPųHks(3jNOcB^SԡKwAԶ[.VN\E`%u$ 5a+ɾF6]f^'J͉ÏlD$Eu#iWW\܂As3j.Ms*`nmA9^rAbjJOHlC]쓕)B.P>G48!HbSqΌdUSPǘPd11@J +SZ}@iWI! $}ObWe^0fesBfp| nD~2kTT1 3/rO M.|z?E[F-Q=0 i+F"y(K|@Rdo͗$.o zYQ= f' LY%lؐ}l9h| Ps4L` G=66f;aݷYɀѾTZ;^3 ~[Ɓ 6-LH]e8\_6CntʟiPr:, HN3uU&pskmy" xTECEeAuaU[LwŶu+=ݍz#{MhVdP3mE\t)QnW Ta?CCC~=iCJAr#L`TkK3>Y*fayGFP+AVF_ a{lW>;tW,/hS~<#zT ;j=_/H.]CkA [-ږ،K&c{9O! ΝZ[l)OG0Zpǵ;/Z*Q" ;gte7IBo.V8/d3KO/!0a v{`ZRki,9 =q*7NTN&mmճ:Z'욈բ;s ^vf eGAK = o.˨̓}@8gC&)&ضyA ~ՎNSUeM/.v~+1R6'>l6V6c=MBuB3ANÛw%%~s̄tG F -Z.&oi9uЗ6TTp'wcŶ0 (,z ٜvHicRGV={TW 3Ma"mCo!/}c^wo)GkKMHCbVOq@! 9N}fVesȺ\hZ%SWKӽ7Y SsLE ^,`~ J / Z ;NG):D,3jh*hjڄJ%kQ?Be|sd-OۦGV-AϾZNCrgKgFpPi!&Xoe#0lrQ5Ifے ôm"݇RTBwjكZ ӎFC)U@}Q!׹/u;t`"O΋(QvˌΑo.r[Qcf-baф*+_rd |C G\9#CH8w\c4?&/?6.6eVf p9d@ B\xF.p+`I 6\u>[àv|RpML?hK8ɢwUMdYձfHFq ӨV?4Zi{W+ Uz~Ӆ0 5R \(S (=EY,M}DY&Kk{ẻ1B ~d5qfU2:AxɾK 'lE{%9!EMQt5w_1y$@ v!ųT1kchhǑh&Rh0ֳqnGGaV߅ a@pwo}Ux=cA5,oR'ڠZn_\=YuX/Q7XC~SB/ h$SU~cK+y݉S;Ci1IGr&u5jr_j;#}s]4JB Z?5aWOu*c dxO.l˷zt+ GWtUj)OHѹT6-8k_ '`^J#uu1i/NwvFM>hvB!3̅,BiyiD0U1>';[8$V6<_Aj_|c"knvv-Wo.3JKX \C<}qoqx>0k<|0Ypi:IE@s.V;@y5qiQ0sqEfvj3UmNǤP9z+̠.D-nu;pzlA@1žnBi {oEc~(01iů<43jѭV./e v:ueɵOC d?w5xУ[:b- rNAIVQ?9_MLZ.a`? NSwA#R#qBf)5jȬ_.>26餌xs'! kzoNn0CVuT̮33K2H9?hx@F]; y/R$ l2AXln+L}a^:"{4YF4]ܙf2NRG+9{z 9lȻzlfN oXnMOI$ sS#l0îEqwD?2{ =iCMk~[*תQCm*ia崊w>C_/3p \@;)+*"ڍʗC+~u&n7TlQr|E%2"$L, %щAs1l}6^+6)NcNpݿ83m =+ ߽6e$5$u~'e < |& U/vp0Ũ$s{ `8]~:x_0xeMJF7 |bЁ2 ރ_[s&KrV:*~Ek7ZI5,P^{7eij,L͑*G 'Zb$LMxHbp6{ЬlL٫%SeZz8R %3jQV}`;jv7,Ц׎Fѕ F0䳄mԻ  /뾇20}O < R?Ln}-L Tz鉲dFWwlz,XMmއZh f׶d<4{b6I/ej⧂Uxa`7)2dW`|"şfu_ n~7[bzAWhtC[R$YKS?>x;R7mLM;' E!Uטs9A>۽;a^X/?E:F1y8}2H릩iFXZ?Eٚr,X;xr 5; 2']|QT@`N& ڬNc-TӱxiŪ綯oLMtVU HUxQܧY<iXAO`DdoFfu݆3"N@j}0Kc U̽o@A_/F'j1Zr\ͧ.e/7-1eEսlIK*%|eNʞ&x l]nCyĉgD8(hiwolԻPBCl@O44,O 0pk4PZ|2.6){PudO0x5aAZ,$_V[Y@dRK zyϑsmmCqћ<5ڶ4[{;fL}7c/8FjP(' r\ xdHJ]$ϦiT\(-SV}DɵΕVm_E&:nJ[}ƛ6A H"_:ϋ[dEUKMD%2t,`qXGMYjMJqχOIOJvem($3*8$,#G.:ΙuMXub&7 URK,;_Nm1;OP:u#a\g<. rI4+Atqݧ|TA4`&O ^aI^LPh>݁r0Ym*Wiruw)71&SMCV[9 æ%̅@,UR4RXf3AC4Ip9p* z~73o%< #:Mhs݁ N(z7$&OA"ކ~VF5#=ZmYA k6ІrWsU=tǦ"ۦ8{k9\1*.ׄ- \BD |V2d)X& 9Tw`m+5͡z}XײpNjX){"^W@FJԐEtSGd$s')rO$%WAМ܁݄p{HC~Ũ ?/ "s|>JF.<5Q#vG#{oٙE"XRluػi"|/$(,uy #V.#'fШYJqRz 0ws:MF~=E@U=e 5K&VP3//(6uA45v{|?ݣd._=rfARV,KDپԊ@^]˟0u 049-S"T%.ϻ]uAQT.4*v)?zGzN|)'o_tl0{x)?1Fuf*c^f, Uldo{{%0j?7Ѐ\~9AkzO#nk#TxD}je""U݊- P:[8puF>{ 8TUf"61%!HI¶Z񔊦K6Q篪'wasioP>z+DPSj{( n"uIhat17qvVt$E>L,PcC-DSӥS#` b!dfN9QG"!c`N_G8v3"fYZs J#%pM  2Ë' D]i#cHx}uFO Lw=S9m:B.b0p7i*gǙ=w{39ԻEҫ|Y^רme*(oQ2wYPQ5>'_I0H2`e: y"~hPe_[P8SRk7|U 7x WTHa6M8_V$- Wٳ|Qf#UT.O&̔O\ٺ:diZ|!&(Ojݝ+J-_5q"әȅZC:f?o8+FO0z#QV;#$r}1@)ߙ5bxH@$Yrx c|/0s|SUؙ{K.Э+OXh'=z|U=-Op'I& buD;OHQ:Y=4U֫= &J wΨ^i÷,\>;8HbjIQ/kn(4&J1Lf&H&9gC<,RvȀ%PƥȾDP5yf>| zbos#=7 8DKkj6@v܀3?(ƙu- 4q\ UrlY8w.IKފ?;1^XG1=oT֑%S T2*1?7Iϳ$Q3Эpޢ:4vX y-$'Q4Q< t";`w\? 嗒3VCNt>S  y>_ AH?{Sp "bm FAoOoRyU>[˧h;# ~6/iK/0V5b'qO^:L)_u͎.q3b|`A^'.~6GYCHOz-]18V@K/>I]BE'Az?.Ӳ]WT8L |pm(R>%-[dFͭ*؛B%B0s"#JLEsS/U[i'P";7s<W 8Yfix%, t38%lLxEiI ]^D?X7xqKv60봻3gF g8fTAIJ]K'7g>L)"y>/Th=dd5'O)L=n*G.%37.&jU)C-G&S}.Gx`O3AoSwj 3KǗzsԋ_5i)HIE'U/{rݭlE/#È0; .,:%AI7eG[{%ʽzi2 2RNi6ץ?l_lbPtp a"biBք[|JU0l)%W_I %U]NM>'ܗ)v1F9XϋD±}33JqJ 0a}ŀ&5l7ml¸%1-~[ _v 0*guF2&-tҤGZ Q` 阸LJ_Of&Mix ;6vO?5|gª53p]1ҚH\*. __W=&VaMPX؈yZ8$|́G)ZCԦ/XȞGhuRbgJZXV\G Eh5'&[DUJNGkypf-=Emx.y촜V8&f/xX?*g$i_BmBywb'sXb/팄FeE1`rݹk5ϖ0xT<]=q[U?xx` /OUJ n!G2Wgd=BlfSn5(y"z}EHiE#gF~pM-cX(Z{p5P ]e?-s_wl/EMyYE&L<_YhOZWHY3hwlFp+%030<;ew$XR%* _9.#u3%J(^QX)( g)Ja@/c)iG6C^H[k%5r@$nCNHؒ.Vmj$)iqab + 9m$3B#x}38 tTaV͓d$jp-ƅ]|ԯwI]S!ޏŌlL% p>!("cK>$l2:\ o Ĕ Fo6 a3է@'xGSU$&0@\SyhKqXxQg˜!$ԂJp>'hUCqI=Ll!Q'Xnx0# 7|ZQlT]8^sуo t&z-Y.N+˥2, fκ8' Qួm`݊^ߓ'xݫfs4Ap7LTRf"bǺ 7j ǹq Ų E0[dU#?eV|ɘ;dծl2Ȃ rQudm}Y] v%aF&N"r =R~ckܜztfML5T]$#0w*o+X>P cG(|!_cLρ,\DZQ˅ >Nh9c 9sF#@6 97whi112O_ ]+G8DBYfֺP,&J^8:Jh=kf^,;ap] ,4ĩc 1CFWƙȎQ "8]!UO0l=0Sߍ<;%;QDNa d?0[Nn\7f d")b,2ڍc9b2] W7 r}Ja=Þa%-{`1Z>a ԫ +߲9Ԇ}M,B:#vJ#l{D#޹{@/f*3%]|Y=n1i=!.B~*6ܭ7=7kYp~1;XV)3YcD)n?汰o^b.%68B A9Si4N vx#N发LnR UAMyV8R@ST2){v_0z6)HCk޷C.EMNc"_^|Ou~{\{L/ByF0 7{}$-=GLt {s;JrT`sA_Y'=yShߚt@bIQ ߺBhV; o;NO'.p d!@K;tAL~Xb+.{h75|Մn>٩ 馣}5<rWvS,v $C{BE.;{i>.๽H׋,1:⼒#J}a&KK׬{fa%XE=1X'O#ӤO ѿ&0=DP7{\y̮ Us2GQ,tK4B$ąs'dwx=ҝuW8>PBP\*&{ xANS&bO A%\q)@ sf0!15$h1=*~{_BW BCM= #$.`$VHfnjyh-wT\X6O'u_Lbm$ƙšaaOhkr!WnZ9# g,)r[`wlۣzjWM xRتzj n@.l[sm q.ywN]ϒ/(#h:>mӜ ;B?2IFQuzݥ.ǰd~7Y Jt:jVbX d{# g63жTmހ!+V%ūz@9O=%kg qth=ؽ8eJ?Yϯh]\DT%iٕNOH b\@xi0"/]JET`kCe :PRGQ^m ~=2g\B:gݕ(_X(-h?ІHNBsBd4֥x5~B\ZoVX_uz vw{IwV-\͉u_C<&ۯN I|ǐq /<]y^T?l=Cd%Nv|@!dGD86,C}q\#/K.qǕNkN՟G!č@Q"]?~3d4\"ِ;DcrV//J`"yZAiHA7svzL^&i#k5m'_q]ɂh5HG/sU*^:7:1>j2cz Igt’ ҅pfRSgo(lY$& uے)}%$gNΞZh 0:K@&UIex >U C֪@r b'D0VFs\-Vх{xRͫKmi(QVdb5u}cƞՑQX1RN"4ώ)5{O:\Zib\V:L [:&ix(=9^ChㄑńVKb`ERV%-Р,z73SbaHY7LF^O rd0q=y@x[KlJN{$|?rƧڱdm𒐈.7DϲoYcp\x>O]u=_~whQ^RճT:uIz%)m]ꆘvrRYc VW_&t~.lw Y/ $g[rr<+bH7+C"`C/ %Aëd\3m6r::' PD|V49[A8Xu 6"S֩Ӓ dDc8dz3ޥ^T[rZe;u xCDlyѠ\d\?d|DM4N!PMjJhA4j9| r#z$B1EW+@K Á7|y0d3mc rK}ZqYD 9t'$gd*g@kYS<^-ĝ91bA$3YK]L`g`sḶ/}\c@-L IV % jKQh{_-H)_ӳ{m`A fA+(3^QvJYv;}awNSixE/^"N\.f:S/U6l>t˒*I {&fb"8zLi>]QRY*i#Ⱄ03-B'Os7gD!s~tp<;'_X9mt,PB2G `>]iL?"WRpw'5>ׅ\j̵z:Zz-$8( c&Dm+ Z~+S8!VI_Ei0U2Qղylw+?:;wB)f.#80Zeb̤YMd} :V 4DWa#V&~W~|:2 Xh焤G:3C7dSt{ڷn\2X4R>y.2t|-1V ~OKd;ƨ>4y X P%6ɻIH 0Zepk}Op (1STUD#@g8ɔ2MŇnZ^URAuY =pao)8n$ݏhaPtJl:d*tQ=~D4ы: o[N6v@ϭ 2,Avɒ_nk.TH+R al'd&U=,}ϲli^hB‹bJ#RFէ fuA\[/[z-葖~4GBFLN9SWŶJeNjG9쀧D{4_8q׌yW3x ;8"9XբX&g0:ySp8" !!Jg7TE%Aǂ٠aͳPX@luHvylyխd+h$} WeKy>CV )>*"ՄsAxUltp˅%¦A0q=y$\D\jpn^Md ]~MNe)ֲRR:u99Bݣoss{G4՗)s8ĝ􀡳Əx ۖU| {G<]wgʙU|0LiNDGGnIJD.b({WμJ;_l{S]S6gAg輨ʲWۆCvX91i2*trB}˷ȴ^`)r0<:jkI=‰lwX(!~H4"ra[)`)n=#D.pWiMӌj%@b&.!Dq1hϦ|pGȄXs 1.U H1\6$hӊ$h_ En^6;&^(z['mwW%.|.$2P8҆>]`,ѮU8 Vה6&_0ްP44TCN{}$V(g^)tB0i % \Z ta%~cY?=~kSIxSr1cB7C!r_\32 آu?Ŵ&.Dw Ek Qc9dA1a+\'X3cL]2쉥d؀?ݛ{ń\>"GR6pQ9ůzGH*V|DEVT<W )@O^G`FJIk]ɣ;&>82K-i Fӽ7 ]xHǾpS's[$qaTŴh{PwZ._?cٞ^_G_}վ\U`h(+t:cOg+Shk$~YKy!庹!S?]v} Gc~Nq"MHz6QgĴ8w drԪ2n-x%YqH->؇$eLGۭwGSpdL h%[޲pXYOsڪ5@.bp)LRc#ثR]ovdeQACAƭm c4{y]E $J _/Tgikg\/u)T8 2.+81 [6zKm1|ZzMR!v]Zd@Jь8F&:9UJ"DTԖ[⥳ QrК8!}i>,K6&OYyh ZlH Wn֑KXWO.~W! z)Vq~&2eCY@㴕5]%N9l7+,n'@..NQ.\i=ZL Y i:(v+`3!?,W;Dq4%9AE+xY)>NЋƹ(Y*Die!:@YT"RlcqjHÛ;"/>Bԯ;d lv7l{hGF  Z!ݨt&s^d' L ʏ_A%qK+ǦUj*a!|Fv! ҆o}#P%Fi BbL#0]ʿBʨP+ld+{>=#'K[+Yx tXwTՔ+ i p-Bs-kW"}-)1ݾo?RQXi8I7"P6nf]C}~{Ova^qK>Y]~MQ%!6]ef !E):`dgo+%veC9)ftꈖӑqڟ[ɤ8g8g7w6S1gwYKJt4{I0iBRTU뱝q/<P^u>R {ӯ,ABz\qADp@<(r0(ѼcӉΌk(ѻ'%F ePkED=:1&0Jk!Lf0h\m{[]MC>YXPp,,y J`.0Hj!ZAIOYʪ.F/iXq%NGy<13^\iͳ.˽ɕe6V3}A@˝sv\GG44SN!\|M/y}HR]sOLQMwrZySo6 h;#VrvyG{ߪ|LȹHJggD1ҕ٭63rp.j^̔POk+6#3*ގX**kWTcC(61\x} dӦsopسO_y-D^18ĕ ŚV3HRg9G4Ns6O|QH1G}t݃rCt?r ~եnl--7@*t&JblJFUvM 8ŴBA'6Ń3ӹ>{4giGb6I{B/˒PYǔtJPzs43J_#fK=v;`̓q )n5K34'!+{+VcqtvL1m{n%D-뎾@ukq+1(%$p>z WM;'"NzekM4O'nĀó+6IYwpXsw//a3U.OHr<3g7g)-W$ i>wd׵RfgaZd|_RSg%] @S/;^6RvjK-f_;7ZD 8GэoI㥛kל HoO[WUsc{d(ՁLNHEEڈ=o:Mi2փ]˄T7f&+ ͹\Eb\@S(ү B>Pvw1\ȺeO 4 /gV,2W7B\c=b8k`,링fyZS<(웘p]n8Bn"oI,x&=J7V;5njj2,?j(ŕ<0C>v;589KPnȠBt B$ce,{0@iJ"#Xpif!c9tm=kF]Fv}zr4OSV&5̣&%y{^ '|0j%+o  J[g9l~ 0S:xvH9a1d-1(޹ Du(>#޻qq ^Cʹ$04o| OԧzRCj!eʟ?3Ie+q ērgH= 쒙%)[Թ,;\wҮ_us^Ţ<부ޮ jT7=v4~|,08`bL*J{7T H,rJ,S31;nv0@ a_ L"WU3%.4q 閐3I-IO16A2noa ?bWk-akK @™yqMFA|l^=J 5ꫝ>%) @M׍a>"S~M8nc6Is|db*5ܷkgG1^+/?nyaT!`a28Bru$951c{ ">O(l҄7u9< pvWCgOo6+90#8~Re)( lЊMwP&&Ĝ]K@9051Q܌9~vE \\W?e VMȁ^ :(qM߉+^)( 4nWy|j#Ђu"km{W#mC7!0 w,E5:CS5tb@nm/V$ G-y!<3v"Z?bhC-1{8/3/7ڵMUF]x\JtRLՓro,k֚Fsf&DBA-\`(kwSڿ[HC2y ;Hr7npW$)V-$LۦPAPb ˴BFt٧3n5059S,VoNo%8 M`Tг WyUawB(#h_aUƖȖ(`#w[쫂$uu ^u_DacjTw(A~%C0(.SxRGY7Ȕy JwZu%? 4*9csPo;p a6*cyEZckl"Cg]1a|[jt 3ڢ ox_fuԹ}V2(Vw[ {g&O5q:3)P' 9Ilb_G'gaRhdeY;`NP~zކFHB&}TyH= XVtu>t9!FyE݄k|;P A-9GC8TVIU2:VEnF33X(.e( 1m~ "n"NnJC&c k+qaU*%Π M0XZ0\YۏgU`GO҄/ILh91=Ɩ8)gpQ% wM!a+66 )JAF'"rNS{^FzXh@A*jqA8&/rkT %dJVHIQ*N'p?x\4@^j#A;ؽ-b/ 10rM@ʁ;lƬL ۓ#YB2$[='O&BDD;x+NNܷ]Es SCv7cj5=3lN/}|Қ()"՛rUTDz|=_=S%V-(N;W]8){a< bqVmSu4}RoB4OzOj|JOL8ysuMtzrsBOi5E@EN28tw=wCC`I.(KfMdC#GN ң)q@(<0G?A NR63Ֆ7-jC43G=gLZ@TS HRWf%âfQ3vhZaXO/p$.c6ryʖsr}`[;^u!oF06ho-FPm%|Fe!0EFΛfSpQ-[D+}QYL߾t~KhJ4XD]B[mڢF~j wUkk9}y/aar+I2Y/:=݁ j:LBWMb E~ɢFŘ OHu|Xp/Ӓm  7]Hup- 0ذ*`!8UAjLܯnݰuh[[ 렢Jx'8bl2X6)<-vEUkA.!BjUۃ=&]hbA6զk䱧@jU[.ld3iIʅ,o3@ؖ56bYPT/Οu˭2J} Eb!{s1,} +f,\1F3YٲVuq`I[ VVm+ hDaW^E6}\OBm?jO ._wwgP -hdArO,KS_-ڨL&S˱EoP=@ȶ!)_+7Ct)˚ϾB dG..<8a`r(JVE= YQSU1հ^-I0_Ԟ@K-Ğ''ΊQd~4EoK&ol9H/8dF:$X=D#мZr|"Osd0_w+ŗ+>0OK1ּMEs>ndN.TRRO,aI?0(6KBTC^c{K3GW´~\o/q>ϲU)R: CD#+1Xq3[SF2x痿AYaR\ $NBt?Sv1mߟh<S<9QY|ΊKPh@!3̫q[&#zj+' Ă0Xmtka)603,Ų %Beo> q ƛ>_< x ys\9YZ^{28؟|nSilX[/3&9Y߭U3q FfnsJ ObjR(S8ӯ뱿17 V~Wr:sپdjf2B4$EShT z2JrFZ|Y"Qu2nm;١GpXur#k'O ˆhDF>1Nَ[tLGQRbe B~L;DcײpBiuԹ!SEʸ |o>OA?RG>"+q:fK^$9nǯPfVn‹bu q||^M%=Nd%U8Wms`"M扂Xˋk$"?.⅙At 1nrΖRۨƪszJi:NVU^%d]}bLg$ VEH60-NP/n]?lR.ؗ\l@k^g=3;rz{}ڗYӤCt꤄=N[qiFJSa: ՐeE {/lŊI`3#6ؘS־Uq`d 8ÅEpùM߆nV6܊Z4oK3 ?I]XnsU zGD2|kYO2V#kǠDK~}CQi,P*X=C0}OMxkR~j׹tNEE@yBUV|]C:icgFxjˉր~b6mYVV >ΠCL óH,tcǦ(sH,:Vz=y5DS/X#lXs"I VpYvlf5{ > y lS:>uE8vi$+WZ<ܪPRVRJA}-tK&;$;5#XAT~Tݏ"fͻs Unӿ[6zLǨ*؆rFЍ= ItEfNi) ]*6NGvQo"&Y I, '+CSr3c4L093AQ|^@b$.H}ӿ#"p l T>{g.Yv&Ctݱje| !O ?@U!#e&ѷ=w(܎lA?3f$[eLN6Iߒioo*OnltfƉl, ;TLFȋ0Fuԣr ͼj`wһ> 5(c%6hn5|MboMl.j}Sw,`\~}%wM)fTd^@JţӆPsrٯ '0g $B K'ep64RI@PS-Q[ǎlɪT!HȺGG@vo$%12'Ht ,`)n\;〔Gmq'sˆ._8$yntt芎סe,8ډUPN6QgUԅfeԯ~iB++$w^c"QDQ|\utZUEQ]:>GҞwVQK"͝#s8wm(#cWSʐjȯ@6PgG=~+ ޡSɋ=q^E q {G˼҅z|ķc;Orƫl1UW)1 cBSwSw&[~3Rѓ+%H'Fo Z)م\4Oz40$znIwZi`yax;P~ :QV21OѩuFKAFnU;fAv0O佣ǗaSGf!MϤ?kXheBX94 …A@ ;Hz"A洌AjDrmJW.VdC a٣jfE4*R@Sѯ|씭5a7*ϒi{Lr1'bFn8XxZc7/5ݵ 'Jb*A a1Շ̮jgI+ipsx2>ә+Nj^!{*߁yF+Lx֠rZmѶ]Wȝ{+>߀-GS8&E lץ tuLo[t$Y km¤Qii)- 1+w,&үAQ=d6aۜǞN !c21jt۹4)7HcLt'ZXnSݗmQɍґ^z7ѺK L8cP"'Gzl/¼D0لD2#e`_/pSZnfgGJK2S,Hcӈȋ\1PD5OuPՒoslHJ10F𠠵F_ӮGC4xvڈ0%]Ž`]9Q̲Q?eu ۵}Yh/H숆>h^GT?WL${{HjT`'^V2ZOUytGIyKWJS7=*rŅP+ 58i/j=BPuj6KDBA=ђ0>* aޞrj0:Y@ v d/Z +a Rbo2J8z#1jL+@$t]L-ٕJfd/B8Y"t N,w6~2ֽn{CO@G[wzRÄzig5f`Oi>h~GbRU`&(&Q~éԽr>> !i\3}% $ClRoZS5`t݇zO}- \;$6d^)V=slMB \l|1KrJb4|X9NW=Nѭi}<!&B߳kS{1[9xZjͰF9F+msWjDh%SyչE/$I!"a:h\qi٭T՛sbu2 Yy&ߠLJ: g?#h5<^ ^^Sn<*eMLz#'Ө%m&bv ƻ ^m3FxV>W M%$Aƫs% [EȢ3,'] {J$ sc.H-?Frhę].G{!{Bt4 E>XzUHv]VEesk~ǂ0I_OjE6B\3_foas7l9H謱t=rC`9 W)dJ6w/:q2ф7e .&kZ`'AQIFN*SWY(xIc7SZ+/SPg0|=Kq@&,fH: !l1`˩rt/0ք< ]"!`շU7{}J_ABpcY+T+:v' VbRS`T2!Dܙz2 >TIDB7iy욹R'j`mۚH|wkj2DubzY!fU/5 ):Ȋ2Z#g'TS^2 + yix}r pFdI" W~lMf3W3oi3ڊł\M8,ϿWeΨ ZvD{t%pGUH{R36D-wdZhjBRS!kC~MK&g;ACHFʢBJГN8.1;] Ʀylvl%TIqo^="T$hԍuw`QqRa)^N =:E):#"l6^Xgi 䈣ВA l}WZocؙЀJߦ=JL>` [vwNWoؒ11L-9/[<|㬇A$'djOO1I!YgE@Bf*YC60R^oiDTkpavzN}د3Iuӡ'SwԊGGN9Q/ĥxk 9ŶKװ:gpŊeZaɧ \@;љ3n5W:_5?Mq&&n1;y- mw5ku`c׀toïQ8֟婛dNۢwh7E/FOo)wbԑ/.K$9VW!o߉YѭO6gIzؘ2h!} ͺtrZԁߡAg+f#yF2 B8/tXN#!&ZD zϚr*R @^?ȻV¢PQ6]HSzaw|Rѭ?j$n? 5۽0 mh>' =Q>XF ]C^kxJVOTf)a(@=z ݬ^V)!y8Y%6F']viR2vҩe/ Y&|Ν۾ dZ,chϮhxb1;#r|[Ic/hz~l5 C}SyJbVxv:kzgU<6S]͜ój1j*^?}'UOcI4!BZl³r$o#?1`Κ[d2 mWkR՟Ȇ%xUob⦷Jsȑ` +X_ Ʊ7n]3}ԋ#-"HRM>ѐGD'ɛK;3f!H$CI˥aI:OE:DnU+FUEʇJy Ǟ Ԗk,)ep*fQ=I#,9,'V1""G(%=hY ۦQP3wZP_4b%=+]M9s[ B B;4%Q\V<|'- 0jD;ST9Z)`nPm4] EHLzW-Q0x:Gn8+./-fU8]c\xiZKõW U_OK.!Ȟwoyő1ۆ /G-v7 ]Gm'fWCgH0Ҁ}x ղ "y! ᒭ_N 3ƈk63RaHX8{fT/4)&Ŏʁ7ʔwGr-CLAmXR't,vN*sTҡ}@iĽ5KoAv˽8X IcK2{eE\ ҳM_F{0Y$Lrd6w}o:^dxbȱ$6m:ٰ`Z C(HC3v/cݖ%[1[&pMy@Jn]*By*^Y;&2mfF$s'DSSk>vj~3 LRPo͘қ]cd<ϽyLjKNZt9O?i plr^wJ~-]~"u(گ‹lб2%e19Dj ,W~5$ &E8mO4(1 qjO%P2͵ -ɱgYZPK!mgDDsnd-seq-device.ko.xznu[7zXZִF!t/:]?Eh=ڜ.+υ%\Mvq@WF<4rrryJwiðաZxY"[wZ P%EL # v3_1&Ẏcyэn?N9=9~tJc 3wba}k63;f10I7ȫ)rVļm O'ozO|6 D 4Y^M[By.BS.j1IN2 C ]ݣT` 5ЬA030TT{p>.EY,,Z9~Jb'9o替,wY.i;m}h |;Ήd x#n1Vނ[,|W^gc9ex:Q?nk^ŴI92m|28[dHa$tnQ_#U{"U4W fŐ1w7b=! < Q=11tC ߸=CwM(e79Ϝ7̖eyf6P,u``E;96Rbў/eXRI< '"R Jk_=A)"Aw;4ʑEEm%f' > *.{v9URDsMuPjhPP>erx\f#Ql%>%ppI.gd:9IStmОRtTNB5z063췐e':S-6ey In{|r J$Rf8P"Oj` 8XLP^hiz m :"=ӻ%m}cYd@̪Fq #9NvUz}ܵuH%8l^e;T*=ݳĩKylߩCEWY%ß|ۻw糅*LMΨʀn҄-?EE`~w `%yj~R$`Nu*Tй6z%H z)vYv,FαPt3 v!o_Tڍx|J:Wg"#a|Lԍ|_Y>dcpu*"0̇ ̃єÃUӊxR2L8;$=L㤏F'9^gNDžm, p2ɡ68 7QњE/3ad4Ε 3'FYkXdM8WaZŴ;̶}l* ;ǨsV6@@Ky]ᔅ9v]J *!Y.gYr)&uE~ٗH܇|L~&/q'^,C,]S9:M&"7BRPOAjၠW@. c!<?;| tD σ6nPbI:hݺ 2\Ke7T^4oTlcbZIJfxFYu^ Veh9I#DX~Js,UTL# GvBЈqi[p.⵮D}u`ut c\3dG_KEKP[AԖ)Ryޓ= `y| TGj K4 Nf-ֻG0A.ak<%4Xg"-E6]}4ĩz+ eЧgbP^f4hg5.mxm_ SKR2\_D2G8TNv? @^Vk+K~ W-rR ]3t 3Y] ~=IS_Z{D\,g[찄^GFvxAl(7l6x4ZBn(MKeidib]GP#)[ ;(JvvNnXn^wB ,MޛQ/.ȒAB3]f <0ZfكK2ڃ1ʩ}vPXZɏt{݌'#S3hP9Bk"B|i 161am?}WlO0{nvwa\%+}j.x/Ca> V0L#ReYgJg'syKL+ G7w卬QpSeKONXn4in 4/B Vw7&j|xqb%g牨r{=ǔK]DfYJKv؞}YDmOfhmo ''EǮWx*i|bd#[6笜R[xw}7*6fR'p#$>MbB[HRrk9+r+uh T|$Cg`nQ~15pKҿ^L 69NYͮ/)wc ;y}a2"v.N=;Mvpeo`U=uvɮS<bH/%#+kOd0z-s\ ۀOTM7Hq&Wh*)vm: 6YYs[_nGi6O X9B+(&Ud7D*ж%D?QaDO쏥dg]mgR3Tہy$`E9y;.F}v 4v3fu_!hɮz-.-w[_+fkzdH(Cf؉se5H03VO'\4keo*1},J+ 9uFigYZPK!P:HHseq/snd-seq-midi-event.ko.xznu[7zXZִF!t/9]?Eh=ڜ.+oov>.p@&Z=2 ];Xp~ rG&ͿJ_@–n"rmBVJ>[Fpwy*>zԻ [{zo't.Ԋvg5(@TXv6w m*G%De$s5urzxGHBo<W5hV.9DL,y]GH+UsVoAqF?qjs"؜lTF̺%`[Fwtd𓍼zB/Ԥ6t퀡? H$*K헨58#-jW+i˚wo6?jXݏt/JLCfpO3,3h`V@֍ ebx.I@~oG%&bMbv|},vUYlCMKe aR*kp0v`X+qK>7 )~ /sMI:-kw:.e(S6Et9|*1--v X̺I츜_1z>b29L%U>;y*l`U4u'Ee)F=>x)n fĥ)d,F.ak Cv<-4]!T@H6,ɧ+e rډ:TœHN<49a0CIOGX@n֢ڟɴoD &缻TԷdOsmr4]{|ƄԵFyh< OGb?;|54ַD01\3OEV Ll;g1Q5y7WpDhTIg-\q_HWq=(g(2ޖ^(g@COn9- W6fv`r&@`tpeI[T:~~y%DJНLl^pkP<e-VL0~緬v7^8$VA?  4 $DW^;WuM86A!_KW|]=,dz!J(l&hvnnDD\--iGC~6I~ ܔ'*'Fzm1:-1,vUE]gG&5^F؈YN9#d1URP4Ù~âG/{"D󐹟u?=3vU &`|.!2o D\[Öz_&{ز[br eIE!#:-h׺gIF2r[7,BD4f a RHVNJA(jLHMUUb EDoՖ%E"J koq)7>E%<4{׊$7 QN.1%#fLGMu횤&{ K5us0=]1xFZ]&H<&V}AHUgf['D.w_삞(?V+hKyҫ&b+  tU!I3TȞcG\Bq?ӚnZdJD>Vm3?>Q]'5ˆ|{طM|`z1Pt.g2q,hH71sgQRQI !Eh =x mb접UysWQ"1݌?>Wu%>Js\|@6Wxu@_)A; $$E9D ot Hv)Wa㪩>4,BG[sG:pY-NKqxOwk6^#ٟWr0,1=trZjF_6YE2a :@f4 3_Vu'"8S\qιdeq~oŧ)(x=\RV}vgr4|46oL/MQhc;&L$)^98G(LNt#|x>ݺvԅm?;5tj*0 9'd7Ia+rY*kԑV _=^w(//k<y;:^ĕ_EUg>:&HCa'2rTwҺ4<%#.Te5} e>ELMON"Op'j S@GWD^*%jd;Z$4B*.SDGJ cM|:p?O a} lp2%z^Qď"Sr°ͣ>S珒I?a;G: 6K \j 3xFw"r&wi!(MKo 13#Jjwyb[FƋ0- qB0HھH 8/9#J8I 1É:iyR\Ь,_' >,EJ7}y#v;\DXp: sKn3zgKkc@ v2UqJ́OH Kk7E'GI<@I+k{l\qh="e'E[c)q%j USQ96,M@ +KT_l)6 H*ER mk‚3A7;-i?GŒm@PrLAZ~,sG̴fMmew4dۄ&> GGƳdSb )Kpve/] G9?`6hn!J(nYhZ }IyiT~s߶Sor=60^2m=|St6 .gM8fMtX@#||xI{pن\`&4 Bm<]$P)2JUh$<~Htĥ\Rfк=7gV]6o\+D7Qa B3FK5HrLdzS!qq" HY"40ׯЧ,.!Xl]gF%jԆ93FOp 0q('RLe r]gYZPK!6`D`Dseq/oss/snd-seq-oss.ko.xznu[7zXZִF!t/D]?Eh=ڜ.+A\Mvq@WFpS\YH1 f`<6CDE[`tؕ|{uwx:;U '"|6sx@*+K/@ܿ‚0RE,ekX xCz˩&]t<:%U1-]F*lWS/]4 "a!8-y]JWE|5 .-y AQr*{Co9|~odZ9Ŭgu.y#`]0-dCwSe7yn}v2ߕ<OC@^Ȭt]s ȭHFPS־ |9ؔJOB Xw]iCORP aOd yzR ATa2{RneKwϝVCZu)T/mpYVP 뜡ymu2yFkkgW6O\2{@Ă|>Fnkҗ] >OB$9kT0INEuD>+ў?2EU 4׀ӪYS֔$#h)(!WţW"脛̨U )&oV~Vai` eEZ2i pWڿR/Z2 58d]~c]uY|6G7LIK6'8*8p7ܓG\7poc;Ѩm'l1^Q S8 'qD ryNtPME`?;mf;H?o& ҙ^:9Z УF\ I00t J,|hi#R ˰1LO')%Ul3IJx}:@8n%2ƳB,5ju27-"L J5RIO/U^8;5q-*eS`*DuM)(3ln`3UK=~2.LɞYBy?<^BV?\~U{:( vbi0,N(--@&@++i3QB2ZO4q$K.VEd̿JD*n Y~7eTS+緥c+Ҥ_UBI"C:Gs`![91ęUR 3$Va\$'SZ>гG{3A1`#lH)^ί*׭kcz g"12RnK͛5j޹׷;PA!)l!O}2t2eME΋/=DdA eZkߢJdS ~ͦHf˂ P?*M&hXfݪ'h-\<\B.77zeײllUr嬼g\$Dϧ̿$w@m[G /`b0w~O ~ JYLYDyՎy]l "6sBZEIKG^ĪkMOV ?H.pLsH2Ec>HP.֓FeS"4\ BBm(쬅#["Hm,@"Zdu(x`G;ŗs'::WӢqZsuՅuXpv߸wl@%(xxt?giS[wk٣Y*8 Tc-H"m';e5,Vl9.řg.ASjg& 6B@%7h ּ]B8w[iEc{[D)ee8#ᝧ/dGo`0F#:чB|/z";Z+Gr\@}fq/H \.T#b9Bwop+F> "i!MI9(@bYw}Dn˄ \ȼцӑ |Y}2x="yU40xA4IalCD'SZ@$O6@ܯВ_Hq셱$]Hj3`3$}4 nj {Kƶm5͙ 52DTYHF%(JP -bsX/zo\`pdݩ}:f>#"N( H{N2nV8$B 8FbXm)9V8#ɖ!44c>*[{Mb PةR/?\8Ͷ{Vܖ$5 It:5 1@*o3FDr5 +]xfkƖod!ڰ9qH ErmXiqrygT[Sz܆bvP9LH 02} +$~L0ܴjt|GSYąׂ PP@k2*hf;Ƌ a5 M| H#Oq6 8oM?q6 Svc-=cO 7jR_[؃8 ռ훤"@ʉaBEqo9R-c0/Vri80IznC^1R}# pxzU)Aܒq9(wTF'; /݀c5EgXv_H9O͗eyOG)rT^;W ۵˄Ɂ: ;?'8V `bp07Qdٗnޜ КH/RЋ ҧttYIan8߃7NƦ<)ljCy(Z 깨78NJGŔ,0Tׇƅnʄ17<6.#o\|쌙h[m+J=ie+Adp]É Y96W%V7VT눶ћ`wElw;Wһ%j.Y^Il EqTb(zė-' _T|bY%َ.+$u~8`{\M'II,),l6sv q+8c8$w/^JVx0SǫRjhyb RM)oc7[ &8Qf>i,4\KTj" 9ۀg$ؒ}xxJ5o<~X\Im 89\T|g6nq7T/ EQEBO{i8'ssIAF[ۿC#k=ꢤr~treOAu|ΚggD`NӐv%ܒj @^Ow) A3F5czý? [B|/~N̏?\H݂}ZPjeQWzA$1!Ԗa3KqNFP-Wd=R9Pc{鉥Keyr?m-9;6Me~67Y8Ǿ 9 xQUPF{dei`X-% O,cKvgm<_h* ErRNv~m0ڸq>ʢ!cFWބn`;-6,5} @e:P6 3R3(y(z`>]-ŽȈ!?"{T3p fQ|+ץ߫£<{%^s⌍lΉLHہ?uFH X[83[N}BwqQi4|T EwK?Ѡz<|}8udH +i=Amzާ]k@J4X$7!wXvbȗTXECӿ}2'3EymWX9hkTj0vIk%{)W~th@ia+FWҢsunC49߉aiPꁉ64w9}"ݹ @B+X`m5Ftx}]k=2C8!s 4:5O` 7&GS>#Vx(] HsG;[s9<_,[9@ByR֎Fޞx`U:*x(Ui cOxSmKeQ1KAsXJOHkzbx8X33} L[W<|"])#RP%Pu}A:^;e\%sH)S2Ygb138%PZPjfCo:n ^G >աY  ou6m^W#y߂U}\̋XHp YqU\'FG<Ӝ'O=!!/,[발'pHxC'',3]aIQkn!IDm1@yG[I;4]>C8ݓri3K\MdHs2Ei! m>>I;tLT!T =(]3GM3 ӒwQ.99ܥ^{F%&*37'dm!)ҽ-d f.mt~b w|gs&nSGgg3y#U,&V&+ݧӪPcHuN9^ [,Wj758nActtf+:1q $Zy9#*EQ;) tF?7z@xb E߻X`."l#Xvr\jQ*$7(o_Vmz?H ]9`ґaILJ΋$YބMA~Ϧ;R0b mp[u6WX` 'a,YlI̓lǯ|>/NP!ʛ5}h= 6׭ sǢD {>DmrC 68q^2+X5oOBׯ^$o+*[YՇn[ W(_F0_DWk0oҒ dF̪tfd+GfbqԢJ49US^#Y0^ ?8SD[KXk" ENm_hT [ƕ [x|~TMWw`|Rϋub~T9ޙԧE',wkC!2hW^|x@WNɫ .FtKE֘Xd~0gDưz0[cg[IIC:*$IJyGIպ [iO6L?1XBwq}?4IOxpch-ǣdq&eW+ EJS^#Pne'?3$%ky``m@VWVBfi<_'4}| DuǴ",DgKM) jdā1E*?՝ 118)ljE7fd{t8ëeUY35[I$Sȗ/bzr$l@UQ$dG6XE#s,VPtDM0@@C֦{dLS_KC"drt[⫰ySxu+M.;ˬ3R|m[^NQVFWgD\[fwH4s;^7'~/k`lÃPcqYSc40vTR QS2/*ȸ)`JR FMD =>- A$K̮T *X{77l9Tz%D b ~Jwc770}PmaJ6[`|d #e5(Xr]I8'gNTUpGKW78[m}_4)=w`kjxr%n֯C/dHѴĩ  Q_t7|jLuPgZJǾ^^QGa+ն0ش.>0v\jX\!!,lgA7B\XZd tΑfiUٳ:0P;w 5Z:՗jNdNwʊkO5ܰ5ptݎ[+Ai`I{0[ϾTvmesCΤV* < :`0y}IwXTݼBr qaXCIC x&#::8rw׬[Nzzdf>4!H^xlC6|4+AYx/H}c/a"T V0h(L[$M?1Qb9YC.53VLjZʠI}&O#ɑobG?"hQ7h='95eQ~ʝ6Ql1Ii~BNEkxNIJ#<%n*zbM})M6&{+uf$UFhfHq 91OY|]HQ,qjiν6㯻A5 8tKU*Fy}u'l :IxPޢgτF&U9:sY8co}&~qI:k'C]zig.DBT,D6CxL zLmH-u%stMePmLE6aDћ;, jOڈ,c…mpɊ,}׆;NdWBwyjz6#4f&ypםeu,WO? YIfU)c"vV >(Z(6FI3}qJ2.:I(;9㿂'PueIQb&|rQa '*6Izh1IދQ) (& US+M_:LvSFYqeZ&Oz]G4=OaYwe4ћgF0y- CZvXӛoƑx͟B̭WT:O` FnIT}h@5,JY6 L3RĮEST%8*d24]1KTSN-#|ot8>wzoLܻfa< 9}3"f/i7q| N]{, HSp2q Rd%hCx1eP*R]ף`v /Ag}Imy1ԏ<+([jF1jOG78YG!J_uaBGԯIıy#k I~Njkx{!ކz'Vv+XsFD^jN|GZyZ0!eb/yv<=ܘ|œtXi oab'=_qjԝN^$N镖D4; o I $sͿeC-m6vXDФmAQx N/ n#KW\J>=#KG^a0Z,a*Gy`iKf|6v^DQkzt8;z7m#A ӆ+|0X-\ך[k%?/y1+@ϸFSh>龉h{-C:Z`Y&ՂJcWbH5T\T zo9GqA!m&{Nl@k e38k c!m Gf^;PWUvGM3Ϙpɣ̒K/ [kHIUSHl׮W /M1 %ö3&tPzc,#sv}#R*R8PshEt%l8F,J4[7Eg\&O+u ńӕ>Y1Cy0"Կ.35[mf +?J8٫ʨLn /?y:U@/Bd-GI*Q_ 5˱Fӈm!Yᄥ*?5 xL?18@J"t-**7:šʛ3#Fiΐ‹pl(G0}%PbcMJ7%)(u -,g}.7 !1Lt墁íT~C71̰_+v1-,`>'YDAH;;vg/EfN @7{E.GCb{9kf9⺽듺:|I3mX@5]1Ρk 06dOνp=z']-dD5:S,߿h$v\xlxe%DgGu` neUW.Ռb|.(^N+f{}Be_5: pY0s]9|Z0W 8Z;"gL$ ^$$q'du_Y {B aXHx6J?XA vؔߨ?Q~gJAGoL %k(τOՉnYz9%m #=uy6ЃbGEসos,C =.ܿKc#[.sϝz$ZxJ5k:! ClTl~AjX2%;7^A fj/ #zunzэy5֬ų\WGpB?lFKe6Sxk[ߟ<U#k#u5$s&AYXY`?I1r4VW(/` vWOMbuA,pt޹@k(?N Ԥ=F%G,&Jh' bn慯GqYDNdBRN`<(Dj G k'm 9gڷ]- xڠDTfCYI%?.w1%$ aecdd\mnOmOas4I>Tp[Z61w)ڿ#@'*ЇCoܑ /.E QJ*,_wQL%,HzV!^ Ćs甙~!>SHٺ}.}.M~ȿiSdS/`k֎[gWVu% HƐ 0vƋܞZ[N绲T=k$ H/9x9Pc/ g[K-h9peFVWv- AQ뎂/(T9 ~{?r(b1Яe@U(䭳d!ϓhT.d4Nf4RǜKRyeq+1@0C߄NĀIr'l?&,͟"ޔ >kQ21  ᥸?eҌZzݚ RgFv]UZ(k2Ma|o:ZpsHć0d&mJ0ΣF"TWaR =9K.]ɚb)y?"z ѻ7Gѻu"jpIt/QAL7^<Ċ3ȆTrdFȧcU6&l&~`nJL)%7`bDHjj#`ڷ0Y^2¥ t(B=%"[OuΜ Vl .q˩/ |cZ}-~u s%YfػxQJGY%Ou)'͏8L'wԬmmꗰ{ ħ9&y{Y'VnCPʋHhPcfǟ`A_2#0tZSV f;Y͡ =z[T!2 %oq> .oxD>(~[d &7&԰sz3&[A"=P{7MAAYk}=nPnK*P=MPᣏR A+~-Rt=x:hnf_ljzv=.٢2BX'"$<,{e[UX-Ia"4@rm̄L"Z@$*X̜j8?bl5nϊMoZlK$m&l% K9\NJ6"l*^!'/d1^H5:섶lm4 +<9cqWQ IXN:ܯooZV^G:eD+Js/R0>x3# ΆV y9*B73"H;;F&x5[ ZM\ӅWW_*H u[xdadv2ްQ̙s7gJHvн/n9ro 8QlsN) `W̜u2fEҵe-b||W-Ndޫm,Fj[H+Ѧ"C+q]QML!`q!u IG4뛮vbR$PE}} !@TB0 :Dnx{Ιިß+_#.!%E*T3}m !WqMϲԨC&鈜HKBߎ)$F8}KY'|b{gem?;7ʻ$NwEG;K(Ov2CW08Ɏi:L7[ wCo9)R1J㥛 %\= ;1<,L*q’ކ>+{+`5k.` +5x_Z09Swu(!m[9`t yd6œjߵp4\߷G_j]ZyO|fw["%r9ͧi)Zh<|ۤc;soJ{pvglde p._7M˒-;3˜-\G-q*)KX%o6YWSm]~5_!DK,rBN8k*b?יL@0u^G9g)$ރI`G;yyS(UBsR[$ϋ2/U iÕ-(g{,ٱSZVt:IPsZ0邡jf&!'#O!vWF[Cyhahc%).y1&rl'i-Q\u ~K"D Eܻ\Ot"[n ~QgQ Z)wJ)_r2ƙ\H/M: ux]m{ӆmVq)@S,&z_XA;&{8urfՅ1ThQ>Pse\_j*2b,UYnGn-a11@6nisp=R$ɘ>f9~(SƠمS/Sr@S*Ay[;%-Zm512}MVzJ'upAKB`0*#[c).BZ*뷡< ɐhE[:H)HFOoP{N^:?~BH*8('Gaug)PnŠg=">CB̃+Sa5)Fn#IWwMHhzʹ;N]^(ەFķ3ą* !.gUB&1G@h;,z (ō W]B {YQFP?leH3L6gNLd!W^~B ,PL}$xx.7 TЀzQ],%$"*"TQӺżuXY&XPpANOZk#+gXǢ 7==;IH8 (4<ןM2|Nl}ɱ|:uT^/!Ѧ6 .x-R1Gg;kwty2if#fW1{ xwqFUlWVSx1ߗ&Qoܙd -"&}Ҽwp- %=i2A'jb꾐s`m3 av1Y^.0IDMsQ 1o E^'\C} wCh uekvXbyAi!Wp-k^lFIϺ8#GHtOe|LBW^2OtE& +0*lTXz`'Uz@RbLP&WHM4k|#6lEQƗxP D&MuDN nR*Eyl-boyK.A^(mKLb0Dɧ-5.nKRŴw!t+KlP>2Ȭ>@UŀLtP+CY4]Osސ#[ ~'HO[6L/8yY5_=X[=.ujґB,-2ΙEQ'uG2'8`qݔ |]"W993 M:z;z h"%dc)nhqtP(r}6FuXl1"deM9@f%$4]؊{YKᄷsd{2~lb`^K2_j;Nlv!c9:D1$nxwRǐmr@  ID>m,n߄*wI{/[{"==ОL%BޣoS}-2JWیBVlLCiftFHkA#qV@'ػq͓xr?&67^՚:-bjRgxX獙x>̩00#^ܿjB7ίD@bd/CDk;l+_(< Wm,^QE!sK|Pd5Dazf?.E^?:^x;)P#T(\Eӎ *YUZ\꧑#C,JO什&5f]IYn!2Y#hQՇ3xRynGB b34c} m1%? *37Tp="^avM_ϑıWlXG%g\~8j`Gؠ ?4f3 {'~5loK*뮜ճLM$ˮܛu↮Ew4^OuUTS׃L 0p!~\Ygە{Kaɬ狳czװqa *P\HQ+ߒ2 /W9Evay(L3 O1"V'VՏeKO\,L~U|l6H_v"zg IB)24Eۀ 54Zy.~0?6VV?zw։ar*6_6VvHO:5Oz-:5JiAQI2瞷Ӣ^y?oĩ$C:[j !j[ Vf}@rǗWz< ~e:^ANvhO3^d;JE47ˁJxJlYm++}HM1XZڿ9,ؼ\:veZ]Եs1Y5d@_Nɍ\ Gś y>khd' JBle3)AnCM%vQI9(q4NK,a5D-1^#ug^7B/ 4`mG kƒE e;t;KʃJk̉LKw{Ale$ݯl1;Z@O3-QXkd8D0Z2[R_Cg~NA2X g)Ǫ`K%p8m|r%=&>_rΗȀ40c1@`$0~Ra0n%Uh$ɅёlpAz~8q${x`Vsݍ)zq7r9 Xn1⸎J)9z2 v DpgոDc|9wSOi1Cd1VU,B8' YX%M\ͥ5, N7dI4rp'=H`Q^@e~FR|pXJ9Ӊh@bG.G9r*^~CjS5_;4b6P:\NS&5'0]b4t@wYoQAU[;H\ǂ\h93 I,g逨v<7ub>?~vQ\U_v$e9+Pݔ;ś>/k~nRT?;z̼Rt,&CpnK*lFV.c` u籸QE񶮞_EiLq>:o1bK"in親j6*q9U8|#쁗CѣŝVލ[rzMxּ`Q,KUTڅ Ev{qz|w bjHߝwe>qB_eQa!\b0 i3'ߨ4H#*‚H(ID};paƓ\ۡ6[a>00'@e/BuzoȡAxxXgזf`d5Hpoe`̛?"l8kJ'IY(3b2#2Ӻٸ-=ՔR,w Vd;S!-Ե*MAN\mKz6sP-WMR fxN+1otDTLd z=:t_O,}U~Oi&B]JPePA36Y{xdHf< B]Ah[{¢G# vS3ͻabȲVu?n8Di#NKE{&^}KrJ` qNţoiVTMĵj`Z\=ۿ78݀p$[z1˽IkɄ0'ODNSdiǶT$FU4}g*R@k`v-̺BIvԭ9rg.",Br= mM>eב/qli&YM `=iBfL_C:?WI>V1d&rU*7a6]\{ &}*2ȢZE`WM)Yb~Fwi(וY:fEa\eb4\3p _& eݣf9 3H'5)+(?pF Ĵ}[Z깿Wx$~VPw$u dj҂on)B)Cis$"fFף>ydÆX2Q5IOTkFR$u&E3`1V4qj^{c{_œsMtd8~"sD΀_t h#J=mxQг ?[Q{nvd4JB6Nj1E0!O^9F/V2## Q7 (4l\Ww$2iw3$~8[|]Q?KW{1䚧f,JHΟ=+?:7QvFUa+YnRX*RL+ntE<@zt ѕ(+񣕫,ˁ|BĆ8̣Sj/hSZI0=QIj&)x* J?8K`@j~|8y C;=~ 6njg׳mOCFb>d2N4h= #I %՗BIZ@);@FS[I6%i?8 :1-\zYTĩsj<>^3.WyuFST& cޅhfuISK-e-#eI͝C9>%6EG?/dFߜGf!m-tӘ_ $)G ۟N $z6.0 g+ǓN謂u~(镀4V m# ϋYcA~Gz`s0tlSpvWejcW,N6A@'1qe<퉲Lg`PHV(vhYqY܆{6#!*%fX[9^:f"U˕ô7 Ԓh\u d<7'uƷs1"[iZ[zbYٙNv$2sIgNt*oə@Pe7iQgPTJKՏX̰URF'^oĒvVf fɨQ I{K''6J\,A5^Щ@_aϑ ϖ-4x)$1wlk>I_QӲ0Hfݭ >$JYu!l=U΅\^JS'bAB1wYaUX%˂#pycZKlyb-@~y?}WbG,R`^,fM7Cن&G'Bm?y ûϱ0FU1r\62/u3ਖ਼hh 0) l6rxDGp-W9}j? >u'pm6Pz/~y-o#)q>\[4 w$AԼi0\@l(I dr[oت̢GC4xb=P5gʢ5}zzZ0\St]޶AQa2$'>)~#Bte]Div~/)i}>,*(5մJj! M\g>Yʮ#[ki ww` |0y~Zp@ת[-I˃Nb2m&A6*`CQ@O!`uMN.@riA"e^a= B<)@& JlO]OJP&j- ѼvplT?)ΎgYZPK!vRcseq/snd-seq-midi-emul.ko.xznu[7zXZִF!t/Ds]?Eh=ڜ.+͟S,3p~cLʬk&W_6OmJϣgƑ E\k4:bpLTc#}4Oj|!l0EӭB<^< ǝyqxbUtP\C +` ܇ !I-%IK}mY/࿂8߻C?$Hk/\ X@Wcod07,ۚ3Cduj:QrzD"&AoGkrVd6`x܅ xϊG%էK}!_^``Ǥn;$6쓐;}Ȉ|Ѕn&e7n`]E|`NxØ\ڽHy;/`lMzܫK_4Q'wWgh9A}}= OHŊ'eƜPzY#gn q]f.]w1d$1f?f2S9[ߘ h9E-Bx):t6U""O^qLFz 6|( pYޣ 1rhLX!4>i%yX!٪hhjkcDhXϡ|-d8<43!&F+>LbH5!d$ yD8d@55/+YQ;QDћWFP!{ܬo]/Sr.iI[̀M1h'@i'= ѣicsjl!a/\o} oG+izpTDŽi&W+ma9gZ9xDCNɰ;m F31tDjuIB &날VVv5#I?. [޹cr{seL杤g97ԲFq(sPQ+0MX@ZN=R1V ŊQ9X{U՜@P⛕h]}MOz00$qk/xmB?#lm1׈i.| sK=حshͻBn n.:.p0'ȉjS ;R~ufD8(Eai}V~ϐ)G $aS"sw  ~MK7d %=Xe\>`)wnH!vw8Xgջ,7[RQ!U:Q\LU- /wgmXS\Wƒr:sӿCc0H.lh\] !%i}"1Rދy6Ccj?ʏ9qS5-F㜨Q16*#]/KtR`) 0m&[KHiL|'5.O'r }v҅d=ŗ bhW X* 鬥ԡ-(+`{à 9C:_q!\M 3M_ðe& $7Bk|w١)>lfQ>G|x63>ֵ+KFυ,\,Uq3cr.Ix/:ӃgwKxIOQ5JsY}; W/#}jFV=B©̴Q]G+hMd]d_["{R)]xFbڠո LLUN;Ux?oΠ.XBHH\gA] EkeFA0Ъ& O4IMW|UB+d/?d:H 5A)`\854Mץo./Lq9xhB7ct 3Am=)ձߎ<<՗lsetB ۩u[CH\IV!sn:5@ES t>R((쑥g!5K̯̼Ŀc硢Xk`kt**' qBke/ld;:*O5rƫ7e!1uDjGNTaFQxӺCdhnOQY~ޫ}[䲊 lurYsBDw^Q9RԞy Y<6ܞy/ \u.y' 'ŭtEd_H05$Q-!rݾ\uY_z+C\ 4]y|GZǖ)$T.fAB+pÖU`TMpͩ{,G#wo6# ~ԏ!zE3ו_WR NEp]^c>:6qbzv8Ie`Lx(rM\>H8n,x? *$C?nwE0މqKГv{ZkaE ߰;( *NN]H'Ae4?-৆Nߘ 4 x5ZmR5۳OL]7vT1iVhg&Tvv i9\U@+M8(afߌ4|2BH%2ķbgoh ʍBz5&%&5! ea}h˲T}H{bTB#%`sc#V4Dmu^5qYMVi+'jЧpՙλFG^ ݜ𑏅lzI-\]u!ƒx.X/U}&6 ?2=_mq|V堽CD)sdq+0x8m)r;fWZLxɉJiFhq;̚G'l ~e,6sH> S)oK~h1 %:/l>z2('9e6D 2LxJoEwgI㬐dY񿦶 7Pm7&F7&,%ݏZP3Jk`R++7uDۨmT00ڲ0IJ> o9J;N@,MFFԳxZ_]xjE"d6{>-~m>U2MLO Ru@&mʡ;dz$[hԄF{9]h֊i̱A#xqҐ+$ pT 9+orirI=c mbBm/[!Zj"$%8 T)1R,ϢU-)DQcc/JBɿka-nDLQ5FfCV4E\OO#4CR^Xo3@=N q7ڑ:`JRYfz {vG(Qw"QnktE8Ӫ潫,m]8Y:bh~UL;K_7ćr\PPl.҃ "OɅc?K(\e[%MgAc2&&ig"I0 fWV8*_bq?-5/r eВ0KMC!< %K35L3NPo;yȇkW|'rEH6u=>%p%"CRc az礚˧9U@}x6SDw~J7ae0XC86A{~9-3bsNC5:%س&ÛLS'*zFbH)y)[ID01gݧ&W3발>C,*%+^xvM??ś(֌ǂ^%T _o3"(UB-*(?:n|(ӑӦ? D2蔱Յx_㇑a؃->%1֕U6-³J&?)L,z.u63!+Dy -}寘h_R?fO9Aw8YK#k:k+7$+=,]ܸfg[|#8+YAw:/yeH>C51~'p 7]hʰ8gV|*5aaN'Xn{|ZYFc~OL1LGF&ڡ1Zjz36'329qū&Iف8@JÔN5-BP8Tk^}\s.MMY`0RWCbdKrGZfBB_ZFgrAo#QVzaSr#I>S6F+;26fq6`߽~iB Q=Sl2 ̭{k\O67eș Cw:% (Ɇ߮(y3Mm'{[>V7D bn9eL'OQL6Z_jMʌ.V0,^Iêa4*A4m_nxS8iw0RRs?#MPH{a\uvD7ehwP4~e% lGqXIU36Tԓo5 WoZ8O)GquDWu|?6tjUĜ~O#(t簷܊4xU,Dnx̃N됴J"k9ĈA,f ᗧ>Q<ìYWF27[`̒ ɁسoJ'xYQRݙ~K%a >(t9O{bM0x4D'Bnyb| ;'^ܱgYZPK!#QY` ` seq/snd-seq-dummy.ko.xznu[7zXZִF!t/!\ ]?Eh=ڜ.+;mS(BDal9nij90xlCPj}Fjǟ;ـ& U?&ͺF&"E],?+߲?aJtšq¢ǧ|TJ ~ Ws(A\O!OU3Eo}8@sd#8Av0+ #(Ӯ!4>8 INr ȕ9{QYd4cjL<zV"34YW>P:-T%]] n‰һEN Q4LlxƏ?$զ~"?z?Z2A/[.s) }C73N,MUwZ@C;{ /9wPuUv.JM9a%\6 %uȬ\k## WW_R7ub)r͘ OF 9⢜˶0oً ? < &dgOqcؑt(k ɔ^MS2NZjd ,+^Evfwq'RW"WfT\HCnYHiB!qQLۅDljb#e8"y{5WKTDE9M3E)Sx :Z2ľ[զ 2ǭQ3>m˟}>CaᝃG #+baxG7xЀȜ&& xuIDE;X_ќ{A1p;OYu$+r'8S C9͋MhgM! u}՜g:k.ξna/i_.q.חEk/D#HP@SX ]) .AF3޴jhaw5paM$- c*!D`~nC c-[!gͼE-zZD!dh{4qD =qX$+ ; ,01%R5M;DG: x ʤ'ϠT?mgy kk{&B{_Pz^6EBw{O':<$ 9KKV(۝ Jץ"Ery*E#RyB^8H7:TWҢ&daOzG&xMP|[<dJ <:αfm*2r;H`#wɠ_bܫ3gM}`Ž0]ON_ܣnz("Zq=N%mOoϑҼ9amIfvb&ÊNsLtewAQo1nt ;>@ԤJnK_/bh 4dC(Z7HkKns>V.E9f XcLL\2,X[c2/|cOep 8]n GK5vZu",rQ,ͬJN-s%zj3Oǂ nؽ[}4o &\Ҕ!l83Dz0%A8f9($zlO|Mn*HN)F"<p۪Q+E2aHw&@3FgYZPK!^seq/snd-seq-virmidi.ko.xznu[7zXZִF!t/=]?Eh=ڜ.+ʤu3a& FYg*-Ryi;c5|4lUXxSEww2{ ?5fIV9cFڤeޘ אа1RP2>;u`\P`o7uƌB8$KrlB3JV5)i+syZإN.YH'4|kChXS&0tKZfXA6=Huw\4؞ˤJuC ̩I@Toa?9];.[:z]:kA#Éeao0},z>{ F뱅Ed暗L!)!bfBCww*Z`_e4$83T 왿?Nтy^M˫rBrFwNaP$Yޖ.&!oЍc]bdBmwfݭ41͖N}_zqB:ˎMfeՓV?~k}@x-ʽIG<`#䄴,Կ- QCLuvYcӠ,%Dt8^=}"e`GJSb@gwz*~>Հp(0 {D!N+By pǽ%+M7#6^= r}@Y]A5q*O (N3V:Sz<жda G-yd~3;FՌL;=k dQu'N!& qQZ|ph %8<>amL)%kӒv&` 2F .By Yawwk65B" % &u ȯ5\}!2dRN'ʀ:[3J@N>njIܞf/gF{p0?*h@- Wrn:oWe|AfD !e᫝(⢙ku+H|i7ƛVU ߋ2>* .\቙r:ĺ EH/Pr4~5:LUe/:oP1Fc&{A -XFn_ڎ۷7 GqB '*#gK:&#roڵ_$4:S 4^%]=^'F[Ĝ"qtw)p۵XJFk|l(iBT $GS3gZqBmG?6AqW FBduGE-ϲw0["9E5l lӍG;/.ijr5m`-'=V7G=':B=ku"`Yw(~S0rz)eiT 5v#pq\2"Nnr0Km?cWCLa7%3U ŕ6fio;zcF-.m#<ІfG1>)~Jki7UvW,δҵD ļ `jUޖA,,+ɋĹ~Wy Yq_.O_,xUC%H,y/2LTi}R< b2L@X2F&;`ac+#%*VJi^"~ӔeJ/wzߒ1Msz$b,)]G^ =MW2&)2J܃nO79My \ӚBA1I$<.'DIGLjMSp "62CTu`侶>=>;!k ptgFA_13]_/ KV.rWsR-͙i:}>73w$_=d"6pBSPԹ ~4M|b0ܾukw{9c,j)`'ëŏٔg=.2_EW8$j/і r sٛqtB}o[2m6?16+unrB/x"CUcdVdlg5 ŴI>0jɟQ WFDKL,Xt&-Є뿐|z5@?`W: 3` sHP3M}%@X>v_@ZԓfJP)cSck9$$Գ# D땩Iؕr e7&ܹ6Nӆʌ:UBJr>56j>:vޱgĹʘoɾ?Sy]  hOAK{R.bMkF5^Pz]Th&y2Ө|>7ʢ䩺Zr*ܠ_b)coF4Z ,<$)A4ۅp+~c`M?F{=TPC W - I,i6ێeD g;d˦ ^c6z唙PW_o76C<DZd5 r0C]|;kl4:'sVo") v#ږ_R5k!Cەsc͂w 搆o,!AAtߟ!מOmTu e0k5 FКBD R;k]7([I]me" i%/ ϗnfmO{MA茝s.BR|DA<-SjAŎB2.W'aW)pjZA]r}X!aFcղes~^upz ʽ'Ӗ񭷕- %ї{eg?b7sYymJc(T^LPr~ nu20uIT.IY/]D}9Ƃ,r X1k0#Kr؏:3EԬ4F;+6.v,UF!ZE=䥬;#dtNTGNQ =6R :"nIo՛9}ϊqܖu偯|!WhJ@H,T\DR\N2n{XC >,sT6w5VQ[Qmp/LƁoA(i%5dv2N r/6;,C¨0>ՋR)nx-vkQY)Ff[Uvw"cdluC9HfYLy1Sb Q?RQbM_8^bszH~3 da@?xD(o?*'X';y+#-<_4#2B;>Xo~v*?o0'ʯvv4ײ^Dק&:h^5!{ gYZPK! n nseq/snd-seq.ko.xznu[7zXZִF!t/4m]?Eh=ڜ.+χn0gq5Ir2F_UXfsQ3fr8NͿ7)vU.AHBk$2YRuZFXnuD0~u)o"dzrBŷӛ ip]Gǒ/jJи;x/.N &wql~\k:8LgP7 \Sij Ѫy8QQ| #x`7%o-zGI9#2( q};e,<ߤ"X띉zr QH{`x\ 'mY^UMa◍*QXeGTD*lNJf0hi08 zj9N$$:hT#xc !9n*ƒỞ'"Q,5=/ƸޫQ`[D̶Zce?gب<Q]F8 ASy{5sv=>w(wUƓ "v9-9DI=a( % ꥥM=uyx48CkL0܇r+u0R^.eg#aW-f}N$97cR\vHx s?0R{vd'@'wRwT2: SMHQø5AS߿9?Dh\b($~> m~.-`l{nj }Ѓr4\:Ӆ0"ܕ\D A>ŜH́g%՘ $oBnL䍳}o ^ rNZOkav?R@]?/ZG:D5EIy ~jA!ɉZ8)ν\L<oVp$]-OV說 _"m 0vID 74>Ԑ>o ƴǓ4r;? `6"(Fܞ !4Wj2Oם{~CX4M:yL`aQ`b3z)Y$4^rb "AT1=,8x@q3;FN+ru ԀbɣͧHNݽnlyh߯QC|7@1KǖW+}1f<&Z}o({|&P8n2TN )P@eK@PV1=zqui/!q* Gu#ZK+S{5D*<ˠ޻=ed4U'$20V Ǧ`@ uLgtsor¹# !evr'(|:,rBlǎl܂1Id3QY(C(kkzKL7&2r6L-h9:@N^65T,2魳OTدJU&Ɵ};JbkE77Emb"b0^uP&Ncj߭twm*Pm'Pzá> 8 x[` v vv\&ˣfzY;ޭiK=Ɠ 0ť_h DGyU}&ŚO2&gKL\Bm.6*3 ;3OacR@#yIqozͧ0^5':8Sv+n@pSyr%o|.bf^&p$ޭd)|T"1G rbA#@mh|Dӓxe &PPbũ$'ĪrvFX p sm̍ vᥙ UkUsr;~'FLtyxYxͷ %z21H'P1j8NP@՝DFl*ٓ~/jG0 ȃkgs\a'5ͮީ'=qi_1w2"ynuDNK֘UMBYxgaA "T5ܿo6(IR>0hN'nTtN51=QA܂4) MklQO.:t@j*yNt4BfZfa(PkYpbӭ4z@0S;H%{7hQE4bkpmXGnGSϚS=z5r8jm*LA[ml*"11 'wgF.֛"$?Fa0^UNQM@/<]"N?>,~p`R$h Șl1ˈZlGV]n VP^^ /zɯ,00_I)hp3GUy;>yi=uslv7z)<Jc.}^DKݚGѣΖ0%ebXua)y (2nu+Q"N9j "f4Uޏ; ֩K]0݋S4%Hg@cŸ4 :WL5Wԉ]:8W7 բn'FoW%k'4"MJIKgV?X$VooPY[v;V&C)ttX5-=R($^OF%j@EC1JWzԔܾ%GI>W\#H0L@BآUʰqDPwp,艁O|wUVt^y6Hkx'élIWQw5Y0񗍫ӂ) '!(-}[VA_dsgza#KI-.:::0Yq}[̍3j7:Y&II&|аWڦޣnd86 zfܜ%U>QhI[bBvu:M7YTWv˻GinS"snybS`pP"<(t,TiCTE_-"C4.H$Lgtn5'(쫃 j_zD-1i:U3zoodSgQ4fÝi);lc7y5T oX^syHߐ~B bLQ 5s*mIM@5y{̝xy˯ HUZV hXd4(x# L^~N1V`iBx5J v2NoP:`+0w{a$}#L=8P ^-QAݏtBڲt^`S$"(?]vCcrFr(qGR)EE'+Hfu'hBo5.bN2zQ=ƅ/IeSxq6 -U~zyTʡX"w)cyWSO bӋ7.ѽ`Hβ9=|3& eSa6V.UA7k0}#"2a0vQO|‚"2zCŪ<6(L룢); HB0O눏PhNᤑ(tEZZ(W8͕#ᑋ/Jp߅-V>u|SԌČߵ^\`MXG9vtJGA=nnjI,TBrs;7+ӥue,d(mTjRGE6I 2! fr)+}@Apam*$]5KjFQ-m3 y`kZP6BGfg;roOSUXLDP,©ܐqsH#{k4GBj3$]V;+Νv N.sl!!= lW/o4T1![!S9'hK{a!&D$־TOЦ# @8Zw9;@W1@:Z.>  rFcq·0]3xXJ}>OvB)*f%=gkR]_4ڼ7mBzM,BfOJ;j'jF*$ɴ~Q؀mjMRPX l~wn Nk#T|,cKqAU| ;?#g4崟r եMوīt;%.̴-QŸG{WN0ںRC@>bf ǫ#d $>hNa~ڳvzy:яLIZsy/bUh" ADUgf*m[G پe9;}lxy4Mzuw<4dXWPSe8SXպ*!$agŨG\|ͷU㥕zgAOⓉ + ;rD ۆ^?İWr-.eth|G>%C<{BcF RJ:`;U^6,ՠm60$5TM֓#er$OZp~HA˖Bw[Ӄ{ zUl.Vxg'̼ ߼y% q<:ywԊD E`>~ll`ˬXӰ~i){dZ 8rOfBx7[]֍ %LU]]#8R*o2"%%f"jK/s`*(ꇡ6qXf٢6 IK*yF$}3]ltq9,[MW+XM#WFnƇv{v9y*p`.Szf5-F7iQ,|#+ T(;"'?L^yVMz2`U3d&~bDlB9u]^uU\*IAl.Hc:]f=$|ծ7b*$5iTKA \חL%/)NIԽr+ZiшC(ӱ_jI')w\0-̺ }a--Șepa2>܇QgΆְ 7Fx\9E ԑR( 8s@SǼ&PKziBa݃BHtJGwzj5ǩ=.+M6f+59.9&M`9JvswVkԥ {°zcEr3x…Iܾ4_UjGP?Mg-g{}=c-WmÔQͯ\Sމ9SX_~|ҒgJ|ONH#Dc{Q]13{= + h-]UORV9%tuIrݩ~1X1` F1O[`m~{yL,\⭷Y]RF =pޤ`P\{~S~ꮻRW]TRdV7\`NZc4$S"^sZ{8$lԏEHh mӴe]Q$ tg>tTE:̺h3btb>S`|`+D(cu]6Hf~,OГF!j^mE%! %35 O]+䒵|qXl' DSYpREh$Ra]k?xjbPm*g@qQ/оN._5vdi5Fꙺ~{5sF~ -TLL$fAɫ8>j4ߎ@ &fhQ}|,>߼93aQV,C/Ks:SyMBӝ\@N9#@;Cqո{;05Uu?x.nd/]9a'PHVzaR(UEaYKVda9B{C:ڌiJ?pN&`f *X<@RY!D"_8.nxSV¬s/rb~^]"6(\P!!8uM^GKoWsk 9k-fqO7fJ)f 1GY|狒%HY43X)ڛ>$.!=y_cZ)'x7-z~S1!@RI- [BƽDC&8s4䯤%[Qt&Ѽ<ݖqqx&=!5O Aab'D|)C1eƊqy䞵06Snx*p-`ylsIH0Lȓ=Lwy%IsƆo0twD-j7j}ݮ]▰NDCz;3{ *K:a{^RtUe4MX!u8 ]RPx )Jx I9U3؃'DM0E/ 5E!RtNwRF]ai%Ndkp(6ݮ$z(*r]FWgs2[()37]j>7*ut:js@nlo30JT&N Mq$ L$t2WYvJ#u0K=݌$x烦!z;2E.WA+m [0.?vm,觤 5ta`3cnjrD%`O;EFGlG~'p@N"-nIȳdy9A/%$D3w4ᇿ'>ZX>!%mxEd"F}u,oi. Oh$]4o pP5ϗ4QCs:o@Usի/@yFhx1ݚ҃ R $!-;j!y^>omy+m1D Ѝ4=%ˀMm.)Tʿ7Q;bȂzloaa=V$[ 7%;Go &JH鱠A؟+jn<+u,AW&ME4Y +RȝT*>U""z/cSa=c钟%`,M#[VDr7mm/Q_H׈)W?-IX3?d, ]سŏ@;Z#D:-x^ʠT7&9m?f;jk(M3+p*"@&ak~g~F4P~$㴔l}vW [)r (4RK/kyZ&D3[l!`e)eќrikm[?v3o"'\ ۑ~IβSəDK٫%.νRpM/lAwc? 1 &_my؝W0NV ǿW,,yYEeʜ+q蒌0/y =<07l Vr#i9zs8I?A.zd!"Z;"b.8P# cJكu8VzEurKm^)*k5 rJ >cJAkBu2z1p#d+,B)}Wy1z0׏~٠SF ]ẹRapVT2csXpz&O!OpٖJ6}平ecҷ [ʞtW)b SAd6qvZ;/J=I]%$J9©﹟f/G#̕2-WeW&֩ |@ jwbiT Z_}oQ 2Wa0x:J7#-bϼs/QX@Jk<3(9/ET#TEE{ b 0#j듉&M}LpJD7?E3m %[Q{ _5WWaF۝ಇsthҝcb G}^r<*CUW}X';m)QpXf#D$ =Z.j8[Ӆ3!o "wDwM4ZŃy,R^[J!NX^l7P `+dג  ŒUKA'% QeOS0995;딖y8~ uP. C~DhzGdbtT쓳%/%Ig0(ۻ\/gɏ7Dj'{@q;*@zĹYfs>zh{[LjuZSNV̅[Tv1UQ;rF^س*4mkHs!df]g$JWSf,!ZIut~[0%dO$ L!ٛs1J1mYWR3^^q)dbəmMES ^ƹI` ?g!~&m{Qx]yo{ A@weg~ w%R۳^,!Ul~2:1$RfF*#ndgll$w¤gjaCJLV旁nټM./Ɗ9MF<%[OH`>se4KPY-O!\ᐼXM-͛?K~h͋yDx]ւm&ۮ KX|Xv{6g+WANwC%/u2b*Z0k$sݜcI[C nh/Tr^$-3wH;bAn;vonw_s"CDZfǽЛ࠰h%D@{YMn7k/hz3;VwQ-GMȘ !0`6oWmˀQhYdrMs2ilV؂D+X8;Jw@>>*ϭ~Mb)@3ߤ0(NUhǥB[ڟƨϕ֫(ZC|A+6NiI숌wsa KgdK%0s Rhbm;OLE8ЯF yӌYx3kÕkUyOJH8 !8V@y߈`P0C=/vҀ`}$#ƌ9ԓ }[`[32B&h9w]&atJːEcG+SS`q}x߅ 4?v/Tͅ#YK$/JtB0uXq a}^Cu(a`\lC)Vp\C3YMn,qrAIy8h4s `juy`>Gxiдae(i]Cݜ.x3CE8`-#öEO= ISCŀd{hpKS8F7ghR[@̦=E7m/8ʩߏqN'M Fob#rD08m-Z \CF=(y5[51gxAJ|rq&j5au_L[ !=J;7gLe.9:ǭ>Gt6u Eo3q/nVJV{ܣ{{X)̤QיִsB*LNb}& J/mJfq|3wAʂ$dTG{l?1%zMI?I;MQ:!Q50Q^ xҧvߘ%FIjyx`=Sﴰs1󶔾 ؟2Cj}( =/O P_@a=4i,ֳ+pUUɥ,y05\E{E |ALQWw(3}ȡ6Nw"Gdȶ6I-W@ov ܔ2.jBauvI0=|4 kVOOFVFƢj-UKu#Rۉh+Jw{c)QI7}r${yRHFS)IK8:^=!" z rh6[̝庸Eʯ l`(OAy*iH%u RC!03nlϰ#+;\$;}&MB[6BRdһo7ъS -y 'ہ>> 7&js+i HJvxaEۉkr׎]5tI_rZ=EO~ERV#!Cd!t97_Ŋ!w+m[8Oitzuvk4d͋v, AnXvr+Ҳ25+䙦.-8_7OOBˀ@ii %X(aׂJY?3y玘lڧ[{zB>Y2W]yL8c݄+$fJ%FRydzSN}۸I > lM~bhQ*ΈgCQ<Ub[-77vY=Dҵ⳸4¢5p!ZByTC`T!ꗐ`wFE _79!Y5s\sLJ ԅ;x #z9sn!fwᘗaeH:RBy䲻ӒN"^d:JÈy&gZ $kIbDˋWі"ḏr0%sobrP13FυHdexeM\ .,2*]Pj[z}y'rP9jV1{HcNCpu3a~5qIGznLE~Qh <Њ1 v|x8$1\(@#_TvLǻўyuf'f&&5(Ǹae2q_AGHmCp}3+Xˤ` `m69t)V*1GݏF6$ޱF Lȶl`@1o;y 0X..Zz>ІȄ{Mx=m21| }խw4,AL>/65 )uTp+I9;Pd܀cG#NeMطVttn0J0S+nZ(gdHfQ`]~K10!fMյ0$w۹% J[sFJ8"Niwן=c_$4f 7ĴeWG2 7Kq"Tz$4+B#sٜbDjӧc^H^}KD^ܤ`E):m2xY|(&:2yUr P|aWtYrQeke):x xni\9Ec81ecJ>ǴH( ]g~u@%$;ո{ UI#+UJaKMnq*лE^/ˇfmsu~^h|CLri~ լ6=a ]<]B 3=(xT,FD4/BZN iUCqyYOs6L o ډB BQxpPNUpl_;&_ o@K'kkD.7WYj:=ٕ[c 2&Z׶x7 ٳ@H?٦/lƮâZFf4Xs@Ov;:JSyU e_5 ֮"jqbmQ 1zjF}Ѿ}2Ԇter^b>'W_= ͘pdaҥǝ"LEe);}uƜ}.Ehhp!6U7{Ȟ^L'蟠w+M!&؏v ۽(&Z] ‚b 8C%eIٯ F]5IAdZqcbݖv62Fb^pP-=ڹR1&6۷Hk ü]Њc6Dkm+<\ [+Q O@ݾQU|>efiv 6s+? B!st99ѮiA{qIn3<[ [AFA"Zzq;ꢌ- KФ+ٝU3@E`W3Ǜ&}8=%*س(ͩW5SyqG|n-`~~oh0Q~3RѮ[HWQj n=L%Ū]9X23b ߓJ3&BcMRZBP Y9x랡wx`o͌5>8:C5-g9UdeGU?# YH;U'GB׬vWB\mq(#;޶ʶt>7da pncBwu`nUʹ'=#o__77W!;cI6bzDhG6AKvd×W%Sߎ t-NR0>Ex4K>2Z,iY»BEM_d8qLo/bP:bʧ.ݥ/rLִ_U8H8nĄV$ ;5w,% e틟.k٥8k{E&H[SѫMOn^I!’'ŅbDɳrT6p, xIh'ȳq0/}Asݱe˯؂s!If5#F\DJ|<&z׈rMж-$z0KKw>aDs9i|UXLp?P)j5K ~\R Ą0*(xhVuyg-F}wl` _e+GzsD"GwQd1HĎK`;ICnUwC/@4R`|w+bxg 8:RF % ߮F߾l`.+K` |lTͲy}v$! |S'4G,NY訟Wn5.=lifc 'hm y8Ēɋf1aJ1- 1G+A9/O'4$QV'ť&ţ NTk]TM_N6,CV>뤰 kKܛ=2h>* gIf0{pF:=7e:P攔z-V/R? L⋅Ń|KJaP~nK6ᐼ !`X#6Ѿ_ 1'Eomn.uM_wy%Zai'ߛzZy*=Hw}Lk?lf2K>RdEe/9lNL*֙Q"JuM"w!_ ,NlIB%~ jИ*,u'RXNrsބl*m~>ąTd B5IZшv"Y+TUFsGl0hTMI@;7 ğ4_Ďw>1:n(- s7/Y (vq=;'aWTEGtN9F6θZV 1@tB.XhPE%C7J0ijV!un=Q ##E`y"q@o_*!K\{;o&J~&xDDݖ.yG`W,eu\U(`\I$/2Ⴘ*uDfC/d~6N`!\u/F(]hGyHA-{WOtTlГTڲ"{\ma]tcd :h_!Wa $-vW9F-YIՐղ7?ݛ[}ٙab/3b`>@}z-EB#߷_KN%߾ی>Zx BhQMɳu;W^9S,!`}_T[K2B;*#P AH%;S 5Es*Hw7kd\LĎ*`6_gX G~&>HMn>LfhJ]WgC%^~WϱdD딡_uVl=|6< xs%bb/njFp!C?<4*&O6j#Le8n2d~4msOh}讝P`Y\_}A5]Cv,#_vK T61װo6]UA]b:us  . "H}㨖DuÙJ ! A1zWIN=V6'ҠscM9|/i[{JtA ;k| I"=$vt<y;KsZl]U[VvXxD+j:@$*˛TjuURXe\e`r"0G&^kuR\ƅ|M#vD ȽcmF\u2%~PN&խ2 \z}Nk{XU-gYNΥz[>8;q*۲6H;rFTw~F E QwO媵*AshpV΍o2KFfn7j8FmLiP%ol7 u'2Ot,K<އ弻NdYcm_Yl9o`Pz=N׏VWgXqЧ¢ eA؇86n>KR5Q;QuKDdы< ݥ'%NaoL"$Byu]lj>*䇄wխY5]L:seH=dϸ w c.vN[wlXş_7FoV]˽V6.L T/fG`N.4~+Ӄ]0bg7=8N6H&)$}S0ݷ "*,J"@2C -lB|q[|e6SڣNJEㅵ; y%]{yqo?;T` hSQ,Ĵ ߱tQdIr~lbK)L禽ܚ':=/Af&ȅ&t SR׋jUWǣaLn16zcnBE;HH4WDvbcTv)/VhUR < FhQe-JA &7I~(X.}8oG?w K\6*pO3C^f]t( UZTZ+N)ŏv0",UyVyhYףh@9QsG,҃$ ClbLn;甦xqZtXIɋWYB+{]y*N ͆[uؼNy%e1x_yPI 3@ bNLlSp[V}<5S´lv0s8€_ sueeb]n?hFʌm-F8819C+:d,v;Lsb1qX vmrӪwga]ҒW4dv\7ɷu0/@Jl@b|Owg`1?#cz)y`0r pWl;^rdj,)/poR8C۶y֌խlEC$o?'~?ǔa,CvYˎ-h62~z?/ p}w-tjvp13k۠v5(*g"Nh8 0a/,< ֏)Z^Tɮ-Z\@n(V8$ s8֦y$MLL)4I 'ʃ`6&J wc`oETeI d ;fyǙ\RBIZ>V# Xrܝ3_sgkj#͗'wC -JŽ= BL8Vm 1)/)2Mg왐`Q?|v{o@S>_,X='%V )9z|l<7UUNI1>{&R5MNz&;Zdl+aMCZ>r 5(7'Zr/ʴwǪVXsfāyjbO#.Ogl<@5Qte)Tr|`/ʐء6WF8q7\1gtM??[#c7()rS;*%;J!,Ff R(uZۤg3mȧ :[sՂf7r7F4 o "\c^,Gc8 O=(Н['iar 1Ѫ'vٻwa!7Zr^dpN{AбY\k*fv2Ie'9c3 ;4'ê+W "hD)%<5uZ1?ytӤ>Taq3؆8YPrJ3;fcws5hT: X{^lg܃5.V-m()qjKVZ@h! ;}& , '65;ފҮD[zWC*\m.4ʼ>Vu53DI=g뜟ʙA*oI==B-BXԈۻv]_-}J0A㘷)guNzE'ÒE, 2 =e:G@_r ȰNM5@kN-S2Z,ބgVĦp1JctB0VMok=~.!%gI`+;cZ@)S|FNaWDt"pjJ0C?Bzb2Ԫ)U:œઑOüܞM>pH6NFeHneji?рE"F'p7/"`"!Il2{J0@}"t L,U!f_7c8zgOk ٣"O"MU /d vYr֐,:8QA[/eowV]lWOrԸH8:I,h”sG)϶jKG]?A8]mո,qoRjYO|K©ek!xzi(̰kn`2&zuդ)p*8e&uooQWװ0,M%޿vTvzSLX蘭doGF+lEN385T2vFfr ބlc*v}S.#m0j̰b)*&(ļcE2ʰ2|4iETc7ި +mnf٥G34j׾]‘=39 ۛ5opaâHp qDbL +OtEJ u ǀ%eY0RE'o&ad/i-LQ_{wjegk`dxF| y>등;K @n{QڕpjjBDU{_FM9Gڿe.!P3Ҩvb%g7)AZ;d9qMN16mAq{6̣ g~qKD%E;@ϫ|KHX?=WvE RkBY қ(yA(5݂={jo H3J)ncE^:Ua ̗cAK ݶfcJ6P,od'!ϲ}M3AOXjDŇm]L3\cwDO,3CL9Ķdjc {;YwzO^̣-\ =#}Ȩ,WYORL3r1w5B󆻠 2!@~ {H>nq 53lݽq$/_ }M-=S؟v9p{;^Uri1^v`32j .cIΔIg'|qI w6X )u&~Xm)//j~BԞ]I!t: O4I+Z7FSA,$D:#Yj- G+8;fAb#1&boDֺ}GV9"xl|ޟUL] ~؄fd蓺z!O{v~ɭq &Zu{ X-b'Zҭr&:t m'`=gaPLs=sz88AG7hkCy,0s}89G-\l&@_K3| “vgYw*--JOP+"_L/tgaȗ#ž ]L[-Δ`#d$j]%l-68/ 7]J/twRY-/1~ӗə&6ѷտd֝m)5&n{TC-9!vZ-X/ZEKkAx%'7!`H\Θ͋3?L- ?WnPnd:Qm{]uBg2h4DdGLmWj"Un^iVǏsQVK7U3~@ |"c$V3 H\]tHDH>mdVG\BO^$ * 'qqV^` fjk5Xuzuq`"ϔ͞}QR_:a!bq"L( AfaS46O{dűMKygP_hT˗-%Ճ*nZ^`E^`ZIBHtUg0$281!>ځkVHRj?XTlZ7sϧxjh4(T"k_VFk"DlSS|gȑ0<]IIsTQL5ڷV7H(YzȤQjHiSLlˣ6 GNܓ6wϣ9S<W\ 6$zS[&sUHBD5VϷ@n$&>nTAY\m"琭94W)<{mcNO^=wy99ŭfI'k~&wT`¢=?evs\Mn$"7 ZԘ¨Z#J4:w , '=,;Ǩ>]CE &vf4Pw?G3q棘<'k|ww4 e_;|Ya4"oEE( i7/ 9fS%u[p.xDuTs >/ IN,EH )MDlQ'<k~`ĿEʴ+-8H[_*a֚=.؊}-s /ޫݘLmsIcOVh} EqN05]@odX}rE CŶ\Xf|=(+0wlƉ\F .b]iYoIsDD~F!"XIG%V= *"iGHIEJ-=`|!*02Szax{ڡ*o&Qs݌Dךؚ!z+"pBb.}GIo[3Cw(kv58F \T ;JAjڣ}gҁe0^52*3ݡbucY F/ ! 5G{0ʔWKU l'h !a^[zYSfšyg˞vhT2Y!As% =)CYl{!a> i vX6V59(X\jGRl̾AS+uBAH@\#sʃ48UsJ)G ,SeG24ï`K¸a3F5oudz>YE)~n<ЄZs-}FXɂKF\p쩉liy2+:j| Ǧq{`TWo& O!a%[_QfAѳ`--jPtfIKhpt<;w$S.N)^l@1x`9R/qC-HϒAM#H7+֘td.CV*B&~܅Eh܄k1tDayvs}=3O,azgzW×P.M:w}4 CQy2YӘ>!{ϥ/OBܶHk nS`V,ܕpy;jӜ\}{AXM !⪎C^\F I-@iB0KF-O20Mn6 H9H5ՊQKYrfqt-|̳m#&UJa$Ԟ}T7Z(|>~B%=6 #ހ08#N] Jؽ5K) q#.D_Ǧ4b<t ݨ/owr$;҅vў zXǬӎa7DhFtJRySZHi$&P5Tvܭ>02mR mV[ޣoSD׃M=ko,{h牆9J*nїܞd5x>Hܰz1dI\hNԘ]5n,,BSPsy}vr,F#lT-*<j"L)1I9 䚘:~ BTj:ZHoO4K,p{L')b;+Oڮ nu]KB_pjʀ-3W&4V4&0Wgnr{Qҕ1nZ2[2HP9օ]C•2|n'2O""ZMp1f N֪-kC?X,ћe|w!eu]D0"%,#z"Wr҃h9*m?Փv;9l%)$n#1s c! 5=l o|'VC5?Y"S99kȤoh(>KZ=RrlS|s ݟ@cT NhN|^+ק|.&X=rl >j !ƽ~uY%. Y PȮ]/>GD:+biƧeZQw22TrefnW+xg-iL׼RPƟl͚&uaށ${PQǁ +-V' Cl(ݧ"+AE dֈbvw4n&'h5AF£%N&(`P]H)yb:{ eC6NUյ>3Ez n i3C7S-HQ>fi"nz黭ɽ(])8uTA̕CQ+E;ݪ @D64.%-sGA$@G-$`q |e:iYTj BԠ2_b` 6]UwuH+Bp›@vh!~bIi6@>ʅ>`$^^|*Sg3í7 .f\k_2-z-"`r|}1$Ѳ!2Uk d.1lsgasA"uaʿ 387pr@}̠c@җZrdMQvgfS/qFQ#gXY꾟9x£) GTO%[y^M5F+-_^skJoCvJ2l'5'/h²dD'Rb|i8yoǓICShpsK[ ˙bD]߃"N!Z,c `($0ZnRBMԽ=說,I9h=eCN+Lw]r0om  K)w1Pq~lNp^g='3MׯY0Eu#T#R7(KD{]4FZZj%KiB2toz'X,*jvqƆڕ1K-68Ϳ'bk+`7M?h0׻-u~:&p:nf(3E$oli*"zI3rsjDa;nKn%{"A]7; FvCwc]d"hg[~:bxU?׊OŚ \i5We~:N ix%n*_>8)"nG (vKbRDBX!:M4!n 06KU>2x |U z9w)dsRm?Ƅ3kdlLJFjWC{\}n%VUXˬ!h0TwA5Ft9NK gp\'3ϻ"qn1Ymj"}UÎ߫=H\],?E!\~OP%}&؝3a&߫'3eRM'X(YNPK0l٬Zt6|[˻7.5qHU orx`4(ؓjbfZhe= 0ttnBx"SG"9.  q Qծq5jN44oaCdMTb#8I؂, jf }*?宿,]Ev''x_!0f?orKnIg{Lt>:_!#ؐۡ `r(!R-CLALffDȁXz;\@MY0L qC=%4>%$1LHGus))wQ*s̑ͣТEnrCݼVYa&^GG2J%.&>.j:ɾVL#rzZX]]b=D7JfZ~/~~Õy4! >Kvk%1)LŸV#i0tv\1ns[L5bjjm{jr0cY/H(3z `8P2)rJ 驟M4R7UL|2ͩpk CQC~#fbvsٗaˬCVYJvoLnFӽ- K3oND]GD+1FUX/ROd?Q/ƠEqUj]?=t qtsX>oFirx}!NN# rucR=SAmP`"mMDfKPI-#,c6%zE aKf |,ERׂ5GiV`3y|UW8NO< 1#d`ۆ\ 5dB*-q[m(&yB[(z_~_BYFlXaf@ga)s1RXѐQ8~?`߬JY5j3/y,ߢ$2/rftP@i^ޛ~&ߴu1frp@E,i@pP097y>-(nX*`) O2Zpir :(ӛh)ӓyZw0L\LJcos3-k}O>'؄yGG2q=_5r3Ffc.FWm9Pz  8T$8ZD4m{*h[mVc*ͪ(k OkʼX3(Ѕ A%F38(Jh ԅUn:ewH cUZ3_H&x#1P VyqJvI*3SI2:q!Waf| m'C'Rl$z`:ƥhKPDA/] ݇sWi͌(TFg`v4:`2 Z61.;2άr̮_{1jUd|ks )yA)y}gnpaN9A)ܦX7򱳬<#Rqhv,IE~ [|=w>]ZM&)t$?u>2/B2z.6˛\C`Yw }3Fm"A2ڳ4+Ǵ.gKޗq ^^6W4_N~-7LjIN`@e"‚'u(ZX^jG(Ppv `0{kw5БmQVZk }\]E4!kO£_|| ASS~'ƅ>; :٢,`djB/dg:%Ddx[vm#NvK`20ja9gДt1<,eȘq}Lz5Q ܀ \`ØTġIJgɏS4*:չz|]C "oK>n`=WEyr1deds\PA^huf |MankSo"?U ?.0K &t0H(]!)fl `]o?F0&g ߄s돑mM,'ry2LlV+ /E D!ʆ|J]C\p'5t2R= )u-jB&sEϣ l^|~n6Xy2x.Mv0-ƧPrkfOWm|ݚ^Z P7̶IM}ㅏj؛\ahB),#dq/LB4Z%۲9_1yF _Ų{ ] *I3$858t]e'JB4Ԃh \64ϰu% -} NRBj+ᲤZ>833+Vӌ&D/@$eC}$:2|޽Gp$@.doJ[QZ;o ;E uH;uGLp<:?h )",3ToҫD9)8B͊8 g(*I?(|vIRL.|*4tUf} !i?lv ',柊6u hRJHsLuXՈVlfvk-UGf7{+ۚ7EĺۈNf:B Ajvj+n K7BʭФk%|6YBoѲNg4Tbal73vwq̿ .iWp w#e34M '2S:=<&h)2?޽`Y,ƬZ+EQt)X[; O Jl@9'r6-EJ ;mR߈|G۾N/Aę I]Ys2e]'7` ?]+*e$aȪ鍿Ȅ^l/KN"tQ(B92;2ҵDu4zzG: sLo1-?ޔ(U=%Hx29tb:[Є$_3n5e&Ut|ju K$U8=Ycc.#-s>=yb {8y8e,ookGپiF` &M6$j TE9ӆ8BF s}0 he%n@>Di'X!T6^V,qL62[ s뷠q)$"6S=g$?z% 9z2#I-W?t!DTtK"C}=褘h,^[JlԉnRV.:rʎi;mX{ SΊMn?^o˩5*Vҁ]ŒlИ)#5~# 셰$5/5<6,fC?SBYʉ]b`"ڮH,@qkit"^^f =H`o{WκOY/duBz1AJU PVJE'>Rvj9ީ8U fv;Qaez"6u8A,JB02ML`ɲ{3hz->P;;R A71ս~!QKI6?nlwG ˻#"ſg=/j{X?3I%#7UԟXۏ@@4?4W:NgJ-ȣP@L3L<zT1!.=ӟf秛ލO*(7͒*05Kig8D-]UեP*H1D L K2p\Da(yiO9/.W'QD=]@Uu9W",[WP{7!n325VOe&&#ɬ A#S)Un?Ֆ ?НfZ+-\A};8@af.>!tuoleve(vхa/~ExA;p8)U|$y"8M ar{1dP=R^ޭ>t$vw9 fO|=C"Qg:?ٍi)I( ^6@qOpTCv1WE{hZmsd'e-xrA5&WLOwwI5'K3 +ȩ23m'u|bWA tӔjöPV͋˳p}9pO@@&)s]$x RvhLNW; "ʛfA-DGCW|+6 opU]YO`[<;n9ٖ̰2ѡ^FRth(y&"JXɏx&L~kٷ0܈F,gv'Y{V7zn&ͣ3*YURz!8pXl _keJTIןFI?lNW:؋ FVE?ӵڮtcb^US E4sw]p|-I͉(<`H:W^ћLKmBA0mJQ` akmHmkӠ'tƞj/ykA:}*9J:{#0:ʻt`0o Cuo[WfeLEkw +Q) X}P-Kòx3Px/7c ,=[45UgQ=ZMU|&!7?f Ьkk6~Pm ^Wf2hN`2E,tz~lul+cŀE*]]Ň~ rN4^>P%eyOl" @1'Wlp4Ǝ5y)ojgs%%f׿ #,ZcYTYJ6@C!* 0<5 /^ s 0]k (Pͼ7fͥwfxzʹ} bk3gpŊ 6%bSF>PlQ%{j9'cv|mW--5NZޯ4-2\ @б†ef;̽=*$K ࡚%F2nBXEG @/cmH']ם!# ɡC:*sFke#wˣ?hT=YcDX^{5oc!LlGelϿrdbZyv? eoK&gqUJUxHj߱q0(I^f o}plyDzC֛[ZZteZ.>m-KDj9z E"F&ɥSRSMRɌN*m,In2F+chlƍE/]0< :E>͙}+9a~. FYGȝRX4il>kPBY%=AwB~82k=&Ǜwf'kO97_ÙjtچSƯwG !:%sU$H\ s߃6e1, jV$mAB UQ>G^*=5VK5EsQ2iy|^?ӽK{֪:# OnJ6d~7wd^^†_B&b>9c_&#dPTo5\)+i"_Oksb i. sk tsႌaC3BAֿtrkW@z`dcx+L9` e[|Y10hJR!.k -9Q88#.QoP6Xǎua\ uۤaQv5GnWEa9:i)VO,j9sSIoaii;3lo~-Ԉ> ɯWLFjqIN"v2gpoDREr:- +թ*H:IQZ܂3!1mCt_Ns0A7@KK{ O訃i Vl0pEr%!alRߩ)M鲯$PsP`#} ӛ)YybK# i8YW4q,Լ0dV:tIy*vr[ wTc,k :Md |:>0%^{ <0eRГ` Z9_"6<;}VCE; c:c{'lXTN$(-5,(q.< jTO^ca`e|0V%x:;$gyV$ɊŪ-_sӍ_oΈ1 un'T̶Xg] eN ":饀rc1HKܐ E*dMޭߡL5j]k*˳wlT/$QV:KP)b]6ݸĖwwwn2mV%:0l:(wѕdOC#r}:&>Bߤ.S`8=R/`(kk|+a]@KʗZs hv侀㥃)H Mx.P y-{2xhZҥ#V5*K째4N9|{c0),RmZTjpүvV'Cn:7[`BEN`),ͧ+pOX7Ծ~eCنyoPI ʐT[6+Q)KtH{ ȰvR*}D2|pĕC~Kw)hy&7z镟ebǹaԃO+X# J"sdØFvݏp_/3-n*-yg^=R)Prbґ>2mgb`B!٣ TOphhOQŎyH֓,hHGzБzZPn4ʎ̒&N\OjMQ_zL t]G>XpԽgH^ۨ}nj>6(^`R;:')[g!&NawjhZBAMY͹||0iN8j8oSH'@OԤ]cy@Yޢ$2ϻu%td-YI)N>2 %Q@ޗFDG"0/CF< z.w^A tTp~rX%AZ_XIː/MUtzLt3Z%ܵWwEpKFQ*<+"]M*D1{cLR L,?":W"޹RVL*  i7jYDߨu= 4Iv]/%#,:ZI`Qׂ9PO^3(n,~+iJ$?$dwf?O{7%]W}eڂ.8,SVwIk59cBy˯ vZ=x# LmÀFdD㏥x~wscӖӦHyȤ6Lco!\xZ*PaG'dnRhs-:=9t0=]Y!`TV'"Jڱ=ٵ ِˬw(^ϥ&yGkqo7sDpqHnMTO+BQW}JIOn;O[)lAYhbZJ>IATM_cf)3I/-2\cJ ۂ';Lnw}:(W;nNtBuᦰ5TO#i>3rZ)G˗@`5pKtڱߘ>Ź-XԠB_>KBKE$m3@^?l_\_%Ui&6`Y-)+&:nhF\bC:!2Uj&HU=l+ks.=ZN1]Љz_d: ~YV؅]=L'nqג]V?!R%w #9+ĘNBެH(1SAU5(xa0>LMrkhZ@'#_Cѳ%Mnn5ެcЇsv`{Yk Gخ # ʤVLg{,< F@يe,t(ofTcCJ0_.[Y'lBlUsy*hA:8_Pǭ6#!h]i$뵿_Ti3!d1EIwغF6%@!1rPnZ[(!GVVS18 P&-$ߞűM=Vm.M],?HAGoC=]xa+U/DVyPoD&t_c0z~RLA ,t;{X*)iN,6#tKIᄴ 8Hsr4i aԊ'/(s r[F~`[j2]=ydX~ >K~71T|Sӕ:%#үKͼĠY 16rtiR~Go61vl az;sv!4f׼vyT9hx8ziM I%.9P\\X #90Z2yp]/i_]*tB%YXlR! :b>(mob)P9ɪ83."Y'{F!4f fT>oxL݈;Asu,%y%:.&WQrmǪBE"m[Mي{Gļ˜ CF 2UWc,:-L^* \.Bq9Sk[. T}ąY]G{pf%C5^p bh8V?z)ʡ:’[] cTzg4V2Ү'(rR&D@zly@|݊懟93]>l91B=1Si#D'Q bGυjNGxS n ` ݸM\ ,wxd29j_5)uo SPܣ! A펻e+!1-<@wSRDIE!٧UV7" RY :t&sް7,'|8!R5'%Y69 gcEBI1 U+ƩZ9ͶqNU1pJ[J/ skST:&j[82HcҚ>rX.=G'Z!qL|W/;?ZVV)hQ}a'GZU=~m.vP8*XpśD#U]hWR~x`m:4|ԉ 1I0[zڛC`MVTnRķSCp$N2?/G#NJXtL1>!ĘKRxQ׏'^~τnQ\r[xWnnaG}aOקyQdC /94))>E1DcF54D4I8>~YMJg,=ҵu|TnҒ(V\$&U} ‹  po("lrǤ59?ٓ}ȫ[(nFgN ̮3a_><(O.9r Vhڊ+beؽ`V!A>CxЩbuIu9dk1ϩpduIzyVwWᘘrQk2GIY" n{ Xa35.;B2h˷K~C㥑rbUiaϞ{;X OpXh=;^9& &ʭ.e!}yHa.e۪A8p &|Ć?1CF-0ˈ5֟/`U{7Ed)i$E&Uh2{mA8%$~z5f,p6_J]чZIk^DiJySttCɍx-hҪ|d;Bw}[$ {\̒+ΏJs>OErٌ4ie3p&A{8檎 QpRO`Z/GKw3(}&RZ=NbN ;#c9 +.+y/mR.m7E>2 !~ԇs~ۡF"N3ׇtߣ/ Z}hHb eG,83{p_5`iR$=?Aa,e=pe]gKb o?(zfpYiFpl[ 6"%`hP_Ӻr;ڒ]LrgE=\gK]TCH"7(wtU- Pڸِ?QIQцJAMMيpipljp|zŽb?Q{%oqZ4U?0. -rsrO,9LwXľ_^&Bً֣d KcE7 KDP z 3\p{DR{^:\[HBvW*ät/{3a$@NݵR\0%YauT1jޫ㒛 [*b-ŽS̴dCJ2Np5:ØAFdV}lAT+R輢b45G[c߰'o2:\6)Pp$f$aP&nws P3}!lKeytp.`M<#'m{=ߊWIeκYUr(jwlVj.UZRW}4#L[t^6lC?D($V|QxhpҀ뺑3|(0X'y Ҡtх]x(B*rEhe}T -7Ҙ.'wט1MDϬCXzNJNx0蚾5Ji+Kcr*Aeߕ폖1 5X]ŀp02 ]Uj9X q'Wp 9b&Ɣ':[(v;# 7Gy15I>~ TbGaA|#SY*2]E 5-jv1}Ti2F :HT[fu3wY"&׾Ў^:tdRJ:)KEfyw=x}dff,w/\2 )-_YjjI]Xw>Ki^KOToۉ HKG)Iԅ;pw—˥dK>jZ-Lu?v2*t5"xnwU"oiZ89*ߑsp^LG%O09vaf;i]lVk\ʍTg.8<ٍϳ@.dZp*s`VL g$BѼV-1YZoQgDU=HmHq0FNtek*2͟%tyq[CdP1o_]aQ9rC7'xH= -&A:ai(eg|Y0* HY!4c K-ҘGY Ey. Y mGX\ {]FU]ˁ)n(@ݛLO1gs8tK 1GT wNrt_AUº$v7V0:ؿ \,KsLysUݛ8-d^tJqe)#&*tjʕ%[A?B=;jb'2fHkIҐ2vskg,h#B4Ѣ6*y7$!LӳuIQJ FF\Q:2$/3 b|C.4]7*a d^Y gFNEUحUpEAdžoW|tfd9j*SsGNWn#7]v*vİFX&xcok\d]%xe[c$:`+phpMv5.zkv\{f36خ<ǮK7#Q%H"sEXOOX}@\)Wp |[v%dK ,Y)8&ߤ[ނ$ݭ+b})W$x]AQDT6p˗; /5 cAT/@ n] `ޠ6 gzI;eDBU(%ύڴ0>[K1 ?ZfHƺ^%n3 6Ӯ90ec-80깊}P"lFi~oUrd5/{bMX;axoN{~aݸm J ^WA7x>v.Nml}sU9-um3 ' f M*u`Ror$JY C9^|(Tlh_ MbYO:JnuIIlQl~PRw8p{Oq:49 St頀ԁaE)|;˵u"8&*9"Q2fb#ВWQ'l4%<@4Dڧt0Q|eKb<7ӬI+x9 $3]e dYFewvy\imN3y"eUDcJ1gؗ3UߤԧaojD^M @t )|³2L+y4㲫,zxI Pa;Q}9{g%"=XZf9z\`|}wz91rݰ(d81-3)qazBcFyjʑz *y Y,߈(ddKW|'q-7V{H:ᭋ,z3QI|Ƅ#Q.-Y*cR>VX4#.0.;Q]]N:AmDۧLҸ / HJ &q/y{MV<<]p~D9 GGd(3 fqkӁG%%?!4Nkb=dSyK0byg1( Qr{f2 ˡ~f wORVpߺwJt"&CaOR":Rb^ik cl/ejw~ :$nFq- c,=QKs1(bK*؋?a]yq,56ñ9A0 _I N0 .[X^ ̼vP3r1}Xd?VZ Z>f2+ 33[N̩M}NUGZ*=N{ Nx(컵ֵVV\wU_8.r~_.qv⿃œP?%LF8;[whSfaXu0@~=!}hS w!Bj]CZombD2n>%ݴGuFF7ٵ\4:K3@3A6|´ۥBO\DqϽ 0 Cz2<= 0 ,҂^DVaݾ#TV*@rn2%&Y8R λǍd!|/Հy?s.bq{ՁP1/#h Լ?Y2fFxCNϛ3B{[ LzWIw_|o檵3͓$4A_Q^{h;r0*ͲQF5džY=+[K9G;ׁ?c+ jY@wH=X>% r8|#4[՘o `f\R/Q?4v0TM?fAF| ABM6h^E%2T9w"*G)޸kb;0P`[ W0eVt-Wk8D24A ''i2\ ٵboIXqLr"G]處b`!<Zji:G;SZDC/;uƪK& D q.=\l Nw\Nd-TǍzK]8LR05ze e4ԃmR=(AlZ8  {ue>'%F~I@ Jy)V3#NbԢg9jMg:kUy!6bf]P)%bFsuɜv )d<+Y]Ȋ| ,Xwwc #?VY{ OcR@A~cbpҩ %(l +$74pXtY~. F~]Q(I %ugQwٓ&V CV?6-́o&3CX?Mǖd>u,4 (9ei{H`/TJFP }FK3bt%%E1<%6[d,IrG3ԣ\Dm Eþ<}fݘFQYNzdIqdS]|3?^ Ylýc 8*,ˉ=m8p*ji)iHV jSroC&:wҬ̵D#LӶy/ x<)pi9΢(8FvsR"@AZWꌞ)Qm'fg{[DHSa/.NÃ$A']ISq8\k.sQwDgJlUx!a3 7l}/QrgjQR?yLdD$ j 9R3zQo77.du|U<>V)ax-= 4R (rHҵM2/I } Wtj astVhxS XbƂ nƫ "`"%NOMob >F T-cOI\=p(; m*:h$W{]E*Pǒ?( Jv2srOƵ֔R'dVܺޣ\alPy1:eRܽiKsZOv*,g)n,_wY[h9j[3 %Tn˄@Jn4N ;-+9Y{P*j|5VWu%kzɏv9R>HcXSƧk -ӵ] 'XR"gA;R*gNJ{1C! }-C}&[ns uPg{|e;O E4Y- [NC tK$= ^ ][=n]g:䮉od⏶Dd< h+Q 6'1?Zmt/gimItj#@"1{BID9s8L`{G5SM[j4>!::}TS^JU Uϵ3Q (=ut!q%I"`mWbm}j,*@ǡqv6LtO؋ij4b Z BsI#gU18?ū\Û+w8"-׿Ƕe+BBKҷq,QI.RE(U XZH+4Y3,z]^U>J+?@>U+H\3quOy'*~? d)8>ݴ;vtKei7W9ʌnC=<4dK*f: x֫d+բo*D~dLmXĿ8c!Wlgba1=3~~=*lSif3=e_v}ZYpΙv|X'ݕ+rn #3DcZ= B0d9ǫŸ}| raK8 H?HR)¼Kvw6XCAY!xi1X) "pwgGKV|`Lh=&x; *fgU4`kU-AV&}cEV`'؞? ۢ.[@Xq(GucrRjS\glN=+ɍ71n qSu곕:~<^5zq{,LD",VPQsiZD 1mKj nRJ/'ܷyŸdgQYؾj"[ܗH)+@:?`q˾}qtx QN%ƾA7= ۗLW|Ⱥ01ؓ7{6&d[jZWqm6E>/{z> Zֿ_=vߪh+UYuaPrNM[YT K+8% džB*Vh$Q{K +Fݙ\nkD2<|`|ICT?q,n!l۪MhK`T;}&TS}Cu8cъE }SdRNTiCrK t)_zG@rO5\9JPpe4"UqgStAݸ@ A p _:Gx(1P_gN=Wvh A50V'2h(.9)[wfa,Zjt|%ѪlOHVWky3:Fh`*5g:b>6X&-ԥ`:ikUy`eZq5Z%y'Ysȏx`BPj UN2z. AU ?\XX<,.uSi{68`.^ױuaӑ8ձi5k2O]yM7ScV>l$dV=$áY kj񘬛$L)RR;,`a7҈AdI:٘庂4pv0^XG{lP?\V)RY88IƐy 7/$Ύmje"?r7ްZMϱjti*RCv^B}1Kaj)&AkD'WZзƦczǷkl^e^?A H3 Ib/|o7P񄸊?ZJS[H]k%b4at9Lvi䦈'\w8.O . .qduº޾]N Zu+7RK%K4%`r'J߮h*F'/*| up@ +3V8я_k{B>|ť~]%*q> ;jXpM4֐ɇj$'TWc[>Vv1юF%5э1uc9(֘eAMIPG] ~pc&9H@>peUO_yc^5A$i|%^Jl]^;4sl,5_%q -%_VrQ$ыLNMۡ:2C=V%ԙ+F4»Eu(nM8e%H 9zJc8зV 9R-\`OT!wBJߔeˀA.uN#3Q#{]Yt|[ÅZ䬯WaU MC=_"z7)KLKe.ۛt2w;[d|/ӢPt/N#5c$7jI\4Ih,ő \Pe*ٖ#@NZbf\a@B)5oO$toȶ7N;u( wez$,]UoȌHP. Zp-;$'n1oXHj78 \=I5>5|i TV'.WbhM_~d's)jшBADv٩Jص;m>4T5wAEIIUl2gCa#xcAb/A/]lТʰFT<;QuCLVJtk ;9? |%|r1\/ "% hzKo53E3+>`5RmI AV';.GVz;g*L8C4B)= (?Nw{b(y7mb۲5ݔ++lJ) qY(3i7Ȯ-i{j=Pp]fAH>6Jˏ(b$\=kpXZ~ 鐾RhƇ<X!-EFkHN9ԬZ1!͓Y12C~bYzX.ʉqdпr1i;%7뎮PIkf+-Q6adkO3"607I &2=C6ݟH%j_^I*~MiڷӋM<_9S30*lU>:锕U|0ZF ܦk]¿ٻ5mSr:Ԏgw@`@1J;#4mn E.@[XK2?ҹ䄜ZEDzZuo2eVؕtU)E2JqPSû[C/0I@]6~#/yAzbu{%`רM%gvo 4SiyM2:Es.8YExF7`V{^+ uUSU94 <儝=D~Шg{/,mv@q{Kl ?ؚ󜴄40֥8v[DyE=)T ;3#':Te,mڈ!aP#QDxnفK!h"،Sr]&cSȒN'bxrC l@8 9lhq 2.ɄFX +@y꨼MUUmx/{6-KQ ĩ޳Qr%0G^ ޝ ҂h$@ ?Ũ^ApײSQ[K 怀qOMȐZOIhH' *-Ev׭ϴ1!E]跰HW !\RMSizFw6a, .^>5Oh@{E˧>!vfcz9wr.7A( vilWk@6O $}A4@+4əlI |HO,ҍA޹#JSl5 1{?*/X.a&[,FrPy lZ2JzSFS&X |PG/gYZPK!#0!0!snd-compress.ko.xznu[7zXZִF!t/ ]?Eh=ڜ.+MqQCY86A }@!֔JiP ^y2zV9%YF˃Om\sG<roI U^#CeHg|DIY{%bbh"W}Sn8]Hz=ٕQݚ4A5Gz}n R9 gFd6˜vOjך)!Aɳ-}eDfJ,I^"~E ?1t]4tBPH<_kl>xw\.SX49"'3ɎN]:- ;x{L܈THh|˨rNċP'$n\unoFz Ke㦻wτaW~kOpVQ0/rt+=/lmbNݹ~BCWԙ~DGʼn;dI0;I&D;23XgR8Kϒ/D1iĻb']LFײ9Ǐb9ё+mVrn7gFYDp-DӞ$e k-C9O@FZ C;3Aa}x7eu4} ' ȳѬa -Z vJP^\ZV*Yn?؏X,iV eZ,5кhk{fL,XڟSV j_{LO}LŽrY|O#wl s)-ZꇳQ?o НhS n!e?Ss=ͧi}`5gBCzըW:.<ۈ7zS7!$\񇭴 zS\8\)o«d_H{!0&Q̼F7:?L d!ė%W3Um!,Ntc3ፑs+M ;t>fЉLgjm +9oɍ-;[MSjLpZ#1̛[ I64"FbU͠I 1U wH{RODWI٤fz `!dbáuEph$ `#Q4 4rz5?uPm+ y̲ M4^gh>ޯZ)\?_!Aarˎ^T})1*9㣙[oP.(xHJB!h%\^Rns[* iGTNbqȯk/^=m#@\tQqryȆl X1X, 7?&Ulv 8Uww9C-˝%Ͱ̣O@(wq+:UP.H6N#Q6؞?':~6,W-.Aɬv% Q Rp,AkiAx^q׉=92˨?V/=7ih) $p'Kxq+NƴlsU+1&"t)\k2.mt&'a.boZR1?¾ٟc!=[<ǵ3@@);V_^a0gg0/䫢hwmw.-~=Dߖ6Y9¬kȏd8]>aN|RSuL <˖$&?$4k E *ހ l>=:9!ٺrE. #hb٠|kTrⲮdD ǑUM8# *L-=Aj=PXagRHvjbf GVBC>[Jl•Ə;=G.W.1lf@(KW)e"fFiƑ69vX(=&}a_w p I5PY~od2oR5;Z0_@룜$~am]%̢p̷ gvD1C$q0Qq~b1<ʄBIL7_gD3 F vb>RYE*o1`22I iBHNhi+,V"]EV3L?j^zz`hJ87p̢=wwHݷLXy2Hs.YlLr׹@v|C_-S_|E#_3_10t2 K,[&&v{{9c>xgn'w=[&Ɋ\SOꯡs/ AVO3LKcH2Ê|$i^XpBK 3isbRD0@0'F={7\38>W i[*05"=);"= Fgjؾ?TWy&ɇf2e@+ #?xq$5L_g+ ϒYޫsaZW;N1fJDQē@H#ܬêEm[hHu ߺоb@ev8h9!h%$FxLwC83\taTlyN495/A0R)kfioQi'#38jF Q xcmyK黃}˥ˡIe1#0"9,_0|]0w7+R3<.ة]|{۔dڌw_ӕ M;+R> :ǥ;ҊY\EӂY+ ɘLvی&jCK{Kb%WIɀY5=RˠfnmqM.Jh[Xw+6^uT_QQBC4wHIڈ6/3*an=ò\\ _;J¯>$9f3L%,{U bpO*qvA/hq}dctT 0~D.T&3`աUxV8,W!ŅCtޣ;)1Q Mo9:& I{K[u5H*/P/ :gWMv"ana(eB"muftS/}n }[ar_L%a8і [elCxy;,@xlj?!JL!-g:i܋+Ql[i eS60 n3+$ϵFsP3sA=ͨny'0+|zG5 F%TB=\$FOj"I[1ty19oU QTKKS1aŞ~/SVb$tW; .c/Ǿ,J]C"|< 5?nMtF|Sr>D/ ^jo' 6hU3]EmY|ǪDJi9Ug_ ^zN~?L po5f9\y]ułF} nőg͸K^L3+Y7pұ-z# zGJO7 X!"M"̢"&_ƣ`dxZ޾V5-zg3>8*G3)`$tCgҚsL/z^h3*R/"Ѳ=zz*`m֞ˢP?a9<ļ0wȕL/20ߏ2$@I}A:\W(>ˆأ~ ԉPHra` \_-Bq~LjQlr| lEW+,_s$.*A[=iC4">h$~}4@ҝL4C@C41+$"x(" $c VajsajiGҌ^`,Ш+\CiZE = Q-_Zϣ+/#} HsͮpCg|4𛕊BV&~}&7sΉ_<{6ykG $$U=u :GDĬ^ Q*O_DMڦPBCxDQtNK{yy D}*Ybi̲h98xoLB?g Vֿ6$d ]1y-FS{+F]&(s/L_JMYRזzN*e/H  C!?)9?Vjl.*iIHl B-3)@~ˆsJQcL|dVFѓk* Ln)O0({8~ Kbъ"H}ѩ7i>{+1%8~Av^=LF8عVVJ{pUjX2W6e"^c RI*@DOZ.t7 G4zViV^ r#c (VP+$j2M0܍TΌ۶}mZ|aMP*d%*#iF!Ò:*;Y*NX^0M5KSxxB>p=97o 9y34 NDJ +ϯ$wjG2Ppco*Kk);4ujzƋPPzl~Ḛ&nLkR7߄WEӍ +FzZ; V]iӑu#:-S7b7G{gq)c/73|!?5Z~,B>1s@Ǭw~ G{8`p4CK2FZV6IܱDž }lHtbCPK, B*6) Ϟ ,X ^E-hH7dnQFaLok7гi4{=Վb݄7~Јz*8,U[UW n=#32݄_ Af0ם/(~LP*dJ%/";̟Ti-a#P-ĪsQs &.r#' 4N]8W]-nl*(O0(aqaqU&:`qpG5(4\=mQ;ps(h>rbj7 B*S( M-83"+: s~ o8 Mc{)Ljp uaU:M(lir/ D q)>b+zHMP]~i~ol9+mOy݀M L@'/k rs>cZM e1g|/`x }Vm;!m-tEYc: ] 6ږ*ln/:)HwUS"gʪPLk%Sl~זϑ@JI׉cAJɝ<)k?vG'=a4O6dA[ZZ=N3C"&)oݸ/M (YXs gY]KZ2? Cv޷cq&R"C#+"5%6jߨÃ[|9IHo_PDm=4ꐈ^[\1v} R27o{yӜɞ&AcSydžDW`^m> tP$r~֣aܜ_NY{ :LO*ͦ~RVxh(C2gU VC4=^E[;r\:/Rzؑ8;5`Hld*wFA8LDA¾zY/uƵ,U*^~클Y{@ްm B>1An@w'l7On`rC@%ڐ~5B&ibҘ@9jL—&ME̝ >ϺLKOVtyk]<[WLs El|9>󞵡) ܧʹrƃkPB*i_+6|wPڢx 5Ӧ@LqR-ѝNխO*8x3x2 D~|N_W-6@]r0qd I1Rw9O =0ҟ^E\ elД_Q.^tNtx5 ΅-m&A$ b>/H=P(rҗ1"P<ȼAu^M^Us'\LR6sA&ZI"'?.b,"[*X8STj4:` b Ιi[o? 4)q=[[*3;icc btpz 61PVg1w!v}kB0&x$S~'V%5]/X >Tt*=P*M/7%[ӵ؉Aف}>f!4z<ւ{WGJ??.@hͣ_GZ-fQ62oA!G&8SDktKTe0KZj,ԳA@૟tF"&CN,8_@h?ݒ1n0TrAi)9pNK̟B agYZPK!wd(00snd-hwdep.ko.xznu[7zXZִF!t/U]?Eh=ڜ.+9.ąG'D`ǯ~Ej߈U}hP;.| beSDM9*wjrqH7:athR+ĵcs8na3ͬxr\SQE < hFIڠ4 5R[V 'M,7~ή;z3QQReV_[ėmã'r{D`/EɊt$Y^z}eF63{VFx|[GX~9){= rYmYQ,oH;W3:ZwfNXs:H BaӠq#Xv:Hw60g> '0]gEAAhI5eK>K!G3+#ݝRBЧa rh?ھ3ߩxYwPoԟE77d%6`dh.2S1r]=SakH4r m' ck(EPQm/L> J;|Do"6ɬҕ n%t#]輹@WvcPf;@ߧ|Uӎ')#6oKrӯל@"KEOr-w3i4'sgA|-%shh";F0s|\fZwz-J9) 0po+ @gxJ:tEʊ0+nJc$ ]z $LA{[Z "n %td(-Ì㨳I@{b w%boV=#=^CℊԆi_yC dO|r_{v&孎ɬ)NʝCwaQ-y gDg8nn&{a{+|"׭0kbH#,-?mvkOtk7`ݽ2Z/ͥ Fb 87Y҉}@Ca?2fp#'t֕"x3Bl8x*F9ӦJ>z,|I] zL ]]0K"ႃUSQ/66`8e' H 4?~>U쭬}ϥD2O2bQ>^;gD߁Ο50,s7({R|ks_9)5CGr)_Dt>uraQկiCƬy6(z $H7,tGE'QIrKA՘e?2žKʘEۇr:u`] . Hb 8%@GGUYSAڔZئU[\VF XYqv4.J=OKu JBtB^<2~?fnn@Tv]tr)ㄊABS(' ˧9D(ǰ$\U w+[(41yC?:h_9$Fޅ9FOȓ\,?u+`"!̄ k7cX]SY1ف?!jVbt@m\z9\Pފ-n|_xut1{Bq6]KM)*W勀MYz aZʀ|O rpa@ '=xICBR61@$lD5AGXPxk|TJ,^ 2]gYkm{U:"Y!wG 0Y^w+jwVd q*QFlWQ1ʸ<4M-/3% CO쭃<(I]M>eO =-洜Zs:ATͷxE+z¯+k͏ &*8@)-Lc9hzJP)NKsgEz#q_kΩox%[$pUՍtrf wKu:πa{4wo*8LlYM^tD5̊YRm<ҋqf>>֚+*GYrp9pt*0qAFo9p,q(0ͷsAV >q58NDu8pHtg,C57-Xi"4T6,ݐL*m%[ÿհ$D!1jS64V@ <8ǸkIi`%v"{cvއԉg %+Z@"| r.S1BtKiWHm1,'SŅ8K -~ڰ$]&3eL й"j=M, \:tXk(\p^NdoO<(#mVDc*cQB-Q#,(wh; Rt;:f|M9[v |A__,o-OӍ*%)b삳nm,-M&o|hEڂwR?Gظ9&b`Y $YXuuw'#0Ok {"SyDKrvԦFk4m7y[ldEϝ 'CS U R42P8z;U,Q$ =vFQ6+ß5)*B߸1LE XVo;>!'/0do1n{@qXAm2wQ_W;b5GrX/ӑ>V>Wflu(x^V ֶ9Nl+n 4I8h40.C%,ԺNÓi tyUUJ)p‘f:i%?1X0f!sm PNr:Q<8r;%1 |wUbg] eiab^ EC8'DiB 5&cgIk#tE=˫)Ǧ/i#2 #q:E"؟zEn}xGC#DLPʉ]*@$fU r_OHc4A),c bc40gx:xS/'*?Cd1m25Cy@f(8wސEp T.^+QɋW˘/*dh{&J7%mݵSăk7OTC'Lnn gML!=09;R7h#~lDWqحZR( >ʹJWB+S&|X<ٶ"a^?FMN1+r{/Rߖڙpnc;LpmIt rgQ(NVGpkxPFܷzP woO%bS§7):<5JQC{Zx \^ƸBQ-pQɉ߁ fo$vbwgEúl 4'{aIn{L쥏*ȝWJd*q6GUl&;ź-2HEPm 8ci,ǍPԂ鞣5|^L#pG6rp6\* =~ը[ŹYR(=l7qO#ߋ&A4]+w4~UHfCz4GA FmX?!eRS5S5;*ejׯIM~L9!y\3~6ѝi\u<r_Bq)+';%][yYN_tH]kX$鍼M_'jGB+Bq&o|SsS\"3K,Nΐ-&TU gU@TKu~OG'0= cO\IqȎT$K8R(I|U"/(j%udyN-2/D%YjVhD F,7KMi?rՋx Ayu9z7BAQ08prN,~p2)Xɖ. S+ 睰c4_KU}zRXX5:?odM% HϬNt$vyyXF)LsU_kCwamo5jYFiD)@=W` ܓfwdab녪YY c]ԶnYNȁyn-^؅y 4k*GWvfkڇ[zk_LS- j7Ap^U_230&/tB?\$?d:m69`3CxSeH"K7TdE֢#2IP;|*g%/w>G'.)Zu$;VZK |m,Q"MI"bDp-Ã_W܏"ͲXDtxƪL2IȜĺ:k8͎ƴRp`tS+^jQn _ U?E-Фb4/g47,b,^zP<'B*J98It1`P&{ V|N~QQ7t{2b`,gb7X `mch#lG)kbHTjHIsҫ^`2J+giϖAiTͿ!Ӫ8>I!P~RW0::7te=ȋj` MN,Tů[U Av!k Z١K̝[ #T[("f$ Yt֡C=z>h^9-9Zi*{z5+91}4=cu\r/J_"pZ}o1w0-:~`2W_"DRRR\Z~C\yI2̙.cEUpk|dz3j#GA A+р Sw)I-GR!rʊ3Gٯ(y"\pHbGTV#6QwNZ";O ' ak> .[>%`4.vRph8zRpI}jXܻRV.GvGepQ|Р$X+sEh;өK.qxۦok4r-Rvd%gd=0v˼qU@&])FʼnY3kaNxqyD@3:~9WW>]tS;ܶ8?S8G,1cΚK(N׿e]j|%+Nһ4t> {hxH%k'J_t9PSNq|zk:X͏0\2F)x%և"n9χ>m\~ZV_[d|;_V>ؠB#N2{k!nGp'`,Ѭ$[9rP>^wnb`ju栩4Oc?0_)Mx]O&ApԂ0(z9/fSE[!x9߱zh)_gto0gbtI$v)|&ϹZJhuX&5,DA<$Z\{@],S@iď?ib)c~PDD/@3vHA4}K.2΍mZxotG+ot. s$_ OJ6^}'QTt̲dS4Am ͫ\22C*gL6Lci#vEmVz릍QIָ!E+VbRpDc `s㘨-3n~U):q+ҜYC;@KҥrRm/T5X"0`!DWOԋY:vH!(T uz5Wi^9ʬw1K\gAP۶赕JjHaoB˚\AD?M%%_ ?7Ro !?1{q_CᗠoNW{L:iـt~9I,S]FoF{Y&"w؉5j"ª]-y'3c+4hϙqNS,$W7G,J] , СU VX8luѮ)$c10ڱoCZ3G@mAbe.h}zKaq-nYu-YʰhY&'XNpm'IڻjGAGcf+qV3 Fu&Snns̞@R=(zUrb xɲnӝR$1Ic{9OPYab6y>q-' ^ӹp9󕖲znڂZ~}Gu "Ío Clܢ#ͧxlZtY^HL.mr'+<)$a$ C 61 r/1 "S12ldL(UuKg{NZnA®W7 n4r8]YQXW틉5d#cn*<):YsWA(G L[6Cѻ"kS .pe=mf3_%=1߂^İSJLCjB(x;EaQ|g*VՀ*41bا9zKK'.a q`*; Cxh"~ ]%Oe7nst qE؜$5W`7oY}Sa[9bU;[tXK9үgKJa\ym[;'l_c6A)e\J_|-qmWVaS#͓hmaDJ+H{ 'd0:>سWA wO?bhD&]xr'Ȉ$"{$ˮGPZ:Ǔ8 =?2w ysh:eo KY zK_@ 3Y=$T#ԏ g o!ͣa#:|NK.J&t1A)sFE6S!>Àȸe v;_/Q4z܁ʌrn""; [UD)A:mj́wƠ322}#((PI7?ѶfƦ 2؞argkǻ5=$c Ĭ)9JH/w%њ[3@pOAl/|4m=a'L)@x{va B݊VN"B@^Mƫ?5p?e1xR=?VR9ꭲx3& qudh_Hծ6\ E?biX )AHQq9PVɡߖK!uݕj.=Gbz|sHIܿ GQ)P ڶz%rO\boqi`0Ѧ^J.H 'dEMT㗓^TJTUSǹQz^}=T*xaksO}ƻ+O AS6uhz6]3g4F<̖SnqyzuMŞXԋې }> VKKualZOeE'd/'G|DחN5[|B˗HiQQ>ӽA'rԭy_=ro(! }U9}A/%܏T@ƨ2XX|7&+nв1meu-|ؗ}P[6f8Mhw\}W~lF/w$y+h?7|BkP̉˻#'+O*_ =sU50ҫ5SK5g¾r-8B*_F(( xXDɟxUTLXeC[gCda"] "l_a?I䰵Uk o S=m `F~s!@^+M0izƁ_xǢ%jC/ʊ]H#=%̮dX3Onn~[jvR:aN Y  M{ W)L<Q*'!<2BSAϔ%ʵq#`9j "_ls0IQϕDt+׎3P"Sᓯ^Y6JJ- Mkq@v"||*Elw fxzؿ8r <܂fsYIv S9sۺ(j*GAU`s *3`C|C挹 N"j3&c`aLǕ6#`1H30hq AAEL$gu{aoKŲoAKEF#h#m M!-f=q0aJ-ٗہT=ޡ]Mb7A-u!j!-x8!4#C +Nj4 6ʝ{.ѣM:0YIcn4CR{jeyZ)1?8/Z4ԙcgw MiDEKvEXrLZ ڢ.cuW#ͮi\EWaNZ3&;@@BCVj BǦ-4縑[uXĤ5z&KK:M&]}Jԇ<yʫ6~iADu+XCX8-nΙq"}җYS 'PH]iJ$>)2"Y* 0 |àCBo92aXΤxLN/9eD 8^? Q7#S5rPc59gZ?ŲUiϭ5:TFD7_' XR/t+.  ;Z^ oMdWnm8v< ~+mk~cjƷmكU0] jd$<ð$5 <+P[X)O<7^6@B׸AuO {=1+ [Ùeƙ;?dovH xx6hEwp WMkg&<؏M96πu ]'(dq?|[PHJ̕huDED>Bw9ԓ8IubTrb`ib-8I-o!jJ|_|-Wv# l CQcq+!jQ=5Q4Fe+z.]^9D%  2J8d~0KUæ5҇E#W}e<w?0er!K[H$cE7}GHE!m^Wt72S|+1-HI! _x+X6Ǿb{^1RݍFx$Q ՃYAؚj*_\ȔFLΆѽ>öPYJX>: 9Wt \*&:lpoEC B?JB}h-CUh11Qm2pLzrܴ:M v%JߢЮlNs*4:V{ c1FgXRr"t4c>qeuieuL +xGɳf<: (V;c .0PO,?gXr_F_lT $Y8!=، ֧HvjmZlx+n oAVw،1o֐LZ"~F09d#+Ҹ`CQ4?kpZmVGۑ8AndQUU!F'g T^5m}:i@.x>x^2K(C$J5RIP=e\um\.ЁAxe+R ,T-.V !/yDjEt#W `S 2;hվyile\_p\K 꿲oT' /)RLT?zIlv,iߏ!otҳ%~J ?i󈲭N ! 0!ٙ|v LhT8ܶ4b`3oƹLX}Jmļ\[92M鰿>!@**nL[#LB\{.9[.ED{Q\ ZWrcKM[gTt9M@S48`r < V̵Sg@"hprn6^)Y8\i/j1 Zص܉⸞"&G&VtFU\;2ĦŞ`|oMcLXY~0W`##[Ize>2SIm56',G™9ƹzG9N=Eyȗ~` j_G 1bKeS5s~H}$#jgBO&AvjۖbWi6¯u47%4pb*H!W:6`Z!jFu!BtD4,L|`F/i_[g=x pfW\MqkY2̌ ^ďc -._Ѩ i4L Ir)ҽ`"H+M*.uzCRG{x/}Q<'h" 1bZ2Qɲ U phʦCs|z/G"y wd@ӣh: @QB}!giz]p39Lwzg"#*=I1gờ~a@{dz"dHś}7čTy72j =ȇBeV q:bn^BFODk.jwl|h_-\~"Z4 I>b^q?%xۆk,xQ#M*Ӑ`+*ϻ_8?o},'4ƶ=^H擦{WunzBK/('|l ʈb޼ū kDQx%g3s|Mj dB$F:6X&z`b&D9 b飫lW8T̫'RF^ NḂ8ne)M *Ӂ]ϮLe,ßCI`)?@W`BT܀Yq79%5maz"ɿ rkO P:&U( Z4|91Om6@99g+ *deО6#:?H!i%PSyΣÄ[AE!Ӂ] jE {Ҷrx90ɱv.šT8bOmJ]\J`?"S߭TR 21W6. hmhbТW!7_8$lބRְWL=޻?FP@(;GzN@DgS+uZF ZHx-2`-xɕ^F =~T8V"ꤺ5 #&TK0rK%'3B ?E?w^^PI. P 8L V#pBWLꝺ;t'~8OFE:ClɩՠM1hͬmN>>Qmy6 A0Yi>?t!ԣݰb´ 锹ai/.\j=q(Vt t0u7W˟Q &TG,QwLӜ5HAp5;am4PK2oqQDܜk2nDӑ(|x[@}BZ|n6?O9 d)BC[(*b`%\>Xɧ'K4 /`p %z?C&:H?yp,zÑx+C\nrl,4?WX _-?*6;Ιf[i~o1Ѥ \҈.)ׇwSIG( x³Qd-x@?%[^1`*[;5Ʉ(迹 |eS"#@%xTEGleĸ6)CŒCD/*Rl`?e%2phw^T3mvnt] zo'ːY睊"{Q`GjO(QS-D>%CR5a%7Zڼ&*"1{'3VR͞fYǪ6:Ѐ$^|QDݦYOSB8P=ET"jF7k<,VHe<GVkpMSh3X.'d8݃1aE30m,)p ?lxm#o>QыBfDuc_'#\h+\΃$PlXG0tCT9tRl Hfef͎k_g\'*)43!so#$'V4~׶Uy&Ǫ9Wbqr1N.wW- P̶ %\.7 "u`ãOU1')6Q{)UfitN=x~%SыFvy%'+dqJQE$x&*{tJ;38fd%&0Ԋ#5Τ i]-ƞ0To#J>*ljnuRӌ#.IϜ6ޕyq^P۵oxK`nX"^\N-B.B^z[0uSuj앸 Z2E.CQ/F0j5aVgt gB!4 _nLqp>7>G՗P`T dיBn͍}˱* ╬\7`N\K1kq̐^bAhKq.ޚ?hBOb[ezYKb7RS$;GJڈQĺdN8򆴸H\*+ D>2#崁;ry<{=c;niZkWki,͋䴬|X$!P9v=N cغmHtl=3 ~o3/_dtYtݍ %!#U\o|Ɠn["6"+ILxY/f*\k窭D(c|O~=MP_3CE5(_OmXED{T>)@5 p (@RqݘE!쌁n#`Su'#IInryyjɟ)5pxg*]_tX /~WJ)R374)cKm1VIlXF)as\s}ڥ̞A;u4hvQgJpl5O g:i4AYTXy(Nk-[|> `}ƴqRuܠ-ێp:t~EӶ,]f=TEir8 |m^g$FCؑJ}*7rP*ynjO:)stmkJ</?7)a&lb>0DǴJtTRczku^6 l9G%EqmEa ?) 6Da8~%Dr%<=ȘԻ?>go_%% !?A "hgqwFg\qg3Nm#Ȧ?C))|[EHӬ4 [Au*j#Iת.=whv6Ʈ22 BS|I1ēTTw!8y~EIOOϹ"a BVҤqK]dQl?l^S4s8h1hhsrgD&5°pH'@9ChoK۷NZ\*k =lSÓ -6)^#9M`܎ Y`=$y/'ЗE5:Z$SV"|$_(ƭwfů,F~aqf v_CEE̠$&A^oo݈{}FA4ՂHWFE|T?/ ?"0H7:%XazHSo5ƳiI~ŢXx 6Hu%տ vuhxaaKONi幯ַb}&L 2-$X} פ3wg֩RoP,O`{z$LtY\FjbF"[7tOa-26iAh= u]"x-w)6L[S'z1> nx2;&[sdguy -2BJFM恺xۮ 9OV4}Z>\I;Y) n1Si=Al q-Bh)Ru8UqM;e/ a v%bŻc!)Dx SbN3kx࣌nmO cex6^@귐Y^ v#qgh \XoKAnP$~86IM_H\tP h8ڔE|Jl 54a MXINk+`pWkF)}4c5^uԑkʓ2us}f&vd e?YrWz~p쑨j'{Uq[?ĠnB r"_IYZ{B „t TK̅_ETV!&l3U븑b U-fNl WBƎ&C$.{tPe\|"/n%(7fֳ"dC{^>?{Č -BvrsK^MxVOjW?V\#Uݩf,T?2M5!}4Fss~pk?_gY)+Ue㑦[zrfÌ&Eʛ;#;D.c-s|#*mEF!3?"JSvKymD ~S~ r`/qJHl fqߠ{R ,飪#N9  m@l3-Md*WnQã|{`TJJtT9R#ڂf(}܅_iPmJJ)v[_:J8ɏXDn#F[FdaAme~'3]f32lf ,<, /f[Vwn X;91GUI?r *aէa 5JbZ̀5rL٭;[VS ߉Up ˜kFHc'x?C}qz)ʶ aUVBˣ.nS!#ҔZ!Mxo5è@8_'Ў 5KZ.k:7^媼w>V>:=6wܕSLus 82R,Զ;B&HttCagYZPK!wuO ledtrig-usbport.ko.xznu[7zXZִF!t/( R]?Eh=ڜ.+К܄` .qdu";эR2o&Y^U#Լ;xX'lhD, VvQJg\w0EpyaH+.z{&$i_gh/ ͢3z.xPY)HG|Wng`l_Qw^~Kq%$`%w* &- RG;{07Y|o.)qdn R {bj?0$wG$Ȭ"|ջU|HQ`.ckzZ< ˫¹O\&|E˶*9gU@(k)dU1]Gѱp< p#ϬfAN!K*ݡL ;#\M O L*qA,*\g*11gGQ7y!t>pq {G~\sۏ b< s5HD,ڻ6M(U!OY7!r@|ҕC}$BGV䉪 hRiFZ+O,KpbƷY}hOHҘ4tLJ29V*q傋WN Aptb sҔlЌ-e9vgV+zȳKbb5lDd8 !bٯ{T߰)B15[ay\֖yoVB]i~GWoL|D;4=:_54 ΣolCXY=C6v*8$QBWK쎆H,EaĎ㻹S mA=yHJbq{> _`Sz2{$q;X3 7.g-xC# î=#um U+g 3\pfOsJ `O}#ŁNU0tIS(AΡ]gs|*lv99^‹F[~8l%˫5lsШ&-H!~ZCBzVlݯ+S hOfī Qɣ;DFFUhw*`*~|+=@lc? sT ~RyfA!@㵮fȣz#ƿˌNܛ>;ۜhR3)QyD^/A}}=3["Lh~C;h̘dOְЊ 8xw4t^'ƪL. (z.76j':OJ}*m޹Bx/5=gjº^z0݂[UੂyĴe& h4*Qg6NzPTۀ^,8*D?e: dP; hN4wv?'Q4hT[%}0nc04bIr NhMHWYf &elk?}K=z;Fpg'p|߿YNвߘ/G72#}$]IC/JhcEݴxrϮЎNxI?YbY!d [#S-)`nz⏈q)^QA,浬t;ZBM6N]`JbG)s/m'pNpj*;0a~Hҭ!cP>`-j3]iyBpУ"fNLε^f݁a+~u w WLO+ʺ2 ̐rEEq0J9?GKf w-sk\+F,]?tu>ׅ~{}c` >ф wނ#0[QgF-#fDyhx{T S } gOQ]d\lU(Ƈ"q6eYgЁn)vƮ#xqo̸lL;}}̜hkŅx`@׀ Y# wS{Ԝ2ѧr/l3^E^%͖w[If4dW/>K`-> / 9ʃh+qʰыvG`ov4hf_xȷx]<#txl?)x)DGܨ*~Voec]]K7)py^2"A':oFS+;^= ]4 q5mW3րJӜlZģ0¿W_GXKݗ'`ʭN/̅!R>iBWA#8ԂJhh4]]P ($޾A)vʧ Yiߝj,'3KJT ( TCK wW$Dz%mmnΪfӌ(Z5aZlߤ\/##ZivwrWg\A2w*g\дµ%t5o "p q2NLy?]ܞoƂUЕ(XŻbn-[w_c/}#pF 3NnbD _9g\zL/Pm֟&*HYV=^"u18s6 i{% dڢd)r a3fDYSNY@ U]68H/ٯ M9Yz`Bdi jfĈZUQHb^Vu?67ʩ8y(.^}(ٱ8q(VKCp[=Q@ñgYZPK!^ܪ>y>y logger.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2005-2007,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 . # __all__ = [ "LogTarget", "FileLog", "Logger", "log" ] import sys import types import time import inspect import fnmatch import syslog import traceback import fcntl import os.path import os # --------------------------------------------------------------------------- # abstract class for logging targets class LogTarget(object): """ Abstract class for logging targets. """ def __init__(self): self.fd = None def write(self, data, level, logger, is_debug=0): raise NotImplementedError("LogTarget.write is an abstract method") def flush(self): raise NotImplementedError("LogTarget.flush is an abstract method") def close(self): raise NotImplementedError("LogTarget.close is an abstract method") # --------------------------------------------------------------------------- # private class for stdout class _StdoutLog(LogTarget): def __init__(self): LogTarget.__init__(self) self.fd = sys.stdout def write(self, data, level, logger, is_debug=0): # ignore level self.fd.write(data) self.flush() def close(self): self.flush() def flush(self): self.fd.flush() # --------------------------------------------------------------------------- # private class for stderr class _StderrLog(_StdoutLog): def __init__(self): _StdoutLog.__init__(self) self.fd = sys.stderr # --------------------------------------------------------------------------- # private class for syslog class _SyslogLog(LogTarget): def __init__(self): # Only initialize LogTarget here as fs should be None LogTarget.__init__(self) # # Derived from: https://github.com/canvon/firewalld/commit/af0edfee1cc1891b7b13f302ca5911b24e9b0f13 # # Work around Python issue 27875, "Syslogs /usr/sbin/foo as /foo # instead of as foo" # (but using openlog explicitly might be better anyway) # # Set ident to basename, log PID as well, and log to facility "daemon". syslog.openlog(os.path.basename(sys.argv[0]), syslog.LOG_PID, syslog.LOG_DAEMON) def write(self, data, level, logger, is_debug=0): priority = None if is_debug: priority = syslog.LOG_DEBUG else: if level >= logger.INFO1: priority = syslog.LOG_INFO elif level == logger.WARNING: priority = syslog.LOG_WARNING elif level == logger.ERROR: priority = syslog.LOG_ERR elif level == logger.FATAL: priority = syslog.LOG_CRIT if data.endswith("\n"): data = data[:len(data)-1] if len(data) > 0: if priority is None: syslog.syslog(data) else: syslog.syslog(priority, data) def close(self): syslog.closelog() def flush(self): pass # --------------------------------------------------------------------------- class FileLog(LogTarget): """ FileLog class. File will be opened on the first write. """ def __init__(self, filename, mode="w"): LogTarget.__init__(self) self.filename = filename self.mode = mode def open(self): if self.fd: return flags = os.O_CREAT | os.O_WRONLY if self.mode.startswith('a'): flags |= os.O_APPEND self.fd = os.open(self.filename, flags, 0o640) # Make sure that existing file has correct perms os.fchmod(self.fd, 0o640) # Make it an object self.fd = os.fdopen(self.fd, self.mode) fcntl.fcntl(self.fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) def write(self, data, level, logger, is_debug=0): if not self.fd: self.open() self.fd.write(data) self.fd.flush() def close(self): if not self.fd: return self.fd.close() self.fd = None def flush(self): if not self.fd: return self.fd.flush() # --------------------------------------------------------------------------- class Logger(object): r""" Format string: %(class)s Calling class the function belongs to, else empty %(date)s Date using Logger.date_format, see time module %(domain)s Full Domain: %(module)s.%(class)s.%(function)s %(file)s Filename of the module %(function)s Function name, empty in __main__ %(label)s Label according to log function call from Logger.label %(level)d Internal logging level %(line)d Line number in module %(module)s Module name %(message)s Log message Standard levels: FATAL Fatal error messages ERROR Error messages WARNING Warning messages INFOx, x in [1..5] Information DEBUGy, y in [1..10] Debug messages NO_INFO No info output NO_DEBUG No debug output INFO_MAX Maximum info level DEBUG_MAX Maximum debug level x and y depend on info_max and debug_max from Logger class initialization. See __init__ function. Default logging targets: stdout Logs to stdout stderr Logs to stderr syslog Logs to syslog Additional arguments for logging functions (fatal, error, warning, info and debug): nl Disable newline at the end with nl=0, default is nl=1. fmt Format string for this logging entry, overloads global format string. Example: fmt="%(file)s:%(line)d %(message)s" nofmt Only output message with nofmt=1. The nofmt argument wins over the fmt argument. Example: from logger import log log.setInfoLogLevel(log.INFO1) log.setDebugLogLevel(log.DEBUG1) for i in range(1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: " "%(level)d %(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.addDebugLogging("*", fl) log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug3("debug3") log.debug2("debug2") log.debug1("debug1") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error\n", nl=0) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) """ ALL = -5 NOTHING = -4 FATAL = -3 TRACEBACK = -2 ERROR = -1 WARNING = 0 # Additional levels are generated in class initilization stdout = _StdoutLog() stderr = _StderrLog() syslog = _SyslogLog() def __init__(self, info_max=5, debug_max=10): """ Logger class initialization """ self._level = { } self._debug_level = { } self._format = "" self._date_format = "" self._label = { } self._debug_label = { } self._logging = { } self._debug_logging = { } self._domains = { } self._debug_domains = { } # INFO1 is required for standard log level if info_max < 1: raise ValueError("Logger: info_max %d is too low" % info_max) if debug_max < 0: raise ValueError("Logger: debug_max %d is too low" % debug_max) self.NO_INFO = self.WARNING # = 0 self.INFO_MAX = info_max self.NO_DEBUG = 0 self.DEBUG_MAX = debug_max self.setInfoLogLabel(self.FATAL, "FATAL ERROR: ") self.setInfoLogLabel(self.TRACEBACK, "") self.setInfoLogLabel(self.ERROR, "ERROR: ") self.setInfoLogLabel(self.WARNING, "WARNING: ") # generate info levels and infox functions for _level in range(1, self.INFO_MAX+1): setattr(self, "INFO%d" % _level, _level) self.setInfoLogLabel(_level, "") setattr(self, "info%d" % (_level), (lambda self, x: lambda message, *args, **kwargs: self.info(x, message, *args, **kwargs))(self, _level)) # pylint: disable=E0602 # generate debug levels and debugx functions for _level in range(1, self.DEBUG_MAX+1): setattr(self, "DEBUG%d" % _level, _level) self.setDebugLogLabel(_level, "DEBUG%d: " % _level) setattr(self, "debug%d" % (_level), (lambda self, x: lambda message, *args, **kwargs: self.debug(x, message, *args, **kwargs))(self, _level)) # pylint: disable=E0602 # set initial log levels, formats and targets self.setInfoLogLevel(self.INFO1) self.setDebugLogLevel(self.NO_DEBUG) self.setFormat("%(label)s%(message)s") self.setDateFormat("%d %b %Y %H:%M:%S") self.setInfoLogging("*", self.stderr, [ self.FATAL, self.ERROR, self.WARNING ]) self.setInfoLogging("*", self.stdout, [ i for i in range(self.INFO1, self.INFO_MAX+1) ]) self.setDebugLogging("*", self.stdout, [ i for i in range(1, self.DEBUG_MAX+1) ]) def close(self): """ Close all logging targets """ for level in range(self.FATAL, self.DEBUG_MAX+1): if level not in self._logging: continue for (dummy, target, dummy) in self._logging[level]: target.close() def getInfoLogLevel(self, domain="*"): """ Get info log level. """ self._checkDomain(domain) if domain in self._level: return self._level[domain] return self.NOTHING def setInfoLogLevel(self, level, domain="*"): """ Set log level [NOTHING .. INFO_MAX] """ self._checkDomain(domain) if level < self.NOTHING: level = self.NOTHING if level > self.INFO_MAX: level = self.INFO_MAX self._level[domain] = level def getDebugLogLevel(self, domain="*"): """ Get debug log level. """ self._checkDomain(domain) if domain in self._debug_level: return self._debug_level[domain] + self.NO_DEBUG return self.NO_DEBUG def setDebugLogLevel(self, level, domain="*"): """ Set debug log level [NO_DEBUG .. DEBUG_MAX] """ self._checkDomain(domain) if level < 0: level = 0 if level > self.DEBUG_MAX: level = self.DEBUG_MAX self._debug_level[domain] = level - self.NO_DEBUG def getFormat(self): return self._format def setFormat(self, _format): self._format = _format def getDateFormat(self): return self._date_format def setDateFormat(self, _format): self._date_format = _format def setInfoLogLabel(self, level, label): """ Set log label for level. Level can be a single level or an array of levels. """ levels = self._getLevels(level) for level in levels: self._checkLogLevel(level, min_level=self.FATAL, max_level=self.INFO_MAX) self._label[level] = label def setDebugLogLabel(self, level, label): """ Set log label for level. Level can be a single level or an array of levels. """ levels = self._getLevels(level, is_debug=1) for level in levels: self._checkLogLevel(level, min_level=self.INFO1, max_level=self.DEBUG_MAX) self._debug_label[level] = label def setInfoLogging(self, domain, target, level=ALL, fmt=None): """ Set info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._setLogging(domain, target, level, fmt, is_debug=0) def setDebugLogging(self, domain, target, level=ALL, fmt=None): """ Set debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._setLogging(domain, target, level, fmt, is_debug=1) def addInfoLogging(self, domain, target, level=ALL, fmt=None): """ Add info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._addLogging(domain, target, level, fmt, is_debug=0) def addDebugLogging(self, domain, target, level=ALL, fmt=None): """ Add debg log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._addLogging(domain, target, level, fmt, is_debug=1) def delInfoLogging(self, domain, target, level=ALL, fmt=None): """ Delete info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._delLogging(domain, target, level, fmt, is_debug=0) def delDebugLogging(self, domain, target, level=ALL, fmt=None): """ Delete debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._delLogging(domain, target, level, fmt, is_debug=1) def isInfoLoggingHere(self, level): """ Is there currently any info logging for this log level (and domain)? """ return self._isLoggingHere(level, is_debug=0) def isDebugLoggingHere(self, level): """ Is there currently any debug logging for this log level (and domain)? """ return self._isLoggingHere(level, is_debug=1) ### log functions def fatal(self, _format, *args, **kwargs): """ Fatal error log. """ self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(self.FATAL, _format, *args, **kwargs) def error(self, _format, *args, **kwargs): """ Error log. """ self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(self.ERROR, _format, *args, **kwargs) def warning(self, _format, *args, **kwargs): """ Warning log. """ self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(self.WARNING, _format, *args, **kwargs) def info(self, level, _format, *args, **kwargs): """ Information log using info level [1..info_max]. There are additional infox functions according to info_max from __init__""" self._checkLogLevel(level, min_level=1, max_level=self.INFO_MAX) self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(level+self.NO_INFO, _format, *args, **kwargs) def debug(self, level, _format, *args, **kwargs): """ Debug log using debug level [1..debug_max]. There are additional debugx functions according to debug_max from __init__""" self._checkLogLevel(level, min_level=1, max_level=self.DEBUG_MAX) self._checkKWargs(kwargs) kwargs["is_debug"] = 1 self._log(level, _format, *args, **kwargs) def exception(self): self._log(self.TRACEBACK, traceback.format_exc(), args=[], kwargs={}) ### internal functions def _checkLogLevel(self, level, min_level, max_level): if level < min_level or level > max_level: raise ValueError("Level %d out of range, should be [%d..%d]." % \ (level, min_level, max_level)) def _checkKWargs(self, kwargs): if not kwargs: return for key in kwargs.keys(): if key not in [ "nl", "fmt", "nofmt" ]: raise ValueError("Key '%s' is not allowed as argument for logging." % key) def _checkDomain(self, domain): if not domain or domain == "": raise ValueError("Domain '%s' is not valid." % domain) def _getLevels(self, level, is_debug=0): """ Generate log level array. """ if level != self.ALL: if isinstance(level, list) or isinstance(level, tuple): levels = level else: levels = [ level ] for level in levels: if is_debug: self._checkLogLevel(level, min_level=1, max_level=self.DEBUG_MAX) else: self._checkLogLevel(level, min_level=self.FATAL, max_level=self.INFO_MAX) else: if is_debug: levels = [ i for i in range(self.DEBUG1, self.DEBUG_MAX) ] else: levels = [ i for i in range(self.FATAL, self.INFO_MAX) ] return levels def _getTargets(self, target): """ Generate target array. """ if isinstance(target, list) or isinstance(target, tuple): targets = target else: targets = [ target ] for _target in targets: if not issubclass(_target.__class__, LogTarget): raise ValueError("'%s' is no valid logging target." % \ _target.__class__.__name__) return targets def _genDomains(self, is_debug=0): # private method for self._domains array creation, speeds up """ Generate dict with domain by level. """ if is_debug: _domains = self._debug_domains _logging = self._debug_logging _range = ( 1, self.DEBUG_MAX+1 ) else: _domains = self._domains _logging = self._logging _range = ( self.FATAL, self.INFO_MAX+1 ) if len(_domains) > 0: _domains.clear() for level in range(_range[0], _range[1]): if level not in _logging: continue for (domain, dummy, dummy) in _logging[level]: if domain not in _domains: _domains.setdefault(level, [ ]).append(domain) def _setLogging(self, domain, target, level=ALL, fmt=None, is_debug=0): self._checkDomain(domain) levels = self._getLevels(level, is_debug) targets = self._getTargets(target) if is_debug: _logging = self._debug_logging else: _logging = self._logging for level in levels: for target in targets: _logging[level] = [ (domain, target, fmt) ] self._genDomains(is_debug) def _addLogging(self, domain, target, level=ALL, fmt=None, is_debug=0): self._checkDomain(domain) levels = self._getLevels(level, is_debug) targets = self._getTargets(target) if is_debug: _logging = self._debug_logging else: _logging = self._logging for level in levels: for target in targets: _logging.setdefault(level, [ ]).append((domain, target, fmt)) self._genDomains(is_debug) def _delLogging(self, domain, target, level=ALL, fmt=None, is_debug=0): self._checkDomain(domain) levels = self._getLevels(level, is_debug) targets = self._getTargets(target) if is_debug: _logging = self._debug_logging else: _logging = self._logging for _level in levels: for target in targets: if _level not in _logging: continue if (domain, target, fmt) in _logging[_level]: _logging[_level].remove( (domain, target, fmt) ) if len(_logging[_level]) == 0: del _logging[_level] continue if level != self.ALL: raise ValueError("No mathing logging for " \ "level %d, domain %s, target %s and format %s." % \ (_level, domain, target.__class__.__name__, fmt)) self._genDomains(is_debug) def _isLoggingHere(self, level, is_debug=0): _dict = self._genDict(level, is_debug) if not _dict: return False point_domain = _dict["domain"] + "." if is_debug: _logging = self._debug_logging else: _logging = self._logging # do we need to log? for (domain, dummy, dummy) in _logging[level]: if domain == "*" or \ point_domain.startswith(domain) or \ fnmatch.fnmatchcase(_dict["domain"], domain): return True return False def _getClass(self, frame): """ Function to get calling class. Returns class or None. """ # get class by first function argument, if there are any if frame.f_code.co_argcount > 0: selfname = frame.f_code.co_varnames[0] if selfname in frame.f_locals: _self = frame.f_locals[selfname] obj = self._getClass2(_self.__class__, frame.f_code) if obj: return obj module = inspect.getmodule(frame.f_code) code = frame.f_code # function in module? if code.co_name in module.__dict__: if hasattr(module.__dict__[code.co_name], "func_code") and \ module.__dict__[code.co_name].__code__ == code: return None # class in module for (dummy, obj) in module.__dict__.items(): if isinstance(obj, types.ClassType): if hasattr(obj, code.co_name): value = getattr(obj, code.co_name) if isinstance(value, types.FunctionType): if value.__code__ == code: return obj # nothing found return None def _getClass2(self, obj, code): """ Internal function to get calling class. Returns class or None. """ for value in obj.__dict__.values(): if isinstance(value, types.FunctionType): if value.__code__ == code: return obj for base in obj.__bases__: _obj = self._getClass2(base, code) if _obj: return _obj return None # internal log class def _log(self, level, _format, *args, **kwargs): is_debug = 0 if "is_debug" in kwargs: is_debug = kwargs["is_debug"] nl = 1 if "nl" in kwargs: nl = kwargs["nl"] nofmt = 0 if "nofmt" in kwargs: nofmt = kwargs["nofmt"] _dict = self._genDict(level, is_debug) if not _dict: return if len(args) > 1: _dict['message'] = _format % args elif len(args) == 1: # needed for _format % _dict _dict['message'] = _format % args[0] else: _dict['message'] = _format point_domain = _dict["domain"] + "." if is_debug: _logging = self._debug_logging else: _logging = self._logging used_targets = [ ] # log to target(s) for (domain, target, _format) in _logging[level]: if target in used_targets: continue if domain == "*" \ or point_domain.startswith(domain+".") \ or fnmatch.fnmatchcase(_dict["domain"], domain): if not _format: _format = self._format if "fmt" in kwargs: _format = kwargs["fmt"] if nofmt: target.write(_dict["message"], level, self, is_debug) else: target.write(_format % _dict, level, self, is_debug) if nl: # newline target.write("\n", level, self, is_debug) used_targets.append(target) # internal function to generate the dict, needed for logging def _genDict(self, level, is_debug=0): """ Internal function. """ check_domains = [ ] simple_match = False if is_debug: _dict = self._debug_level _domains = self._debug_domains _label = self._debug_label else: _dict = self._level _domains = self._domains _label = self._label # no debug for domain in _dict: if domain == "*": # '*' matches everything: simple match if _dict[domain] >= level: simple_match = True if len(check_domains) > 0: check_domains = [ ] break else: if _dict[domain] >= level: check_domains.append(domain) if not simple_match and len(check_domains) < 1: return None if level not in _domains: return None f = inspect.currentframe() # go outside of logger module as long as there is a lower frame while f and f.f_back and f.f_globals["__name__"] == self.__module__: f = f.f_back if not f: raise ValueError("Frame information not available.") # get module name module_name = f.f_globals["__name__"] # simple module match test for all entries of check_domain point_module = module_name + "." for domain in check_domains: if point_module.startswith(domain): # found domain in module name check_domains = [ ] break # get code co = f.f_code # optimization: bail out early if domain can not match at all _len = len(module_name) for domain in _domains[level]: i = domain.find("*") if i == 0: continue elif i > 0: d = domain[:i] else: d = domain if _len >= len(d): if not module_name.startswith(d): return None else: if not d.startswith(module_name): return None # generate _dict for format output level_str = "" if level in _label: level_str = _label[level] _dict = { 'file': co.co_filename, 'line': f.f_lineno, 'module': module_name, 'class': '', 'function': co.co_name, 'domain': '', 'label' : level_str, 'level' : level, 'date' : time.strftime(self._date_format, time.localtime()) } if _dict["function"] == "?": _dict["function"] = "" # domain match needed? domain_needed = False for domain in _domains[level]: # standard domain, matches everything if domain == "*": continue # domain is needed domain_needed = True break # do we need to get the class object? if self._format.find("%(domain)") >= 0 or \ self._format.find("%(class)") >= 0 or \ domain_needed or \ len(check_domains) > 0: obj = self._getClass(f) if obj: _dict["class"] = obj.__name__ # build domain string _dict["domain"] = "" + _dict["module"] if _dict["class"] != "": _dict["domain"] += "." + _dict["class"] if _dict["function"] != "": _dict["domain"] += "." + _dict["function"] if len(check_domains) < 1: return _dict point_domain = _dict["domain"] + "." for domain in check_domains: if point_domain.startswith(domain) or \ fnmatch.fnmatchcase(_dict["domain"], domain): return _dict return None # --------------------------------------------------------------------------- # Global logging object. log = Logger() # --------------------------------------------------------------------------- """ # Example if __name__ == '__main__': log.setInfoLogLevel(log.INFO2) log.setDebugLogLevel(log.DEBUG5) for i in range(log.INFO1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) for i in range(log.DEBUG1, log.DEBUG_MAX+1): log.setDebugLogLabel(i, "DEBUG%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d %(label)s" "%(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.delDebugLogging("*", log.stdout) log.setDebugLogging("*", log.stdout, [ log.DEBUG1, log.DEBUG2 ] ) log.addDebugLogging("*", fl) # log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") # log.addDebugLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug10("debug10") log.debug9("debug9") log.debug8("debug8") log.debug7("debug7") log.debug6("debug6") log.debug5("debug5") log.debug4("debug4") log.debug3("debug3") log.debug2("debug2", fmt="%(file)s:%(line)d %(message)s") log.debug1("debug1", nofmt=1) log.info5("info5") log.info4("info4") log.info3("info3") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error ", nl=0) log.error("error", nofmt=1) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) log.info(log.INFO2, "info2 fmt", fmt="%(file)s:%(line)d %(message)s") try: a = b except Exception as e: log.exception() """ # vim:ts=4:sw=4:showmatch:expandtab PK!͙22 nftables.pynu[# -*- 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.path import copy from firewall.core.base import SHORTCUTS, DEFAULT_ZONE_TARGET from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import splitArgs, check_mac, portStr, \ check_single_address, check_address from firewall import config from firewall.errors import FirewallError, UNKNOWN_ERROR, INVALID_RULE, \ INVALID_ICMPTYPE, INVALID_TYPE, INVALID_ENTRY from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark TABLE_NAME = "firewalld" # Map iptables (table, chain) to hooks and priorities. # These are well defined by NF_IP_PRI_* defines in netfilter. # # This is analogous to ipXtables.BUILT_IN_CHAINS, but we omit the chains that # are only used for direct rules. # # Note: All hooks use their standard position + NFT_HOOK_OFFSET. This means # iptables will have DROP precedence. It also means that even if iptables # ACCEPTs a packet it may still be dropped later by firewalld's rules. # NFT_HOOK_OFFSET = 10 IPTABLES_TO_NFT_HOOK = { #"security": { # "INPUT": ("input", 50 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", 50 + NFT_HOOK_OFFSET), # "FORWARD": ("forward", 50 + NFT_HOOK_OFFSET), #}, "raw": { "PREROUTING": ("prerouting", -300 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", -300 + NFT_HOOK_OFFSET), }, "mangle": { "PREROUTING": ("prerouting", -150 + NFT_HOOK_OFFSET), # "POSTROUTING": ("postrouting", -150 + NFT_HOOK_OFFSET), # "INPUT": ("input", -150 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", -150 + NFT_HOOK_OFFSET), # "FORWARD": ("forward", -150 + NFT_HOOK_OFFSET), }, "nat": { "PREROUTING": ("prerouting", -100 + NFT_HOOK_OFFSET), "POSTROUTING": ("postrouting", 100 + NFT_HOOK_OFFSET), # "INPUT": ("input", 100 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", -100 + NFT_HOOK_OFFSET), }, "filter": { "INPUT": ("input", 0 + NFT_HOOK_OFFSET), "FORWARD": ("forward", 0 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", 0 + NFT_HOOK_OFFSET), }, } OUR_CHAINS = { # chains created by firewalld # family: { chains ...} "inet": {}, "ip": {}, "ip6": {}, } # Most ICMP types are provided by nft, but for the codes we have to use numeric # values. # ICMP_TYPES_FRAGMENT = { "ipv4" : { "communication-prohibited" : ["icmp", "type", "destination-unreachable", "icmp", "code", "13"], "destination-unreachable" : ["icmp", "type", "destination-unreachable"], "echo-reply" : ["icmp", "type", "echo-reply"], "echo-request" : ["icmp", "type", "echo-request"], "fragmentation-needed" : ["icmp", "type", "destination-unreachable", "icmp", "code", "4"], "host-precedence-violation" : ["icmp", "type", "destination-unreachable", "icmp", "code", "14"], "host-prohibited" : ["icmp", "type", "destination-unreachable", "icmp", "code", "10"], "host-redirect" : ["icmp", "type", "redirect", "icmp", "code", "1"], "host-unknown" : ["icmp", "type", "destination-unreachable", "icmp", "code", "7"], "host-unreachable" : ["icmp", "type", "destination-unreachable", "icmp", "code", "1"], "ip-header-bad" : ["icmp", "type", "parameter-problem", "icmp", "code", "1"], "network-prohibited" : ["icmp", "type", "destination-unreachable", "icmp", "code", "8"], "network-redirect" : ["icmp", "type", "redirect", "icmp", "code", "0"], "network-unknown" : ["icmp", "type", "destination-unreachable", "icmp", "code", "6"], "network-unreachable" : ["icmp", "type", "destination-unreachable", "icmp", "code", "0"], "parameter-problem" : ["icmp", "type", "parameter-problem"], "port-unreachable" : ["icmp", "type", "destination-unreachable", "icmp", "code", "3"], "precedence-cutoff" : ["icmp", "type", "destination-unreachable", "icmp", "code", "15"], "protocol-unreachable" : ["icmp", "type", "destination-unreachable", "icmp", "code", "2"], "redirect" : ["icmp", "type", "redirect"], "required-option-missing" : ["icmp", "type", "parameter-problem", "icmp", "code", "1"], "router-advertisement" : ["icmp", "type", "router-advertisement"], "router-solicitation" : ["icmp", "type", "router-solicitation"], "source-quench" : ["icmp", "type", "source-quench"], "source-route-failed" : ["icmp", "type", "destination-unreachable", "icmp", "code", "5"], "time-exceeded" : ["icmp", "type", "time-exceeded"], "timestamp-reply" : ["icmp", "type", "timestamp-reply"], "timestamp-request" : ["icmp", "type", "timestamp-request"], "tos-host-redirect" : ["icmp", "type", "redirect", "icmp", "code", "3"], "tos-host-unreachable" : ["icmp", "type", "destination-unreachable", "icmp", "code", "12"], "tos-network-redirect" : ["icmp", "type", "redirect", "icmp", "code", "2"], "tos-network-unreachable" : ["icmp", "type", "destination-unreachable", "icmp", "code", "11"], "ttl-zero-during-reassembly" : ["icmp", "type", "time-exceeded", "icmp", "code", "1"], "ttl-zero-during-transit" : ["icmp", "type", "time-exceeded", "icmp", "code", "0"], }, "ipv6" : { "address-unreachable" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "3"], "bad-header" : ["icmpv6", "type", "parameter-problem", "icmpv6", "code", "0"], "beyond-scope" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "2"], "communication-prohibited" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "1"], "destination-unreachable" : ["icmpv6", "type", "destination-unreachable"], "echo-reply" : ["icmpv6", "type", "echo-reply"], "echo-request" : ["icmpv6", "type", "echo-request"], "failed-policy" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "5"], "neighbour-advertisement" : ["icmpv6", "type", "nd-neighbor-advert"], "neighbour-solicitation" : ["icmpv6", "type", "nd-neighbor-solicit"], "no-route" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "0"], "packet-too-big" : ["icmpv6", "type", "packet-too-big"], "parameter-problem" : ["icmpv6", "type", "parameter-problem"], "port-unreachable" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "4"], "redirect" : ["icmpv6", "type", "nd-redirect"], "reject-route" : ["icmpv6", "type", "destination-unreachable", "icmpv6", "code", "6"], "router-advertisement" : ["icmpv6", "type", "nd-router-advert"], "router-solicitation" : ["icmpv6", "type", "nd-router-solicit"], "time-exceeded" : ["icmpv6", "type", "time-exceeded"], "ttl-zero-during-reassembly" : ["icmpv6", "type", "time-exceeded", "icmpv6", "code", "1"], "ttl-zero-during-transit" : ["icmpv6", "type", "time-exceeded", "icmpv6", "code", "0"], "unknown-header-type" : ["icmpv6", "type", "parameter-problem", "icmpv6", "code", "1"], "unknown-option" : ["icmpv6", "type", "parameter-problem", "icmpv6", "code", "2"], } } class nftables(object): name = "nftables" zones_supported = True def __init__(self, fw): self._fw = fw self._command = config.COMMANDS["nft"] self.fill_exists() self.available_tables = [] self.rule_to_handle = {} self.rule_ref_count = {} self.zone_source_index_cache = {} def fill_exists(self): self.command_exists = os.path.exists(self._command) self.restore_command_exists = False def _run_replace_zone_source(self, rule_add, rule, zone_source_index_cache): try: i = rule.index("%%ZONE_SOURCE%%") rule.pop(i) zone = rule.pop(i) zone_source = (zone, rule[7]) # (zone, address) except ValueError: try: i = rule.index("%%ZONE_INTERFACE%%") rule.pop(i) zone_source = None except ValueError: return family = rule[2] if zone_source and not rule_add: if family in zone_source_index_cache and \ zone_source in zone_source_index_cache[family]: zone_source_index_cache[family].remove(zone_source) elif rule_add: if family not in zone_source_index_cache: zone_source_index_cache[family] = [] if zone_source: # order source based dispatch by zone name if zone_source not in zone_source_index_cache[family]: zone_source_index_cache[family].append(zone_source) zone_source_index_cache[family].sort(key=lambda x: x[0]) index = zone_source_index_cache[family].index(zone_source) else: if self._fw._allow_zone_drifting: index = 0 else: index = len(zone_source_index_cache[family]) if index == 0: rule[0] = "insert" else: index -= 1 # point to the rule before insertion point rule[0] = "add" rule.insert(i, "index") rule.insert(i+1, "%d" % index) def __run(self, args): nft_opts = ["--echo", "--handle"] _args = args[:] # If we're deleting a table (i.e. build_flush_rules()) # then check if its exist first to avoid nft throwing an error if _args[0] == "delete" and _args[1] == "table": _args_test = _args[:] _args_test[0] = "list" (status, output) = runProg(self._command, nft_opts + _args_test) if status != 0: return "" rule_key = None if _args[0] in ["add", "insert"] and _args[1] == "rule": rule_add = True rule_key = _args[2:] if rule_key[3] == "position": # strip "position #" # "insert rule family table chain position " # ^^ rule_key starts here try: int(rule_key[4]) except Exception: raise FirewallError(INVALID_RULE, "position without a number") else: rule_key.pop(3) rule_key.pop(3) rule_key = " ".join(rule_key) elif _args[0] in ["delete"] and _args[1] == "rule": rule_add = False rule_key = _args[2:] rule_key = " ".join(rule_key) # rule deduplication if rule_key in self.rule_ref_count: if rule_add: self.rule_ref_count[rule_key] += 1 return "" if not rule_add and self.rule_ref_count[rule_key] > 1: self.rule_ref_count[rule_key] -= 1 return "" elif self.rule_ref_count[rule_key] == 1: self.rule_ref_count[rule_key] -= 1 else: raise FirewallError(UNKNOWN_ERROR, "rule ref count bug: rule_key '%s', cnt %d" % (rule_key, self.rule_ref_count[rule_key])) log.debug2("%s: rule ref cnt %d, %s %s", self.__class__, self.rule_ref_count[rule_key], self._command, " ".join(_args)) if rule_key: zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache) self._run_replace_zone_source(rule_add, _args, zone_source_index_cache) if not rule_key or (not rule_add and self.rule_ref_count[rule_key] == 0) \ or ( rule_add and rule_key not in self.rule_ref_count): # delete using rule handle if rule_key and not rule_add: _args = ["delete", "rule"] + _args[2:5] + \ ["handle", self.rule_to_handle[rule_key]] _args_str = " ".join(_args) log.debug2("%s: %s %s", self.__class__, self._command, _args_str) (status, output) = runProg(self._command, nft_opts + _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, _args_str, output)) if rule_key: self.zone_source_index_cache = zone_source_index_cache # nft requires deleting rules by handle. So we must cache the rule # handle when adding/inserting rules. # if rule_key: if rule_add: str = "# handle " offset = output.index(str) + len(str) self.rule_to_handle[rule_key] = output[offset:].strip() self.rule_ref_count[rule_key] = 1 else: del self.rule_to_handle[rule_key] del self.rule_ref_count[rule_key] return output def _rule_replace(self, rule, pattern, replacement): try: i = rule.index(pattern) except ValueError: return False else: rule[i:i+1] = replacement return True def reverse_rule(self, args): ret_args = args[:] ret_args[0] = "delete" return ret_args def set_rules(self, rules, log_denied): # We can't support using "nft -f" because we need to retrieve the # handles for each rules so we can delete them later on. # See also: self.restore_command_exists # # We can implement this once libnftables in ready. # raise FirewallError(UNKNOWN_ERROR, "not implemented") def set_rule(self, rule, log_denied): # replace %%REJECT%% # # HACK: work around nft bug in which icmpx does not work if the rule # has qualified the ip family. icmp_keyword = "icmpx" if "ipv4" in rule or "ip" in rule or "icmp" in rule: icmp_keyword = "icmp" elif "ipv6" in rule or "ip6" in rule or "icmpv6" in rule: icmp_keyword = "icmpv6" self._rule_replace(rule, "%%REJECT%%", ["reject", "with", icmp_keyword, "type", "admin-prohibited"]) # replace %%ICMP%% self._rule_replace(rule, "%%ICMP%%", ["meta", "l4proto", "{icmp, icmpv6}"]) # replace %%LOGTYPE%% try: i = rule.index("%%LOGTYPE%%") except ValueError: pass else: if log_denied == "off": return "" if log_denied in ["unicast", "broadcast", "multicast"]: rule[i:i+1] = ["pkttype", log_denied] else: rule.pop(i) return self.__run(rule) def get_available_tables(self, table=None): # Tables always exist in nftables return [table] if table else IPTABLES_TO_NFT_HOOK.keys() def build_flush_rules(self): self.rule_to_handle = {} self.rule_ref_count = {} self.zone_source_index_cache = {} rules = [] for family in OUR_CHAINS.keys(): rules.append(["delete", "table", family, "%s" % TABLE_NAME]) return rules def build_set_policy_rules(self, policy): # Policy is not exposed to the user. It's only to make sure we DROP # packets while initially starting and for panic mode. As such, using # hooks with a higher priority than our base chains is sufficient. # table_name = TABLE_NAME + "_" + "policy_drop" rules = [] if policy == "DROP": rules.append(["add", "table", "inet", table_name]) # To drop everything we need to use the "raw" priority. These occur # before conntrack, mangle, nat, etc for hook in ["prerouting", "output"]: _add_chain = "add chain inet %s %s_%s '{ type filter hook %s priority %d ; policy drop ; }'" % \ (table_name, "raw", hook, hook, -300 + NFT_HOOK_OFFSET - 1) rules.append(splitArgs(_add_chain)) elif policy == "ACCEPT": rules.append(["delete", "table", "inet", table_name]) else: FirewallError(UNKNOWN_ERROR, "not implemented") return rules def supported_icmp_types(self): # nftables supports any icmp_type via arbitrary type/code matching. # We just need a translation for it in ICMP_TYPES_FRAGMENT. supported = set() for ipv in ICMP_TYPES_FRAGMENT.keys(): supported.update(ICMP_TYPES_FRAGMENT[ipv].keys()) return list(supported) def build_default_tables(self): default_tables = [] for family in OUR_CHAINS.keys(): default_tables.append("add table %s %s" % (family, TABLE_NAME)) return map(splitArgs, default_tables) def build_default_rules(self, log_denied="off"): default_rules = [] OUR_CHAINS["inet"]["raw"] = set() for chain in IPTABLES_TO_NFT_HOOK["raw"].keys(): default_rules.append("add chain inet %s raw_%s '{ type filter hook %s priority %d ; }'" % (TABLE_NAME, chain, IPTABLES_TO_NFT_HOOK["raw"][chain][0], IPTABLES_TO_NFT_HOOK["raw"][chain][1])) for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules.append("add chain inet %s raw_%s_%s" % (TABLE_NAME, chain, dispatch_suffix)) default_rules.append("add rule inet %s raw_%s jump raw_%s_%s" % (TABLE_NAME, chain, chain, dispatch_suffix)) OUR_CHAINS["inet"]["raw"].update(set(["%s_%s" % (chain, dispatch_suffix)])) OUR_CHAINS["inet"]["mangle"] = set() for chain in IPTABLES_TO_NFT_HOOK["mangle"].keys(): default_rules.append("add chain inet %s mangle_%s '{ type filter hook %s priority %d ; }'" % (TABLE_NAME, chain, IPTABLES_TO_NFT_HOOK["mangle"][chain][0], IPTABLES_TO_NFT_HOOK["mangle"][chain][1])) for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules.append("add chain inet %s mangle_%s_%s" % (TABLE_NAME, chain, dispatch_suffix)) default_rules.append("add rule inet %s mangle_%s jump mangle_%s_%s" % (TABLE_NAME, chain, chain, dispatch_suffix)) OUR_CHAINS["inet"]["mangle"].update(set(["%s_%s" % (chain, dispatch_suffix)])) OUR_CHAINS["ip"]["nat"] = set() OUR_CHAINS["ip6"]["nat"] = set() for family in ["ip", "ip6"]: for chain in IPTABLES_TO_NFT_HOOK["nat"].keys(): default_rules.append("add chain %s %s nat_%s '{ type nat hook %s priority %d ; }'" % (family, TABLE_NAME, chain, IPTABLES_TO_NFT_HOOK["nat"][chain][0], IPTABLES_TO_NFT_HOOK["nat"][chain][1])) for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules.append("add chain %s %s nat_%s_%s" % (family, TABLE_NAME, chain, dispatch_suffix)) default_rules.append("add rule %s %s nat_%s jump nat_%s_%s" % (family, TABLE_NAME, chain, chain, dispatch_suffix)) OUR_CHAINS[family]["nat"].update(set(["%s_%s" % (chain, dispatch_suffix)])) OUR_CHAINS["inet"]["filter"] = set() for chain in IPTABLES_TO_NFT_HOOK["filter"].keys(): default_rules.append("add chain inet %s filter_%s '{ type filter hook %s priority %d ; }'" % (TABLE_NAME, chain, IPTABLES_TO_NFT_HOOK["filter"][chain][0], IPTABLES_TO_NFT_HOOK["filter"][chain][1])) # filter, INPUT default_rules.append("add rule inet %s filter_%s ct state established,related accept" % (TABLE_NAME, "INPUT")) default_rules.append("add rule inet %s filter_%s iifname lo accept" % (TABLE_NAME, "INPUT")) for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules.append("add chain inet %s filter_%s_%s" % (TABLE_NAME, "INPUT", dispatch_suffix)) default_rules.append("add rule inet %s filter_%s jump filter_%s_%s" % (TABLE_NAME, "INPUT", "INPUT", dispatch_suffix)) if log_denied != "off": default_rules.append("add rule inet %s filter_%s ct state invalid %%%%LOGTYPE%%%% log prefix '\"STATE_INVALID_DROP: \"'" % (TABLE_NAME, "INPUT")) default_rules.append("add rule inet %s filter_%s ct state invalid drop" % (TABLE_NAME, "INPUT")) if log_denied != "off": default_rules.append("add rule inet %s filter_%s %%%%LOGTYPE%%%% log prefix '\"FINAL_REJECT: \"'" % (TABLE_NAME, "INPUT")) default_rules.append("add rule inet %s filter_%s reject with icmpx type admin-prohibited" % (TABLE_NAME, "INPUT")) # filter, FORWARD default_rules.append("add chain inet %s filter_%s_IN_ZONES" % (TABLE_NAME, "FORWARD")) default_rules.append("add rule inet %s filter_%s ct state established,related accept" % (TABLE_NAME, "FORWARD")) default_rules.append("add rule inet %s filter_%s iifname lo accept" % (TABLE_NAME, "FORWARD")) for direction in ["IN", "OUT"]: for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules.append("add chain inet %s filter_%s_%s_%s" % (TABLE_NAME, "FORWARD", direction, dispatch_suffix)) default_rules.append("add rule inet %s filter_%s jump filter_%s_%s_%s" % (TABLE_NAME, "FORWARD", "FORWARD", direction, dispatch_suffix)) if log_denied != "off": default_rules.append("add rule inet %s filter_%s ct state invalid %%%%LOGTYPE%%%% log prefix '\"STATE_INVALID_DROP: \"'" % (TABLE_NAME, "FORWARD")) default_rules.append("add rule inet %s filter_%s ct state invalid drop" % (TABLE_NAME, "FORWARD")) if log_denied != "off": default_rules.append("add rule inet %s filter_%s %%%%LOGTYPE%%%% log prefix '\"FINAL_REJECT: \"'" % (TABLE_NAME, "FORWARD")) default_rules.append("add rule inet %s filter_%s reject with icmpx type admin-prohibited" % (TABLE_NAME, "FORWARD")) OUR_CHAINS["inet"]["filter"] = set(["INPUT_ZONES_SOURCE", "INPUT_ZONES", "FORWARD_IN_ZONES_SOURCE", "FORWARD_IN_ZONES", "FORWARD_OUT_ZONES_SOURCE", "FORWARD_OUT_ZONES"]) return map(splitArgs, default_rules) def get_zone_table_chains(self, table): if table == "filter": return ["INPUT", "FORWARD_IN", "FORWARD_OUT"] if table == "mangle": return ["PREROUTING"] if table == "nat": return ["PREROUTING", "POSTROUTING"] if table == "raw": return ["PREROUTING"] return {} def build_zone_source_interface_rules(self, enable, zone, interface, table, chain, append=False, family="inet"): # nat tables needs to use ip/ip6 family if table == "nat" and family == "inet": rules = [] rules.extend(self.build_zone_source_interface_rules(enable, zone, interface, table, chain, append, "ip")) rules.extend(self.build_zone_source_interface_rules(enable, zone, interface, table, chain, append, "ip6")) return rules # handle all zones in the same way here, now # trust and block zone targets are handled now in __chain opt = { "PREROUTING": "iifname", "POSTROUTING": "oifname", "INPUT": "iifname", "FORWARD_IN": "iifname", "FORWARD_OUT": "oifname", "OUTPUT": "oifname", }[chain] if interface[len(interface)-1] == "+": interface = interface[:len(interface)-1] + "*" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) action = "goto" if enable and not append: rule = ["insert", "rule", family, "%s" % TABLE_NAME, "%s_%s_ZONES" % (table, chain), "%%ZONE_INTERFACE%%"] elif enable: rule = ["add", "rule", family, "%s" % TABLE_NAME, "%s_%s_ZONES" % (table, chain)] else: rule = ["delete", "rule", family, "%s" % TABLE_NAME, "%s_%s_ZONES" % (table, chain)] if not append: rule += ["%%ZONE_INTERFACE%%"] if interface == "*": rule += [action, "%s_%s" % (table, target)] else: rule += [opt, "\"" + interface + "\"", action, "%s_%s" % (table, target)] return [rule] def build_zone_source_address_rules(self, enable, zone, address, table, chain, family="inet"): # nat tables needs to use ip/ip6 family if table == "nat" and family == "inet": rules = [] if address.startswith("ipset:"): ipset_family = self._set_get_family(address[len("ipset:"):]) else: ipset_family = None if check_address("ipv4", address) or check_mac(address) or ipset_family == "ip": rules.extend(self.build_zone_source_address_rules(enable, zone, address, table, chain, "ip")) if check_address("ipv6", address) or check_mac(address) or ipset_family == "ip6": rules.extend(self.build_zone_source_address_rules(enable, zone, address, table, chain, "ip6")) return rules add_del = { True: "insert", False: "delete" }[enable] opt = { "PREROUTING": "saddr", "POSTROUTING": "daddr", "INPUT": "saddr", "FORWARD_IN": "saddr", "FORWARD_OUT": "daddr", "OUTPUT": "daddr", }[chain] if self._fw._allow_zone_drifting: zone_dispatch_chain = "%s_%s_ZONES_SOURCE" % (table, chain) else: zone_dispatch_chain = "%s_%s_ZONES" % (table, chain) target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) action = "goto" if address.startswith("ipset:"): ipset = address[len("ipset:"):] rule_family = self._set_get_family(ipset) address = "@" + ipset else: if check_mac(address): # outgoing can not be set if opt == "daddr": return "" rule_family = "ether" elif check_address("ipv4", address): rule_family = "ip" else: rule_family = "ip6" rule = [add_del, "rule", family, "%s" % TABLE_NAME, zone_dispatch_chain, "%%ZONE_SOURCE%%", zone, rule_family, opt, address, action, "%s_%s" % (table, target)] return [rule] def build_zone_chain_rules(self, zone, table, chain, family="inet"): # nat tables needs to use ip/ip6 family if table == "nat" and family == "inet": rules = [] rules.extend(self.build_zone_chain_rules(zone, table, chain, "ip")) rules.extend(self.build_zone_chain_rules(zone, table, chain, "ip6")) return rules _zone = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) OUR_CHAINS[family][table].update(set([_zone, "%s_log" % _zone, "%s_deny" % _zone, "%s_allow" % _zone])) rules = [] rules.append(["add", "chain", family, "%s" % TABLE_NAME, "%s_%s" % (table, _zone)]) rules.append(["add", "chain", family, "%s" % TABLE_NAME, "%s_%s_log" % (table, _zone)]) rules.append(["add", "chain", family, "%s" % TABLE_NAME, "%s_%s_deny" % (table, _zone)]) rules.append(["add", "chain", family, "%s" % TABLE_NAME, "%s_%s_allow" % (table, _zone)]) rules.append(["add", "rule", family, "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "jump", "%s_%s_log" % (table, _zone)]) rules.append(["add", "rule", family, "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "jump", "%s_%s_deny" % (table, _zone)]) rules.append(["add", "rule", family, "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "jump", "%s_%s_allow" % (table, _zone)]) target = self._fw.zone._zones[zone].target if self._fw.get_log_denied() != "off": if table == "filter" and \ chain in ["INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT"]: if target in ["REJECT", "%%REJECT%%", "DROP"]: log_suffix = target if target == "%%REJECT%%": log_suffix = "REJECT" rules.append(["add", "rule", family, "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "%%LOGTYPE%%", "log", "prefix", "\"filter_%s_%s: \"" % (_zone, log_suffix)]) # Handle trust, block and drop zones: # Add an additional rule with the zone target (accept, reject # or drop) to the base zone only in the filter table. # Otherwise it is not be possible to have a zone with drop # target, that is allowing traffic that is locally initiated # or that adds additional rules. (RHBZ#1055190) if table == "filter" and \ target in ["ACCEPT", "REJECT", "%%REJECT%%", "DROP"] and \ chain in ["INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT"]: rules.append(["add", "rule", family, "%s" % TABLE_NAME, "%s_%s" % (table, _zone), target.lower() if target != "%%REJECT%%" else "%%REJECT%%"]) return rules def _reject_types_fragment(self, reject_type): frags = { # REJECT_TYPES : "icmp-host-prohibited" : ["with", "icmp", "type", "host-prohibited"], "host-prohib" : ["with", "icmp", "type", "host-prohibited"], "icmp-net-prohibited" : ["with", "icmp", "type", "net-prohibited"], "net-prohib" : ["with", "icmp", "type", "net-prohibited"], "icmp-admin-prohibited" : ["with", "icmp", "type", "admin-prohibited"], "admin-prohib" : ["with", "icmp", "type", "admin-prohibited"], "icmp6-adm-prohibited" : ["with", "icmpv6", "type", "admin-prohibited"], "adm-prohibited" : ["with", "icmpv6", "type", "admin-prohibited"], "icmp-net-unreachable" : ["with", "icmp", "type", "net-unreachable"], "net-unreach" : ["with", "icmp", "type", "net-unreachable"], "icmp-host-unreachable" : ["with", "icmp", "type", "host-unreachable"], "host-unreach" : ["with", "icmp", "type", "host-unreachable"], "icmp-port-unreachable" : ["with", "icmp", "type", "port-unreachable"], "icmp6-port-unreachable" : ["with", "icmpv6", "type", "port-unreachable"], "port-unreach" : ["with", "icmpx", "type", "port-unreachable"], "icmp-proto-unreachable" : ["with", "icmp", "type", "prot-unreachable"], "proto-unreach" : ["with", "icmp", "type", "prot-unreachable"], "icmp6-addr-unreachable" : ["with", "icmpv6", "type", "addr-unreachable"], "addr-unreach" : ["with", "icmpv6", "type", "addr-unreachable"], "icmp6-no-route" : ["with", "icmpv6", "type", "no-route"], "no-route" : ["with", "icmpv6", "type", "no-route"], "tcp-reset" : ["with", "tcp", "reset"], "tcp-rst" : ["with", "tcp", "reset"], } return frags[reject_type] def _rich_rule_limit_fragment(self, limit): if not limit: return [] rich_to_nft = { "s" : "second", "m" : "minute", "h" : "hour", "d" : "day", } try: i = limit.value.index("/") except ValueError: raise FirewallError(INVALID_RULE, "Expected '/' in limit") return ["limit", "rate", limit.value[0:i], "/", rich_to_nft[limit.value[i+1]]] def _rich_rule_log(self, rich_rule, enable, table, target, rule_fragment): if not rich_rule.log: return [] add_del = { True: "add", False: "delete" }[enable] rule = [add_del, "rule", "inet", "%s" % TABLE_NAME, "%s_%s_log" % (table, target)] rule += rule_fragment + ["log"] if rich_rule.log.prefix: rule += ["prefix", "\"%s\"" % rich_rule.log.prefix] if rich_rule.log.level: rule += ["level", '"%s"' % rich_rule.log.level] rule += self._rich_rule_limit_fragment(rich_rule.log.limit) return rule def _rich_rule_audit(self, rich_rule, enable, table, target, rule_fragment): if not rich_rule.audit: return [] add_del = { True: "add", False: "delete" }[enable] rule = [add_del, "rule", "inet", "%s" % TABLE_NAME, "%s_%s_log" % (table, target)] rule += rule_fragment + ["log", "level", "audit"] rule += self._rich_rule_limit_fragment(rich_rule.audit.limit) return rule def _rich_rule_action(self, zone, rich_rule, enable, table, target, rule_fragment): if not rich_rule.action: return [] add_del = { True: "add", False: "delete" }[enable] if type(rich_rule.action) == Rich_Accept: chain = "%s_%s_allow" % (table, target) rule_action = ["accept"] elif type(rich_rule.action) == Rich_Reject: chain = "%s_%s_deny" % (table, target) rule_action = ["reject"] if rich_rule.action.type: rule_action += self._reject_types_fragment(rich_rule.action.type) elif type(rich_rule.action) == Rich_Drop: chain = "%s_%s_deny" % (table, target) rule_action = ["drop"] elif type(rich_rule.action) == Rich_Mark: target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["PREROUTING"], zone=zone) table = "mangle" chain = "%s_%s_allow" % (table, target) rule_action = ["meta", "mark", "set", rich_rule.action.set] else: raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action)) rule = [add_del, "rule", "inet", "%s" % TABLE_NAME, chain] rule += rule_fragment rule += self._rich_rule_limit_fragment(rich_rule.action.limit) rule += rule_action return rule def _rich_rule_family_fragment(self, rich_family): if not rich_family: return [] if rich_family == "ipv4": return ["meta", "nfproto", "ipv4"] if rich_family == "ipv6": return ["meta", "nfproto", "ipv6"] raise FirewallError(INVALID_RULE, "Invalid family" % rich_family) def _rich_rule_destination_fragment(self, rich_dest): if not rich_dest: return [] rule_fragment = [] if check_address("ipv4", rich_dest.addr): rule_fragment += ["ip"] else: rule_fragment += ["ip6"] if rich_dest.invert: rule_fragment += ["daddr", "!=", rich_dest.addr] else: rule_fragment += ["daddr", rich_dest.addr] return rule_fragment def _rich_rule_source_fragment(self, rich_source): if not rich_source: return [] rule_fragment = [] if rich_source.addr: if check_address("ipv4", rich_source.addr): rule_fragment += ["ip"] else: rule_fragment += ["ip6"] if rich_source.invert: rule_fragment += ["saddr", "!=", rich_source.addr] else: rule_fragment += ["saddr", rich_source.addr] elif hasattr(rich_source, "mac") and rich_source.mac: if rich_source.invert: rule_fragment += ["ether", "saddr", "!=", rich_source.mac] else: rule_fragment += ["ether", "saddr", rich_source.mac] elif hasattr(rich_source, "ipset") and rich_source.ipset: family = self._set_get_family(rich_source.ipset) if rich_source.invert: rule_fragment += [family, "saddr", "!=", "@" + rich_source.ipset] else: rule_fragment += [family, "saddr", "@" + rich_source.ipset] return rule_fragment def build_zone_ports_rules(self, enable, zone, proto, port, destination=None, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_family_fragment(rich_rule.family) if destination: if check_address("ipv4", destination): rule_fragment += ["ip"] else: rule_fragment += ["ip6"] rule_fragment += ["daddr", destination] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rule_fragment += [proto, "dport", "%s" % portStr(port, "-")] if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += ["ct", "state", "new,untracked"] rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "%s_%s_allow" % (table, target)] + rule_fragment + ["accept"]) return rules def build_zone_protocol_rules(self, enable, zone, protocol, destination=None, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_family_fragment(rich_rule.family) if destination: if check_address("ipv4", destination): rule_fragment += ["ip"] else: rule_fragment += ["ip6"] rule_fragment += ["daddr", destination] if rich_rule: rule_fragment += self._rich_rule_family_fragment(rich_rule.family) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rule_fragment = ["meta", "l4proto", protocol] if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += ["ct", "state", "new,untracked"] rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "filter_%s_allow" % (target)] + rule_fragment + ["accept"]) return rules def build_zone_source_ports_rules(self, enable, zone, proto, port, destination=None, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_family_fragment(rich_rule.family) if destination: if check_address("ipv4", destination): rule_fragment += ["ip"] else: rule_fragment += ["ip6"] rule_fragment += ["daddr", destination] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rule_fragment += [proto, "sport", "%s" % portStr(port, "-")] if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += ["ct", "state", "new,untracked"] rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "%s_%s_allow" % (table, target)] + rule_fragment + ["accept"]) return rules def build_zone_helper_ports_rules(self, enable, zone, proto, port, destination, helper_name, module_short_name): add_del = { True: "add", False: "delete" }[enable] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule = [add_del, "rule", "inet", "%s" % TABLE_NAME, "filter_%s_allow" % (target)] if destination: if check_address("ipv4", destination): rule += ["ip"] else: rule += ["ip6"] rule += ["daddr", destination] rule += [proto, "dport", "%s" % portStr(port, "-")] rule += ["ct", "helper", "set", "\"helper-%s-%s\"" % (helper_name, proto)] helper_object = ["ct", "helper", "inet", TABLE_NAME, "helper-%s-%s" % (helper_name, proto), "{", "type", "\"%s\"" % (module_short_name), "protocol", proto, ";", "}"] return [helper_object, rule] def _build_zone_masquerade_nat_rules(self, enable, zone, family, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["POSTROUTING"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) return [[add_del, "rule", family, "%s" % TABLE_NAME, "nat_%s_allow" % (target)] + rule_fragment + ["oifname", "!=", "lo", "masquerade"]] def build_zone_masquerade_rules(self, enable, zone, rich_rule=None): # nat tables needs to use ip/ip6 family rules = [] if rich_rule and (rich_rule.family and rich_rule.family == "ipv6" or rich_rule.source and check_address("ipv6", rich_rule.source.addr)): rules.extend(self._build_zone_masquerade_nat_rules(enable, zone, "ip6", rich_rule)) elif rich_rule and (rich_rule.family and rich_rule.family == "ipv4" or rich_rule.source and check_address("ipv4", rich_rule.source.addr)): rules.extend(self._build_zone_masquerade_nat_rules(enable, zone, "ip", rich_rule)) else: rules.extend(self._build_zone_masquerade_nat_rules(enable, zone, "ip", rich_rule)) add_del = { True: "add", False: "delete" }[enable] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["FORWARD_OUT"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "filter_%s_allow" % (target)] + rule_fragment + ["ct", "state", "new,untracked", "accept"]) return rules def _build_zone_forward_port_nat_rules(self, enable, zone, protocol, mark_fragment, toaddr, toport, family): add_del = { True: "add", False: "delete" }[enable] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["PREROUTING"], zone=zone) dnat_fragment = [] if toaddr: dnat_fragment += ["dnat", "to", toaddr] else: dnat_fragment += ["redirect", "to"] if toport and toport != "": dnat_fragment += [":%s" % portStr(toport, "-")] return [[add_del, "rule", family, "%s" % TABLE_NAME, "nat_%s_allow" % (target), "meta", "l4proto", protocol] + mark_fragment + dnat_fragment] def build_zone_forward_port_rules(self, enable, zone, filter_chain, port, protocol, toport, toaddr, mark_id, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] mark_str = "0x%x" % mark_id mark_fragment = ["meta", "mark", mark_str] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["PREROUTING"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_family_fragment(rich_rule.family) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules = [] rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "mangle_%s_allow" % (target)] + rule_fragment + [protocol, "dport", port, "meta", "mark", "set", mark_str]) if rich_rule and (rich_rule.family and rich_rule.family == "ipv6" or toaddr and check_single_address("ipv6", toaddr)): rules.extend(self._build_zone_forward_port_nat_rules(enable, zone, protocol, mark_fragment, toaddr, toport, "ip6")) elif rich_rule and (rich_rule.family and rich_rule.family == "ipv4" or toaddr and check_single_address("ipv4", toaddr)): rules.extend(self._build_zone_forward_port_nat_rules(enable, zone, protocol, mark_fragment, toaddr, toport, "ip")) else: if toaddr and check_single_address("ipv6", toaddr): rules.extend(self._build_zone_forward_port_nat_rules(enable, zone, protocol, mark_fragment, toaddr, toport, "ip6")) else: rules.extend(self._build_zone_forward_port_nat_rules(enable, zone, protocol, mark_fragment, toaddr, toport, "ip")) target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[filter_chain], zone=zone) rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "filter_%s_allow" % (target), "ct", "state", "new,untracked"] + mark_fragment + ["accept"]) return rules def _icmp_types_to_nft_fragment(self, ipv, icmp_type): if icmp_type in ICMP_TYPES_FRAGMENT[ipv]: return ICMP_TYPES_FRAGMENT[ipv][icmp_type] else: raise FirewallError(INVALID_ICMPTYPE, "ICMP type '%s' not supported by %s" % (icmp_type, self.name)) def build_zone_icmp_block_rules(self, enable, zone, ict, rich_rule=None): table = "filter" add_del = { True: "add", False: "delete" }[enable] if rich_rule and rich_rule.ipvs: ipvs = rich_rule.ipvs elif ict.destination: ipvs = [] if "ipv4" in ict.destination: ipvs.append("ipv4") if "ipv6" in ict.destination: ipvs.append("ipv6") else: ipvs = ["ipv4", "ipv6"] rules = [] for ipv in ipvs: for chain in ["INPUT", "FORWARD_IN"]: target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) if self._fw.zone.query_icmp_block_inversion(zone): final_chain = "%s_%s_allow" % (table, target) final_target = "accept" else: final_chain = "%s_%s_deny" % (table, target) final_target = "%%REJECT%%" rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_family_fragment(rich_rule.family) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rule_fragment += self._icmp_types_to_nft_fragment(ipv, ict.name) if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) if rich_rule.action: rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, "%s_%s_deny" % (table, target)] + rule_fragment + ["%%REJECT%%"]) else: if self._fw.get_log_denied() != "off" and final_target != "accept": rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, final_chain] + rule_fragment + ["%%LOGTYPE%%", "log", "prefix", "\"%s_%s_ICMP_BLOCK: \"" % (table, zone)]) rules.append([add_del, "rule", "inet", "%s" % TABLE_NAME, final_chain] + rule_fragment + [final_target]) return rules def build_zone_icmp_block_inversion_rules(self, enable, zone): table = "filter" rules = [] for chain in ["INPUT", "FORWARD_IN"]: _zone = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) # HACK: nft position is actually a handle, so we need to lookup the # handle of the rule we want to insert this after. # # This must be kept in sync with build_zone_chain_rules() # # WARN: This does not work if we haven't executed the transaction # yet, because we don't have a handle for our rule_key!! As such, # we execute transactions before calling this function. # rule_key = " ".join(["inet", "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "jump", "%s_%s_allow" % (table, _zone)]) rule_handle = self.rule_to_handle[rule_key] if self._fw.zone.query_icmp_block_inversion(zone): ibi_target = "%%REJECT%%" else: ibi_target = "accept" if enable: # FIXME: can we get rid of position ? rule = ["add", "rule", "inet", "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "position", rule_handle] else: rule = ["delete", "rule", "inet", "%s" % TABLE_NAME, "%s_%s" % (table, _zone)] rule += ["%%ICMP%%", ibi_target] rules.append(rule) if self._fw.zone.query_icmp_block_inversion(zone): if self._fw.get_log_denied() != "off": if enable: # FIXME: can we get rid of position ? rule = ["add", "rule", "inet", "%s" % TABLE_NAME, "%s_%s" % (table, _zone), "position", rule_handle] else: rule = ["delete", "rule", "inet", "%s" % TABLE_NAME, "%s_%s" % (table, _zone)] rule += ["%%ICMP%%", "%%LOGTYPE%%", "log", "prefix", "\"%s_%s_ICMP_BLOCK: \"" % (table, _zone)] rules.append(rule) return rules def build_rpfilter_rules(self, log_denied=False): rules = [] rules.append(["insert", "rule", "inet", "%s" % TABLE_NAME, "raw_%s" % "PREROUTING", "meta", "nfproto", "ipv6", "fib", "saddr", ".", "iif", "oif", "missing", "drop"]) if log_denied != "off": rules.append(["insert", "rule", "inet", "%s" % TABLE_NAME, "raw_%s" % "PREROUTING", "meta", "nfproto", "ipv6", "fib", "saddr", ".", "iif", "oif", "missing", "log", "prefix", "\"rpfilter_DROP: \""]) rules.append(["insert", "rule", "inet", "%s" % TABLE_NAME, "raw_%s" % "PREROUTING", "icmpv6", "type", "{ nd-router-advert, nd-neighbor-solicit }", "accept"]) # RHBZ#1058505, RHBZ#1575431 (bug in kernel 4.16-4.17) return rules def build_zone_rich_source_destination_rules(self, enable, zone, rich_rule): table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [] rule_fragment += self._rich_rule_family_fragment(rich_rule.family) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules = [] rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) return rules def is_ipv_supported(self, ipv): if ipv in ["ipv4", "ipv6", "eb"]: return True return False def _set_type_fragment(self, ipv, type): ipv_addr = { "ipv4" : "ipv4_addr", "ipv6" : "ipv6_addr", } types = { "hash:ip" : [ipv_addr[ipv]], "hash:ip,port" : [ipv_addr[ipv], ". inet_proto", ". inet_service"], "hash:ip,port,ip" : [ipv_addr[ipv], ". inet_proto", ". inet_service .", ipv_addr[ipv]], "hash:ip,port,net" : [ipv_addr[ipv], ". inet_proto", ". inet_service .", ipv_addr[ipv]], "hash:ip,mark" : [ipv_addr[ipv], ". mark"], "hash:net" : [ipv_addr[ipv]], "hash:net,port" : [ipv_addr[ipv], ". inet_proto", ". inet_service"], "hash:net,port,ip" : [ipv_addr[ipv], ". inet_proto", ". inet_service .", ipv_addr[ipv]], "hash:net,port,net" : [ipv_addr[ipv], ". inet_proto", ". inet_service .", ipv_addr[ipv]], "hash:net,iface" : [ipv_addr[ipv], ". ifname"], "hash:mac" : ["ether_addr"], } try: return ["type"] + types[type] + [";"] except KeyError: raise FirewallError(INVALID_TYPE, "ipset type name '%s' is not valid" % type) def set_create(self, name, type, options=None): if options and "family" in options and options["family"] == "inet6": ipv = "ipv6" else: ipv = "ipv4" cmd = [name, "{"] cmd += self._set_type_fragment(ipv, type) if options: if "timeout" in options: cmd += ["timeout", options["timeout"]+ "s", ";"] if "maxelem" in options: cmd += ["size", options["maxelem"], ";"] # flag "interval" currently does not work with timeouts or # concatenations. See rhbz 1576426, 1576430. if (not options or "timeout" not in options) \ and "," not in type: # e.g. hash:net,port cmd += ["flags", "interval", ";"] cmd += ["}"] for family in ["inet", "ip", "ip6"]: self.__run(["add", "set", family, TABLE_NAME] + cmd) def set_destroy(self, name): for family in ["inet", "ip", "ip6"]: self.__run(["delete", "set", family, TABLE_NAME, name]) def _set_entry_fragment(self, name, entry): # convert something like # 1.2.3.4,sctp:8080 (type hash:ip,port) # to # 1.2.3.4 . sctp . 8080 type_format = self._fw.ipset.get_type(name).split(":")[1].split(",") entry_tokens = entry.split(",") if len(type_format) != len(entry_tokens): raise FirewallError(INVALID_ENTRY, "Number of values does not match ipset type.") fragment = [] for i in range(len(type_format)): if type_format[i] == "port": try: index = entry_tokens[i].index(":") except ValueError: # no protocol means default tcp fragment += ["tcp", ".", entry_tokens[i]] else: fragment += [entry_tokens[i][:index], ".", entry_tokens[i][index+1:]] else: fragment.append(entry_tokens[i]) fragment.append(".") return fragment[:-1] # snip last concat operator def set_add(self, name, entry): for family in ["inet", "ip", "ip6"]: self.__run(["add", "element", family, TABLE_NAME, name, "{"] + self._set_entry_fragment(name, entry) + ["}"]) def set_delete(self, name, entry): for family in ["inet", "ip", "ip6"]: self.__run(["delete", "element", family, TABLE_NAME, name, "{"] + self._set_entry_fragment(name, entry) + ["}"]) def set_flush(self, name): for family in ["inet", "ip", "ip6"]: self.__run(["flush", "set", family, TABLE_NAME, name]) def _set_get_family(self, name): ipset = self._fw.ipset.get_ipset(name) if ipset.type == "hash:mac": family = "ether" elif ipset.options and "family" in ipset.options \ and ipset.options["family"] == "inet6": family = "ip6" else: family = "ip" return family PK!@@ modules.pyonu[ c`c@sYdZdgZddlmZddlmZddlmZdefdYZ dS(smodules backendtmodulesi(trunProg(tlog(tCOMMANDScBsPeZdZdZdZdZdZdZdZdZ RS(cCstd|_td|_dS(Ntmodprobetrmmod(Rt _load_commandt_unload_command(tself((s9/usr/lib/python2.7/site-packages/firewall/core/modules.pyt__init__s cCs d|jS(Ns%s(t __class__(R((s9/usr/lib/python2.7/site-packages/firewall/core/modules.pyt__repr__$sc Csg}i}tdd}x|D]y}|s5Pn|j}|j}|j|d|ddkr|djdd ||ds  PK! __init__.pynu[PK!H H fw_helper.pyonu[ c`c@sIdZdgZddlmZddlmZdefdYZdS(shelper backendtFirewallHelperi(terrors(t FirewallErrorcBsbeZdZdZdZdZdZdZdZdZ dZ d Z RS( cCs||_i|_dS(N(t_fwt_helpers(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt__init__s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt__repr__"scCs|jjdS(N(Rtclear(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pytcleanup'scCs+||jkr'ttj|ndS(N(t get_helpersRRtINVALID_HELPER(Rtname((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt check_helper*scCs||jkS(N(R (RR((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt query_helper.scCst|jjS(N(tsortedRtkeys(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyR 1scCst|jdkS(Ni(tlenR(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt has_helpers4scCs|j||j|S(N(RR(RR((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt get_helper7s cCs||j|js( t__name__t __module__RR R RRR RRRR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyRs         N(t__doc__t__all__tfirewallRtfirewall.errorsRtobjectR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyts PK!H H fw_helper.pycnu[ c`c@sIdZdgZddlmZddlmZdefdYZdS(shelper backendtFirewallHelperi(terrors(t FirewallErrorcBsbeZdZdZdZdZdZdZdZdZ dZ d Z RS( cCs||_i|_dS(N(t_fwt_helpers(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt__init__s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt__repr__"scCs|jjdS(N(Rtclear(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pytcleanup'scCs+||jkr'ttj|ndS(N(t get_helpersRRtINVALID_HELPER(Rtname((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt check_helper*scCs||jkS(N(R (RR((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt query_helper.scCst|jjS(N(tsortedRtkeys(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyR 1scCst|jdkS(Ni(tlenR(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt has_helpers4scCs|j||j|S(N(RR(RR((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyt get_helper7s cCs||j|js( t__name__t __module__RR R RRR RRRR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyRs         N(t__doc__t__all__tfirewallRtfirewall.errorsRtobjectR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_helper.pyts PK!n%?-fw_service.pyonu[ c`c@sCdgZddlmZddlmZdefdYZdS(tFirewallServicei(terrors(t FirewallErrorcBsPeZdZdZdZdZdZdZdZdZ RS(cCs||_i|_dS(N(t_fwt _services(tselftfw((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt__init__s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt__repr__ scCs|jjdS(N(Rtclear(R((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pytcleanup#scCst|jjS(N(tsortedRtkeys(R((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt get_services(scCs(||jkr$ttj|ndS(N(RRRtINVALID_SERVICE(Rtservice((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt check_service+scCs|j||j|S(N(RR(RR((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt get_service/s cCs||j|js PK!S>R(*(*fw_transaction.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 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 . # """Transaction classes for firewalld""" __all__ = [ "FirewallTransaction", "FirewallZoneTransaction" ] from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError from firewall.fw_types import LastUpdatedOrderedDict class SimpleFirewallTransaction(object): """Base class for FirewallTransaction and FirewallZoneTransaction""" def __init__(self, fw): self.fw = fw self.rules = { } # [ ( backend.name, [ rule,.. ] ),.. ] self.pre_funcs = [ ] # [ (func, args),.. ] self.post_funcs = [ ] # [ (func, args),.. ] self.fail_funcs = [ ] # [ (func, args),.. ] def clear(self): self.rules.clear() del self.pre_funcs[:] del self.post_funcs[:] del self.fail_funcs[:] def add_rule(self, backend, rule): self.rules.setdefault(backend.name, [ ]).append(rule) def add_rules(self, backend, rules): for rule in rules: self.add_rule(backend, rule) def query_rule(self, backend, rule): return backend.name in self.rules and rule in self.rules[backend.name] def remove_rule(self, backend, rule): if backend.name in self.rules and rule in self.rules[backend.name]: self.rules[backend.name].remove(rule) def add_pre(self, func, *args): self.pre_funcs.append((func, args)) def add_post(self, func, *args): self.post_funcs.append((func, args)) def add_fail(self, func, *args): self.fail_funcs.append((func, args)) def prepare(self, enable, rules=None, modules=None): log.debug4("%s.prepare(%s, %s)" % (type(self), enable, "...")) if rules is None: rules = { } if modules is None: modules = [ ] if not enable: # reverse rule order for cleanup for backend_name in self.rules: for rule in reversed(self.rules[backend_name]): rules.setdefault(backend_name, [ ]).append( self.fw.get_backend_by_name(backend_name).reverse_rule(rule)) else: for backend_name in self.rules: rules.setdefault(backend_name, [ ]).extend(self.rules[backend_name]) return rules, modules def execute(self, enable): log.debug4("%s.execute(%s)" % (type(self), enable)) rules, modules = self.prepare(enable) # pre self.pre() # stage 1: apply rules error = False errorMsg = "" done = [ ] for backend_name in rules: try: self.fw.rules(backend_name, rules[backend_name]) except Exception as msg: error = True errorMsg = msg log.error(msg) else: done.append(backend_name) # stage 2: load modules if not error: module_return = self.fw.handle_modules(modules, enable) if module_return: # Debug log about issues loading modules, but don't error. The # modules may be builtin or CONFIG_MODULES=n, in which case # modprobe will fail. Or we may be running inside a container # that doesn't have sufficient privileges. Unfortunately there # is no way for us to know. (status, msg) = module_return if status: log.debug1(msg) # error case: revert rules if error: undo_rules = { } for backend_name in done: undo_rules[backend_name] = [ ] for rule in reversed(rules[backend_name]): undo_rules[backend_name].append( self.fw.get_backend_by_name(backend_name).reverse_rule(rule)) for backend_name in undo_rules: try: self.fw.rules(backend_name, undo_rules[backend_name]) except Exception as msg: log.error(msg) # call failure functions for (func, args) in self.fail_funcs: try: func(*args) except Exception as msg: log.error("Calling fail func %s(%s) failed: %s" % \ (func, args, msg)) raise FirewallError(errors.COMMAND_FAILED, errorMsg) # post self.post() def pre(self): log.debug4("%s.pre()" % type(self)) for (func, args) in self.pre_funcs: try: func(*args) except Exception as msg: log.error("Calling pre func %s(%s) failed: %s" % \ (func, args, msg)) def post(self): log.debug4("%s.post()" % type(self)) for (func, args) in self.post_funcs: try: func(*args) except Exception as msg: log.error("Calling post func %s(%s) failed: %s" % \ (func, args, msg)) # class FirewallTransaction class FirewallTransaction(SimpleFirewallTransaction): """General FirewallTransaction, contains also zone transactions""" def __init__(self, fw): super(FirewallTransaction, self).__init__(fw) self.zone_transactions = LastUpdatedOrderedDict() # { zone: transaction, .. } def clear(self): super(FirewallTransaction, self).clear() self.zone_transactions.clear() def zone_transaction(self, zone): if zone not in self.zone_transactions: self.zone_transactions[zone] = FirewallZoneTransaction( self.fw, zone, self) return self.zone_transactions[zone] def prepare(self, enable, rules=None, modules=None): log.debug4("%s.prepare(%s, %s)" % (type(self), enable, "...")) rules, modules = super(FirewallTransaction, self).prepare( enable, rules, modules) for zone in self.zone_transactions: try: self.zone_transactions[zone].prepare(enable, rules) for module in self.zone_transactions[zone].modules: if module not in modules: modules.append(module) except FirewallError as msg: log.error("Failed to prepare transaction rules for zone '%s'", str(msg)) return rules, modules def pre(self): log.debug4("%s.pre()" % type(self)) super(FirewallTransaction, self).pre() for zone in self.zone_transactions: self.zone_transactions[zone].pre() def post(self): log.debug4("%s.post()" % type(self)) super(FirewallTransaction, self).post() for zone in self.zone_transactions: self.zone_transactions[zone].post() # class FirewallZoneTransaction class FirewallZoneTransaction(SimpleFirewallTransaction): """Zone transaction with additional chain and module interface""" def __init__(self, fw, zone, fw_transaction=None): super(FirewallZoneTransaction, self).__init__(fw) self.zone = zone self.fw_transaction = fw_transaction self.chains = [ ] # [ (table, chain),.. ] self.modules = [ ] # [ module,.. ] def clear(self): # calling clear on a zone_transaction that was spawned from a # FirewallTransaction needs to clear the fw_transaction and all the # other zones otherwise we end up with a partially cleared transaction. if self.fw_transaction: super(FirewallTransaction, self.fw_transaction).clear() for zone in self.fw_transaction.zone_transactions.keys(): super(FirewallZoneTransaction, self.fw_transaction.zone_transactions[zone]).clear() del self.fw_transaction.zone_transactions[zone].chains[:] del self.fw_transaction.zone_transactions[zone].modules[:] else: super(FirewallZoneTransaction, self).clear() del self.chains[:] del self.modules[:] def prepare(self, enable, rules=None, modules=None): log.debug4("%s.prepare(%s, %s)" % (type(self), enable, "...")) rules, modules = super(FirewallZoneTransaction, self).prepare( enable, rules, modules) for module in self.modules: if module not in modules: modules.append(module) return rules, modules def execute(self, enable): # calling execute on a zone_transaction that was spawned from a # FirewallTransaction should execute the FirewallTransaction as it may # have prerequisite rules if self.fw_transaction: self.fw_transaction.execute(enable) else: super(FirewallZoneTransaction, self).execute(enable) def add_chain(self, table, chain): table_chain = (table, chain) if table_chain not in self.chains: self.fw.zone.gen_chain_rules(self.zone, True, [table_chain], self) self.chains.append(table_chain) def remove_chain(self, table, chain): table_chain = (table, chain) if table_chain in self.chains: self.chains.remove(table_chain) def add_chains(self, chains): for table_chain in chains: if table_chain not in self.chains: self.add_chain(table_chain[0], table_chain[1]) def remove_chains(self, chains): for table_chain in chains: if table_chain in self.chains: self.chains.remove(table_chain) def add_module(self, module): if module not in self.modules: self.modules.append(module) def remove_module(self, module): if module in self.modules: self.modules.remove(module) def add_modules(self, modules): for module in modules: self.add_module(module) def remove_modules(self, modules): for module in modules: self.remove_module(module) PK!}w@ helper.pycnu[ c`c@sdZdZdS(sThe helper maxnameleni N(t__doc__tHELPER_MAXNAMELEN(((s8/usr/lib/python2.7/site-packages/firewall/core/helper.pytsPK! Z? fw_config.pynu[# -*- 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__ = [ "FirewallConfig" ] import copy import os import os.path import shutil from firewall import config from firewall.core.logger import log from firewall.core.io.icmptype import IcmpType, icmptype_reader, icmptype_writer from firewall.core.io.service import Service, service_reader, service_writer from firewall.core.io.zone import Zone, zone_reader, zone_writer from firewall.core.io.ipset import IPSet, ipset_reader, ipset_writer from firewall.core.io.helper import Helper, helper_reader, helper_writer from firewall import errors from firewall.errors import FirewallError class FirewallConfig(object): def __init__(self, fw): self._fw = fw self.__init_vars() def __repr__(self): return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \ (self.__class__, self._ipsets, self._icmptypes, self._services, self._zones, self._helpers, self._builtin_ipsets, self._builtin_icmptypes, self._builtin_services, self._builtin_zones, self._builtin_helpers, self._firewalld_conf, self._policies, self._direct) def __init_vars(self): self._ipsets = { } self._icmptypes = { } self._services = { } self._zones = { } self._helpers = { } self._builtin_ipsets = { } self._builtin_icmptypes = { } self._builtin_services = { } self._builtin_zones = { } self._builtin_helpers = { } self._firewalld_conf = None self._policies = None self._direct = None def cleanup(self): for x in list(self._builtin_ipsets.keys()): self._builtin_ipsets[x].cleanup() del self._builtin_ipsets[x] for x in list(self._ipsets.keys()): self._ipsets[x].cleanup() del self._ipsets[x] for x in list(self._builtin_icmptypes.keys()): self._builtin_icmptypes[x].cleanup() del self._builtin_icmptypes[x] for x in list(self._icmptypes.keys()): self._icmptypes[x].cleanup() del self._icmptypes[x] for x in list(self._builtin_services.keys()): self._builtin_services[x].cleanup() del self._builtin_services[x] for x in list(self._services.keys()): self._services[x].cleanup() del self._services[x] for x in list(self._builtin_zones.keys()): self._builtin_zones[x].cleanup() del self._builtin_zones[x] for x in list(self._zones.keys()): self._zones[x].cleanup() del self._zones[x] for x in list(self._builtin_helpers.keys()): self._builtin_helpers[x].cleanup() del self._builtin_helpers[x] for x in list(self._helpers.keys()): self._helpers[x].cleanup() del self._helpers[x] if self._firewalld_conf: self._firewalld_conf.cleanup() del self._firewalld_conf self._firewalld_conf = None if self._policies: self._policies.cleanup() del self._policies self._policies = None if self._direct: self._direct.cleanup() del self._direct self._direct = None self.__init_vars() # access check def lockdown_enabled(self): return self._fw.policies.query_lockdown() def access_check(self, key, value): return self._fw.policies.access_check(key, value) # firewalld_conf def set_firewalld_conf(self, conf): self._firewalld_conf = conf def get_firewalld_conf(self): return self._firewalld_conf def update_firewalld_conf(self): if not os.path.exists(config.FIREWALLD_CONF): self._firewalld_conf.clear() else: self._firewalld_conf.read() # policies def set_policies(self, policies): self._policies = policies def get_policies(self): return self._policies def update_lockdown_whitelist(self): if not os.path.exists(config.LOCKDOWN_WHITELIST): self._policies.lockdown_whitelist.cleanup() else: self._policies.lockdown_whitelist.read() # direct def set_direct(self, direct): self._direct = direct def get_direct(self): return self._direct def update_direct(self): if not os.path.exists(config.FIREWALLD_DIRECT): self._direct.cleanup() else: self._direct.read() # ipset def get_ipsets(self): return sorted(set(list(self._ipsets.keys()) + \ list(self._builtin_ipsets.keys()))) def add_ipset(self, obj): if obj.builtin: self._builtin_ipsets[obj.name] = obj else: self._ipsets[obj.name] = obj def get_ipset(self, name): if name in self._ipsets: return self._ipsets[name] elif name in self._builtin_ipsets: return self._builtin_ipsets[name] raise FirewallError(errors.INVALID_IPSET, name) def load_ipset_defaults(self, obj): if obj.name not in self._ipsets: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._ipsets[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._ipsets[%s] != obj" % obj.name) elif obj.name not in self._builtin_ipsets: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in ipset" % obj.name) self._remove_ipset(obj) return self._builtin_ipsets[obj.name] def get_ipset_config(self, obj): return obj.export_config() def set_ipset_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_IPSETS x.builtin = False if obj.path != x.path: x.default = False self.add_ipset(x) ipset_writer(x) return x else: obj.import_config(conf) ipset_writer(obj) return obj def new_ipset(self, name, conf): if name in self._ipsets or name in self._builtin_ipsets: raise FirewallError(errors.NAME_CONFLICT, "new_ipset(): '%s'" % name) x = IPSet() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_IPSETS # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True ipset_writer(x) self.add_ipset(x) return x def update_ipset_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_IPSETS: # removed custom ipset for x in self._ipsets.keys(): obj = self._ipsets[x] if obj.filename == filename: del self._ipsets[x] if obj.name in self._builtin_ipsets: return ("update", self._builtin_ipsets[obj.name]) return ("remove", obj) else: # removed builtin ipset for x in self._builtin_ipsets.keys(): obj = self._builtin_ipsets[x] if obj.filename == filename: del self._builtin_ipsets[x] if obj.name not in self._ipsets: # update dbus ipset return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # ipset not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading ipset file '%s'", name) try: obj = ipset_reader(filename, path) except Exception as msg: log.error("Failed to load ipset file '%s': %s", filename, msg) return (None, None) # new ipset if obj.name not in self._builtin_ipsets and obj.name not in self._ipsets: self.add_ipset(obj) return ("new", obj) # updated ipset if path == config.ETC_FIREWALLD_IPSETS: # custom ipset update if obj.name in self._ipsets: obj.default = self._ipsets[obj.name].default self._ipsets[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_ipsets: # builtin ipset update del self._builtin_ipsets[obj.name] self._builtin_ipsets[obj.name] = obj if obj.name not in self._ipsets: # update dbus ipset return ("update", obj) else: # builtin hidden, no update needed return (None, None) # ipset not known to firewalld, yet (timeout, ..) return (None, None) def _remove_ipset(self, obj): if obj.name not in self._ipsets: raise FirewallError(errors.INVALID_IPSET, obj.name) if obj.path != config.ETC_FIREWALLD_IPSETS: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % (obj.path, config.ETC_FIREWALLD_IPSETS)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._ipsets[obj.name] def check_builtin_ipset(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_IPSET, "'%s' is built-in ipset" % obj.name) def remove_ipset(self, obj): self.check_builtin_ipset(obj) self._remove_ipset(obj) def rename_ipset(self, obj, name): self.check_builtin_ipset(obj) new_ipset = self._copy_ipset(obj, name) self._remove_ipset(obj) return new_ipset def _copy_ipset(self, obj, name): return self.new_ipset(name, obj.export_config()) # icmptypes def get_icmptypes(self): return sorted(set(list(self._icmptypes.keys()) + \ list(self._builtin_icmptypes.keys()))) def add_icmptype(self, obj): if obj.builtin: self._builtin_icmptypes[obj.name] = obj else: self._icmptypes[obj.name] = obj def get_icmptype(self, name): if name in self._icmptypes: return self._icmptypes[name] elif name in self._builtin_icmptypes: return self._builtin_icmptypes[name] raise FirewallError(errors.INVALID_ICMPTYPE, name) def load_icmptype_defaults(self, obj): if obj.name not in self._icmptypes: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._icmptypes[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._icmptypes[%s] != obj" % obj.name) elif obj.name not in self._builtin_icmptypes: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in icmptype" % obj.name) self._remove_icmptype(obj) return self._builtin_icmptypes[obj.name] def get_icmptype_config(self, obj): return obj.export_config() def set_icmptype_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_ICMPTYPES x.builtin = False if obj.path != x.path: x.default = False self.add_icmptype(x) icmptype_writer(x) return x else: obj.import_config(conf) icmptype_writer(obj) return obj def new_icmptype(self, name, conf): if name in self._icmptypes or name in self._builtin_icmptypes: raise FirewallError(errors.NAME_CONFLICT, "new_icmptype(): '%s'" % name) x = IcmpType() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_ICMPTYPES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True icmptype_writer(x) self.add_icmptype(x) return x def update_icmptype_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_ICMPTYPES: # removed custom icmptype for x in self._icmptypes.keys(): obj = self._icmptypes[x] if obj.filename == filename: del self._icmptypes[x] if obj.name in self._builtin_icmptypes: return ("update", self._builtin_icmptypes[obj.name]) return ("remove", obj) else: # removed builtin icmptype for x in self._builtin_icmptypes.keys(): obj = self._builtin_icmptypes[x] if obj.filename == filename: del self._builtin_icmptypes[x] if obj.name not in self._icmptypes: # update dbus icmptype return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # icmptype not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading icmptype file '%s'", name) try: obj = icmptype_reader(filename, path) except Exception as msg: log.error("Failed to load icmptype file '%s': %s", filename, msg) return (None, None) # new icmptype if obj.name not in self._builtin_icmptypes and obj.name not in self._icmptypes: self.add_icmptype(obj) return ("new", obj) # updated icmptype if path == config.ETC_FIREWALLD_ICMPTYPES: # custom icmptype update if obj.name in self._icmptypes: obj.default = self._icmptypes[obj.name].default self._icmptypes[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_icmptypes: # builtin icmptype update del self._builtin_icmptypes[obj.name] self._builtin_icmptypes[obj.name] = obj if obj.name not in self._icmptypes: # update dbus icmptype return ("update", obj) else: # builtin hidden, no update needed return (None, None) # icmptype not known to firewalld, yet (timeout, ..) return (None, None) def _remove_icmptype(self, obj): if obj.name not in self._icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, obj.name) if obj.path != config.ETC_FIREWALLD_ICMPTYPES: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % \ (obj.path, config.ETC_FIREWALLD_ICMPTYPES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._icmptypes[obj.name] def check_builtin_icmptype(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_ICMPTYPE, "'%s' is built-in icmp type" % obj.name) def remove_icmptype(self, obj): self.check_builtin_icmptype(obj) self._remove_icmptype(obj) def rename_icmptype(self, obj, name): self.check_builtin_icmptype(obj) new_icmptype = self._copy_icmptype(obj, name) self._remove_icmptype(obj) return new_icmptype def _copy_icmptype(self, obj, name): return self.new_icmptype(name, obj.export_config()) # services def get_services(self): return sorted(set(list(self._services.keys()) + \ list(self._builtin_services.keys()))) def add_service(self, obj): if obj.builtin: self._builtin_services[obj.name] = obj else: self._services[obj.name] = obj def get_service(self, name): if name in self._services: return self._services[name] elif name in self._builtin_services: return self._builtin_services[name] raise FirewallError(errors.INVALID_SERVICE, "get_service(): '%s'" % name) def load_service_defaults(self, obj): if obj.name not in self._services: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._services[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._services[%s] != obj" % obj.name) elif obj.name not in self._builtin_services: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in service" % obj.name) self._remove_service(obj) return self._builtin_services[obj.name] def get_service_config(self, obj): return obj.export_config() def set_service_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_SERVICES x.builtin = False if obj.path != x.path: x.default = False self.add_service(x) service_writer(x) return x else: obj.import_config(conf) service_writer(obj) return obj def new_service(self, name, conf): if name in self._services or name in self._builtin_services: raise FirewallError(errors.NAME_CONFLICT, "new_service(): '%s'" % name) x = Service() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_SERVICES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True service_writer(x) self.add_service(x) return x def update_service_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_SERVICES: # removed custom service for x in self._services.keys(): obj = self._services[x] if obj.filename == filename: del self._services[x] if obj.name in self._builtin_services: return ("update", self._builtin_services[obj.name]) return ("remove", obj) else: # removed builtin service for x in self._builtin_services.keys(): obj = self._builtin_services[x] if obj.filename == filename: del self._builtin_services[x] if obj.name not in self._services: # update dbus service return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # service not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading service file '%s'", name) try: obj = service_reader(filename, path) except Exception as msg: log.error("Failed to load service file '%s': %s", filename, msg) return (None, None) # new service if obj.name not in self._builtin_services and obj.name not in self._services: self.add_service(obj) return ("new", obj) # updated service if path == config.ETC_FIREWALLD_SERVICES: # custom service update if obj.name in self._services: obj.default = self._services[obj.name].default self._services[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_services: # builtin service update del self._builtin_services[obj.name] self._builtin_services[obj.name] = obj if obj.name not in self._services: # update dbus service return ("update", obj) else: # builtin hidden, no update needed return (None, None) # service not known to firewalld, yet (timeout, ..) return (None, None) def _remove_service(self, obj): if obj.name not in self._services: raise FirewallError(errors.INVALID_SERVICE, obj.name) if obj.path != config.ETC_FIREWALLD_SERVICES: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % \ (obj.path, config.ETC_FIREWALLD_SERVICES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._services[obj.name] def check_builtin_service(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_SERVICE, "'%s' is built-in service" % obj.name) def remove_service(self, obj): self.check_builtin_service(obj) self._remove_service(obj) def rename_service(self, obj, name): self.check_builtin_service(obj) new_service = self._copy_service(obj, name) self._remove_service(obj) return new_service def _copy_service(self, obj, name): return self.new_service(name, obj.export_config()) # zones def get_zones(self): return sorted(set(list(self._zones.keys()) + \ list(self._builtin_zones.keys()))) def add_zone(self, obj): if obj.builtin: self._builtin_zones[obj.name] = obj else: self._zones[obj.name] = obj def forget_zone(self, name): if name in self._builtin_zones: del self._builtin_zones[name] if name in self._zones: del self._zones[name] def get_zone(self, name): if name in self._zones: return self._zones[name] elif name in self._builtin_zones: return self._builtin_zones[name] raise FirewallError(errors.INVALID_ZONE, "get_zone(): %s" % name) def load_zone_defaults(self, obj): if obj.name not in self._zones: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._zones[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._zones[%s] != obj" % obj.name) elif obj.name not in self._builtin_zones: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in zone" % obj.name) self._remove_zone(obj) return self._builtin_zones[obj.name] def get_zone_config(self, obj): return obj.export_config() def set_zone_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.fw_config = self x.import_config(conf) x.path = config.ETC_FIREWALLD_ZONES x.builtin = False if obj.path != x.path: x.default = False self.add_zone(x) zone_writer(x) return x else: obj.fw_config = self obj.import_config(conf) zone_writer(obj) return obj def new_zone(self, name, conf): if name in self._zones or name in self._builtin_zones: raise FirewallError(errors.NAME_CONFLICT, "new_zone(): '%s'" % name) x = Zone() x.check_name(name) x.fw_config = self x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_ZONES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True zone_writer(x) self.add_zone(x) return x def update_zone_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path.startswith(config.ETC_FIREWALLD_ZONES): # removed custom zone for x in self._zones.keys(): obj = self._zones[x] if obj.filename == filename: del self._zones[x] if obj.name in self._builtin_zones: return ("update", self._builtin_zones[obj.name]) return ("remove", obj) else: # removed builtin zone for x in self._builtin_zones.keys(): obj = self._builtin_zones[x] if obj.filename == filename: del self._builtin_zones[x] if obj.name not in self._zones: # update dbus zone return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # zone not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading zone file '%s'", name) try: obj = zone_reader(filename, path) except Exception as msg: log.error("Failed to load zone file '%s': %s", filename, msg) return (None, None) obj.fw_config = self if path.startswith(config.ETC_FIREWALLD_ZONES) and \ len(path) > len(config.ETC_FIREWALLD_ZONES): # custom combined zone part obj.name = "%s/%s" % (os.path.basename(path), os.path.basename(filename)[0:-4]) # new zone if obj.name not in self._builtin_zones and obj.name not in self._zones: self.add_zone(obj) return ("new", obj) # updated zone if path.startswith(config.ETC_FIREWALLD_ZONES): # custom zone update if obj.name in self._zones: obj.default = self._zones[obj.name].default self._zones[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_zones: # builtin zone update del self._builtin_zones[obj.name] self._builtin_zones[obj.name] = obj if obj.name not in self._zones: # update dbus zone return ("update", obj) else: # builtin hidden, no update needed return (None, None) # zone not known to firewalld, yet (timeout, ..) return (None, None) def _remove_zone(self, obj): if obj.name not in self._zones: raise FirewallError(errors.INVALID_ZONE, obj.name) if not obj.path.startswith(config.ETC_FIREWALLD_ZONES): raise FirewallError(errors.INVALID_DIRECTORY, "'%s' doesn't start with '%s'" % \ (obj.path, config.ETC_FIREWALLD_ZONES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._zones[obj.name] def check_builtin_zone(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_ZONE, "'%s' is built-in zone" % obj.name) def remove_zone(self, obj): self.check_builtin_zone(obj) self._remove_zone(obj) def rename_zone(self, obj, name): self.check_builtin_zone(obj) new_zone = self._copy_zone(obj, name) self._remove_zone(obj) return new_zone def _copy_zone(self, obj, name): return self.new_zone(name, obj.export_config()) # helper def get_helpers(self): return sorted(set(list(self._helpers.keys()) + \ list(self._builtin_helpers.keys()))) def add_helper(self, obj): if obj.builtin: self._builtin_helpers[obj.name] = obj else: self._helpers[obj.name] = obj def get_helper(self, name): if name in self._helpers: return self._helpers[name] elif name in self._builtin_helpers: return self._builtin_helpers[name] raise FirewallError(errors.INVALID_HELPER, name) def load_helper_defaults(self, obj): if obj.name not in self._helpers: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._helpers[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._helpers[%s] != obj" % obj.name) elif obj.name not in self._builtin_helpers: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in helper" % obj.name) self._remove_helper(obj) return self._builtin_helpers[obj.name] def get_helper_config(self, obj): return obj.export_config() def set_helper_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_HELPERS x.builtin = False if obj.path != x.path: x.default = False self.add_helper(x) helper_writer(x) return x else: obj.import_config(conf) helper_writer(obj) return obj def new_helper(self, name, conf): if name in self._helpers or name in self._builtin_helpers: raise FirewallError(errors.NAME_CONFLICT, "new_helper(): '%s'" % name) x = Helper() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_HELPERS # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True helper_writer(x) self.add_helper(x) return x def update_helper_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_HELPERS: # removed custom helper for x in self._helpers.keys(): obj = self._helpers[x] if obj.filename == filename: del self._helpers[x] if obj.name in self._builtin_helpers: return ("update", self._builtin_helpers[obj.name]) return ("remove", obj) else: # removed builtin helper for x in self._builtin_helpers.keys(): obj = self._builtin_helpers[x] if obj.filename == filename: del self._builtin_helpers[x] if obj.name not in self._helpers: # update dbus helper return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # helper not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading helper file '%s'", name) try: obj = helper_reader(filename, path) except Exception as msg: log.error("Failed to load helper file '%s': %s", filename, msg) return (None, None) # new helper if obj.name not in self._builtin_helpers and obj.name not in self._helpers: self.add_helper(obj) return ("new", obj) # updated helper if path == config.ETC_FIREWALLD_HELPERS: # custom helper update if obj.name in self._helpers: obj.default = self._helpers[obj.name].default self._helpers[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_helpers: # builtin helper update del self._builtin_helpers[obj.name] self._builtin_helpers[obj.name] = obj if obj.name not in self._helpers: # update dbus helper return ("update", obj) else: # builtin hidden, no update needed return (None, None) # helper not known to firewalld, yet (timeout, ..) return (None, None) def _remove_helper(self, obj): if obj.name not in self._helpers: raise FirewallError(errors.INVALID_HELPER, obj.name) if obj.path != config.ETC_FIREWALLD_HELPERS: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % (obj.path, config.ETC_FIREWALLD_HELPERS)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._helpers[obj.name] def check_builtin_helper(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_HELPER, "'%s' is built-in helper" % obj.name) def remove_helper(self, obj): self.check_builtin_helper(obj) self._remove_helper(obj) def rename_helper(self, obj, name): self.check_builtin_helper(obj) new_helper = self._copy_helper(obj, name) self._remove_helper(obj) return new_helper def _copy_helper(self, obj, name): return self.new_helper(name, obj.export_config()) PK!`3fw_nm.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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 . # """Functions for NetworkManager interaction""" __all__ = [ "check_nm_imported", "nm_is_imported", "nm_get_zone_of_connection", "nm_set_zone_of_connection", "nm_get_connections", "nm_get_connection_of_interface", "nm_get_bus_name", "nm_get_dbus_interface" ] import gi from gi.repository import GLib try: gi.require_version('NM', '1.0') except ValueError: _nm_imported = False else: try: from gi.repository import NM _nm_imported = True except (ImportError, ValueError, GLib.Error): _nm_imported = False _nm_client = None from firewall import errors from firewall.errors import FirewallError from firewall.core.logger import log import dbus def check_nm_imported(): """Check function to raise a MISSING_IMPORT error if the import of NM failed """ if not _nm_imported: raise FirewallError(errors.MISSING_IMPORT, "gi.repository.NM = 1.0") def nm_is_imported(): """Returns true if NM has been properly imported @return True if import was successful, False otherwirse """ return _nm_imported def nm_get_client(): """Returns the NM client object or None if the import of NM failed @return NM.Client instance if import was successful, None otherwise """ global _nm_client if not _nm_client: _nm_client = NM.Client.new(None) return _nm_client def nm_get_zone_of_connection(connection): """Get zone of connection from NM @param connection name @return zone string setting of connection, empty string if not set, None if connection is unknown """ check_nm_imported() con = nm_get_client().get_connection_by_uuid(connection) if con is None: return None setting_con = con.get_setting_connection() if setting_con is None: return None try: if con.get_flags() & (NM.SettingsConnectionFlags.NM_GENERATED | NM.SettingsConnectionFlags.NM_VOLATILE): return "" except AttributeError: # Prior to NetworkManager 1.12, we can only guess # that a connection was generated/volatile. if con.get_unsaved(): return "" zone = setting_con.get_zone() if zone is None: zone = "" return zone def nm_set_zone_of_connection(zone, connection): """Set the zone for a connection @param zone name @param connection name @return True if zone was set, else False """ check_nm_imported() con = nm_get_client().get_connection_by_uuid(connection) if con is None: return False setting_con = con.get_setting_connection() if setting_con is None: return False if zone == "": zone = None setting_con.set_property("zone", zone) return con.commit_changes(True, None) def nm_get_connections(connections, connections_name): """Get active connections from NM @param connections return dict @param connections_name return dict """ connections.clear() connections_name.clear() check_nm_imported() active_connections = nm_get_client().get_active_connections() for active_con in active_connections: # ignore vpn devices for now if active_con.get_vpn(): continue name = active_con.get_id() uuid = active_con.get_uuid() devices = active_con.get_devices() connections_name[uuid] = name for dev in devices: connections[dev.get_iface()] = uuid def nm_get_interfaces(): """Get active interfaces from NM @returns list of interface names """ check_nm_imported() active_interfaces = [] for active_con in nm_get_client().get_active_connections(): # ignore vpn devices for now if active_con.get_vpn(): continue try: con = active_con.get_connection() if con.get_flags() & (NM.SettingsConnectionFlags.NM_GENERATED | NM.SettingsConnectionFlags.NM_VOLATILE): continue except AttributeError: # Prior to NetworkManager 1.12, we can only guess # that a connection was generated/volatile. if con.get_unsaved(): continue for dev in active_con.get_devices(): active_interfaces.append(dev.get_iface()) return active_interfaces def nm_get_interfaces_in_zone(zone): interfaces = [] for interface in nm_get_interfaces(): conn = nm_get_connection_of_interface(interface) if zone == nm_get_zone_of_connection(conn): interfaces.append(interface) return interfaces def nm_get_connection_of_interface(interface): """Get connection from NM that is using the interface @param interface name @returns connection that is using interface or None """ check_nm_imported() device = nm_get_client().get_device_by_iface(interface) if device is None: return None active_con = device.get_active_connection() if active_con is None: return None try: con = active_con.get_connection() if con.get_flags() & NM.SettingsConnectionFlags.NM_GENERATED: return None except AttributeError: # Prior to NetworkManager 1.12, we can only guess # that a connection was generated. if con.get_unsaved(): return None return active_con.get_uuid() def nm_get_bus_name(): if not _nm_imported: return None try: bus = dbus.SystemBus() obj = bus.get_object(NM.DBUS_INTERFACE, NM.DBUS_PATH) name = obj.bus_name del obj, bus return name except Exception: log.debug2("Failed to get bus name of NetworkManager") return None def nm_get_dbus_interface(): if not _nm_imported: return "" return NM.DBUS_INTERFACE PK!e&$$ ipset.pyonu[ c`c @sdZdddgZddlZddlmZddlmZddlm Z dd l m Z dd l m Z mZdd lmZd Zd ddddddddddg Zidd6dd6dd6dd6Zidd6d d6d!d6Zdefd"YZd#Zd$ZdS(%sThe ipset command wrappertipsettcheck_ipset_nametremove_default_create_optionsiN(terrors(t FirewallError(trunProg(tlog(ttempFiletreadfile(tCOMMANDSi shash:ips hash:ip,portshash:ip,port,ipshash:ip,port,nets hash:ip,markshash:nets hash:net,nets hash:net,portshash:net,port,netshash:net,ifaceshash:macs inet|inet6tfamilytvaluethashsizetmaxelems value in secsttimeouttinett1024t65536cBseZdZdZdZdZdZdZddZ dZ dZ d Z dd Z ddd Zd Zdd ZdddZdZdZdZdZRS(sipset command wrapper classcCstd|_d|_dS(NR(R t_commandtname(tself((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt__init__Js cCsg|D]}d|^q}tjd|j|jdj|t|j|\}}|dkrtd|jdj||fn|S(sCall ipset with argss%ss %s: %s %st is'%s %s' failed: %s(Rtdebug2t __class__RtjoinRt ValueError(Rtargstitemt_argststatustret((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt__runNs%  cCs/t|tkr+ttjd|ndS(sCheck ipset namesipset name '%s' is not validN(tlentIPSET_MAXNAMELENRRt INVALID_NAME(RR((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt check_nameYs cCsg}d}y|jdg}Wn$tk rH}tjd|nX|j}t}x{|D]s}|r|jjdd}|d|kr|dt kr|j |dqn|j drbt }qbqbW|S(s?Return types that are supported by the ipset command and kernelts--helpsipset error: %siisSupported set types:N( t _ipset__runRRtdebug1t splitlinestFalsetstriptsplittNonet IPSET_TYPEStappendt startswithtTrue(RRtoutputtextlinestin_typestlinetsplits((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pytset_supported_types_s     cCs;t|tks|tkr7ttjd|ndS(sCheck ipset types!ipset type name '%s' is not validN(R!R"R-RRt INVALID_TYPE(Rt type_name((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt check_typets cCs|j||j|d||g}t|trxF|jD]5\}}|j||dkrE|j|qEqEWn|j|S(s+Create an ipset with name, type and optionstcreateR%(R$R:t isinstancetdicttitemsR.R&(Rtset_nameR9toptionsRtkeytval((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_createzs    cCs |j||jd|gS(Ntdestroy(R$R&(RR?((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_destroys cCsd||g}|j|S(Ntadd(R&(RR?tentryR((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pytset_addscCsd||g}|j|S(Ntdel(R&(RR?RGR((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_deletescCs?d||g}|r2|jddj|n|j|S(Nttests%sR(R.RR&(RR?RGR@R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRKscCsKdg}|r|j|n|r5|j|n|j|jdS(Ntlists (R.textendR&R+(RR?R@R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pytset_lists  c Cs|jddg}i}d}}i}x|D]z}t|dkrPq2ng|jddD]}|j^qc}t|dkrq2q2|ddkr|d}q2|ddkr|d}q2|dd kr2|dj} d} xz| t| kro| | } | dkrbt| | krK| d7} | | || R.twriteRtclosetoststatRRRRRtst_sizeRtgetDebugLogLevelRt Exceptiontdebug3tendswithtunlinkR(RR?R9tentriestcreate_optionst entry_optionst temp_fileRRARBRGRfRRR[R5((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_restoresV              #  cCs,dg}|r|j|n|j|S(Ntflush(R.R&(RR?R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_flushs cCs|jd||gS(Ntrename(R&(Rt old_set_namet new_set_name((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRt scCs|jd||gS(Ntswap(R&(Rt set_name_1t set_name_2((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRwscCs|jdgS(Ntversion(R&(R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRzsN(t__name__t __module__t__doc__RR&R$R7R:R,RCRERHRJRKRNR]R^RqRsRtRwRz(((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRGs&         ' 7   cCst|tkrtStS(s"Return true if ipset name is valid(R!R"R)R0(R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRscCsK|j}x8tD]0}||krt|||kr||=qqW|S(s( Return only non default create options (tcopytIPSET_DEFAULT_CREATE_OPTIONS(R@RXR\((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRs    (R}t__all__tos.pathRetfirewallRtfirewall.errorsRtfirewall.core.progRtfirewall.core.loggerRtfirewall.functionsRRtfirewall.configR R"R-tIPSET_CREATE_OPTIONSRtobjectRRR(((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyts@     PK!㏷ fw_nm.pycnu[ c`c@sWdZddddddddgZd d lZd d lmZyejd d Wnek rmeZnAXyd dlm Z e ZWn#e eej fk reZnXd ad dlmZd dlmZd dlmZd d lZdZdZdZdZdZdZdZdZdZdZdZ d S(s(Functions for NetworkManager interactiontcheck_nm_importedtnm_is_importedtnm_get_zone_of_connectiontnm_set_zone_of_connectiontnm_get_connectionstnm_get_connection_of_interfacetnm_get_bus_nametnm_get_dbus_interfaceiN(tGLibtNMs1.0(R (terrors(t FirewallError(tlogcCststtjdndS(sNCheck function to raise a MISSING_IMPORT error if the import of NM failed sgi.repository.NM = 1.0N(t _nm_importedR R tMISSING_IMPORT(((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyR0scCstS(snReturns true if NM has been properly imported @return True if import was successful, False otherwirse (R (((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyR6scCststjjdantS(sReturns the NM client object or None if the import of NM failed @return NM.Client instance if import was successful, None otherwise N(t _nm_clientR tClienttnewtNone(((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyt nm_get_client<scCsttj|}|dkr)dS|j}|dkrEdSy(|jtjjtjj B@rldSWn!t k r|j rdSnX|j }|dkrd}n|S(sGet zone of connection from NM @param connection name @return zone string setting of connection, empty string if not set, None if connection is unknown tN( RRtget_connection_by_uuidRtget_setting_connectiont get_flagsR tSettingsConnectionFlagst NM_GENERATEDt NM_VOLATILEtAttributeErrort get_unsavedtget_zone(t connectiontcont setting_contzone((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyREs$        cCszttj|}|dkr)tS|j}|dkrEtS|dkrZd}n|jd||jtdS(sSet the zone for a connection @param zone name @param connection name @return True if zone was set, else False RR!N( RRRRtFalseRt set_propertytcommit_changestTrue(R!RRR ((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyRcs     cCs|j|jttj}xo|D]g}|jrIq1n|j}|j}|j}|||s>               PK!CIR%$%$ ebtables.pycnu[ c`c@sdgZddlZddlmZddlmZddlmZm Z m Z ddl m Z ddl mZddlmZmZddlZid gd 6d d d gd6dd dgd6ZiZiZiZxejD]Zgees0      PK!a  fw_icmptype.pynu[# -*- 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__ = [ "FirewallIcmpType" ] import copy from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class FirewallIcmpType(object): def __init__(self, fw): self._fw = fw self._icmptypes = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._icmptypes) def cleanup(self): self._icmptypes.clear() # zones def get_icmptypes(self): return sorted(self._icmptypes.keys()) def check_icmptype(self, icmptype): if icmptype not in self._icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, icmptype) def get_icmptype(self, icmptype): self.check_icmptype(icmptype) return self._icmptypes[icmptype] def add_icmptype(self, obj): orig_ipvs = obj.destination if len(orig_ipvs) == 0: orig_ipvs = [ "ipv4", "ipv6" ] ipvs = orig_ipvs[:] for ipv in orig_ipvs: if ipv == "ipv4": if not self._fw.ip4tables_enabled: continue supported_icmps = self._fw.ip4tables_supported_icmp_types elif ipv == "ipv6": if not self._fw.ip6tables_enabled: continue supported_icmps = self._fw.ip6tables_supported_icmp_types else: supported_icmps = [ ] if obj.name.lower() not in supported_icmps: log.info1("ICMP type '%s' is not supported by the kernel for %s." % (obj.name, ipv)) ipvs.remove(ipv) if len(ipvs) != len(orig_ipvs): if len(ipvs) < 1: raise FirewallError(errors.INVALID_ICMPTYPE, "No supported ICMP type.") new_obj = copy.deepcopy(obj) new_obj.destination = ipvs self._icmptypes[obj.name] = new_obj else: self._icmptypes[obj.name] = obj def remove_icmptype(self, icmptype): self.check_icmptype(icmptype) del self._icmptypes[icmptype] PK!Cnƒ$$ ebtables.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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__ = [ "ebtables" ] import os.path from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import tempFile, readfile, splitArgs from firewall.config import COMMANDS from firewall.core import ipXtables # some common stuff lives there from firewall.errors import FirewallError, INVALID_IPV import string BUILT_IN_CHAINS = { "broute": [ "BROUTING" ], "nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ], "filter": [ "INPUT", "OUTPUT", "FORWARD" ], } DEFAULT_RULES = { } LOG_RULES = { } OUR_CHAINS = {} # chains created by firewalld for table in BUILT_IN_CHAINS.keys(): DEFAULT_RULES[table] = [ ] OUR_CHAINS[table] = set() for chain in BUILT_IN_CHAINS[table]: DEFAULT_RULES[table].append("-N %s_direct" % chain) DEFAULT_RULES[table].append("-I %s 1 -j %s_direct" % (chain, chain)) DEFAULT_RULES[table].append("-I %s_direct 1 -j RETURN" % chain) OUR_CHAINS[table].add("%s_direct" % chain) class ebtables(object): ipv = "eb" name = "ebtables" zones_supported = False # ebtables only supported with direct interface def __init__(self): self._command = COMMANDS[self.ipv] self._restore_command = COMMANDS["%s-restore" % self.ipv] self.restore_noflush_option = self._detect_restore_noflush_option() self.concurrent_option = self._detect_concurrent_option() self.fill_exists() self.available_tables = [] def fill_exists(self): self.command_exists = os.path.exists(self._command) self.restore_command_exists = os.path.exists(self._restore_command) def _detect_concurrent_option(self): # Do not change any rules, just try to use the --concurrent option # with -L concurrent_option = "" ret = runProg(self._command, ["--concurrent", "-L"]) if ret[0] == 0: concurrent_option = "--concurrent" # concurrent for ebtables lock return concurrent_option def _detect_restore_noflush_option(self): # Do not change any rules, just try to use the restore command # with --noflush rules = [ ] try: self.set_rules(rules, "off") except ValueError: return False return True def __run(self, args): # convert to string list _args = [ ] if self.concurrent_option and self.concurrent_option not in args: _args.append(self.concurrent_option) _args += ["%s" % item for item in args] log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args)) (status, ret) = runProg(self._command, _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(args), ret)) return ret def _rule_validate(self, rule): for str in ["%%REJECT%%", "%%ICMP%%", "%%LOGTYPE%%"]: if str in rule: raise FirewallError(INVALID_IPV, "'%s' invalid for ebtables" % str) def is_chain_builtin(self, ipv, table, chain): return table in BUILT_IN_CHAINS and \ chain in BUILT_IN_CHAINS[table] def build_chain_rules(self, add, table, chain): rules = [] if add: rules.append([ "-t", table, "-N", chain ]) rules.append([ "-t", table, "-I", chain, "1", "-j", "RETURN" ]) else: rules.append([ "-t", table, "-X", chain ]) return rules def build_rule(self, add, table, chain, index, args): rule = [ "-t", table ] if add: rule += [ "-I", chain, str(index) ] else: rule += [ "-D", chain ] rule += args return rule def reverse_rule(self, args): return ipXtables.common_reverse_rule(args) def check_passthrough(self, args): ipXtables.common_check_passthrough(args) def reverse_passthrough(self, args): return ipXtables.common_reverse_passthrough(args) def set_rules(self, rules, log_denied): temp_file = tempFile() table = "filter" table_rules = { } for _rule in rules: rule = _rule[:] self._rule_validate(rule) # get table form rule for opt in [ "-t", "--table" ]: try: i = rule.index(opt) except ValueError: pass else: if len(rule) >= i+1: rule.pop(i) table = rule.pop(i) # we can not use joinArgs here, because it would use "'" instead # of '"' for the start and end of the string, this breaks # iptables-restore for i in range(len(rule)): for c in string.whitespace: if c in rule[i] and not (rule[i].startswith('"') and rule[i].endswith('"')): rule[i] = '"%s"' % rule[i] table_rules.setdefault(table, []).append(rule) for table in table_rules: temp_file.write("*%s\n" % table) for rule in table_rules[table]: temp_file.write(" ".join(rule) + "\n") temp_file.close() stat = os.stat(temp_file.name) log.debug2("%s: %s %s", self.__class__, self._restore_command, "%s: %d" % (temp_file.name, stat.st_size)) args = [ ] args.append("--noflush") (status, ret) = runProg(self._restore_command, args, stdin=temp_file.name) if log.getDebugLogLevel() > 2: lines = readfile(temp_file.name) if lines is not None: i = 1 for line in lines: log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0) if not line.endswith("\n"): log.debug3("", nofmt=1) i += 1 os.unlink(temp_file.name) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._restore_command, " ".join(args), ret)) return ret def set_rule(self, rule, log_denied): self._rule_validate(rule) return self.__run(rule) def get_available_tables(self, table=None): ret = [] tables = [ table ] if table else BUILT_IN_CHAINS.keys() for table in tables: if table in self.available_tables: ret.append(table) else: try: self.__run(["-t", table, "-L"]) self.available_tables.append(table) ret.append(table) except ValueError: log.debug1("ebtables table '%s' does not exist." % table) return ret def get_zone_table_chains(self, table): return {} def build_flush_rules(self): rules = [] for table in BUILT_IN_CHAINS.keys(): if table not in self.get_available_tables(): continue # Flush firewall rules: -F # Delete firewall chains: -X # Set counter to zero: -Z for flag in [ "-F", "-X", "-Z" ]: rules.append(["-t", table, flag]) return rules def build_set_policy_rules(self, policy): rules = [] for table in BUILT_IN_CHAINS.keys(): if table not in self.get_available_tables(): continue for chain in BUILT_IN_CHAINS[table]: rules.append(["-t", table, "-P", chain, policy]) return rules def build_default_tables(self): # nothing to do, they always exist return [] def build_default_rules(self, log_denied="off"): default_rules = [] for table in DEFAULT_RULES: if table not in self.get_available_tables(): continue _default_rules = DEFAULT_RULES[table][:] if log_denied != "off" and table in LOG_RULES: _default_rules.extend(LOG_RULES[table]) prefix = [ "-t", table ] for rule in _default_rules: if type(rule) == list: default_rules.append(prefix + rule) else: default_rules.append(prefix + splitArgs(rule)) return default_rules def is_ipv_supported(self, ipv): return ipv == self.ipv PK![Domm logger.pycnu[ c`c@sddddgZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z de fdYZ de fdYZ d e fd YZd e fd YZde fd YZde fdYZeZdS(t LogTargettFileLogtLoggertlogiNcBs5eZdZdZddZdZdZRS(s% Abstract class for logging targets. cCs d|_dS(N(tNonetfd(tself((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt__init__(sicCstddS(Ns%LogTarget.write is an abstract method(tNotImplementedError(Rtdatatleveltloggertis_debug((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytwrite+scCstddS(Ns%LogTarget.flush is an abstract method(R(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytflush.scCstddS(Ns%LogTarget.close is an abstract method(R(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytclose1s(t__name__t __module__t__doc__RR RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR&s    t _StdoutLogcBs/eZdZddZdZdZRS(cCstj|tj|_dS(N(RRtsyststdoutR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR8s icCs|jj||jdS(N(RR R(RR R R R ((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR <scCs|jdS(N(R(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRAscCs|jjdS(N(RR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRDs(RRRR RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR7s   t _StderrLogcBseZdZRS(cCstj|tj|_dS(N(RRRtstderrR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRKs (RRR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRJst _SyslogLogcBs/eZdZddZdZdZRS(cCs=tj|tjtjjtjdtj tj dS(Ni( RRtsyslogtopenlogtostpathtbasenameRtargvtLOG_PIDt LOG_DAEMON(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRSs icCsd}|rtj}nl||jkr3tj}nQ||jkrNtj}n6||jkritj}n||j krtj }n|j dr|t |d }nt |dkr|dkrtj|qtj||ndS(Ns ii( RRt LOG_DEBUGtINFO1tLOG_INFOtWARNINGt LOG_WARNINGtERRORtLOG_ERRtFATALtLOG_CRITtendswithtlen(RR R R R tpriority((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR as"      cCstjdS(N(Rtcloselog(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRwscCsdS(N((R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRzs(RRRR RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRRs   cBsAeZdZddZdZddZdZdZRS(s< FileLog class. File will be opened on the first write. twcCs#tj|||_||_dS(N(RRtfilenametmode(RR/R0((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs  cCs|jr dStjtjB}|jjdr?|tjO}ntj|j|d|_tj |jdtj |j|j|_t j |jt j t j dS(Ntai(RRtO_CREATtO_WRONLYR0t startswithtO_APPENDtopenR/tfchmodtfdopentfcntltF_SETFDt FD_CLOEXEC(Rtflags((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR6s icCs7|js|jn|jj||jjdS(N(RR6R R(RR R R R ((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR s  cCs'|js dS|jjd|_dS(N(RRR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs  cCs|js dS|jjdS(N(RR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs (RRRRR6R RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs    cBseZdZdZdZdZdZdZdZe Z e Z e Zddd Zd Zd d Zd d Zd dZd dZdZdZdZdZdZdZed2dZed2dZed2dZed2dZed2dZ ed2dZ!dZ"dZ#dZ$dZ%d Z&d!Z'd"Z(d#Z)d$Z*d%Z+d&Z,dd'Z-d(Z.dd)Z/ed2dd*Z0ed2dd+Z1ed2dd,Z2dd-Z3d.Z4d/Z5d0Z6dd1Z7RS(3sL Format string: %(class)s Calling class the function belongs to, else empty %(date)s Date using Logger.date_format, see time module %(domain)s Full Domain: %(module)s.%(class)s.%(function)s %(file)s Filename of the module %(function)s Function name, empty in __main__ %(label)s Label according to log function call from Logger.label %(level)d Internal logging level %(line)d Line number in module %(module)s Module name %(message)s Log message Standard levels: FATAL Fatal error messages ERROR Error messages WARNING Warning messages INFOx, x in [1..5] Information DEBUGy, y in [1..10] Debug messages NO_INFO No info output NO_DEBUG No debug output INFO_MAX Maximum info level DEBUG_MAX Maximum debug level x and y depend on info_max and debug_max from Logger class initialization. See __init__ function. Default logging targets: stdout Logs to stdout stderr Logs to stderr syslog Logs to syslog Additional arguments for logging functions (fatal, error, warning, info and debug): nl Disable newline at the end with nl=0, default is nl=1. fmt Format string for this logging entry, overloads global format string. Example: fmt="%(file)s:%(line)d %(message)s" nofmt Only output message with nofmt=1. The nofmt argument wins over the fmt argument. Example: from logger import log log.setInfoLogLevel(log.INFO1) log.setDebugLogLevel(log.DEBUG1) for i in range(1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: " "%(level)d %(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.addDebugLogging("*", fl) log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug3("debug3") log.debug2("debug2") log.debug1("debug1") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error\n", nl=0) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) iiiiiiii cCsi|_i|_d|_d|_i|_i|_i|_i|_i|_i|_ |dkryt d|n|dkrt d|n|j |_ ||_ d|_||_|j|jd|j|jd|j|jd|j|j dxbtd|j dD]J}t|d |||j|dt|d |d ||q"Wxftd|jdD]N}t|d |||j|d |t|d|d||qW|j|j|j|j|jd|jd|jd|j|j|j|j g|jd|jgt|j|j dD] }|^qd|jd|jgtd|jdD] }|^qdS(s Logger class initialization tisLogger: info_max %d is too lowisLogger: debug_max %d is too lows FATAL ERROR: sERROR: s WARNING: sINFO%dsinfo%dcsfdS(Ncsj|||S(N(tinfo(tmessagetargstkwargs(Rtx(s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt s((RRB((RRBs8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRCssDEBUG%ds DEBUG%d: sdebug%dcsfdS(Ncsj|||S(N(tdebug(R?R@RA(RRB(s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRC)s((RRB((RRBs8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRC(ss%(label)s%(message)ss%d %b %Y %H:%M:%St*N( t_levelt _debug_levelt_formatt _date_formatt_labelt _debug_labelt_loggingt_debug_loggingt_domainst_debug_domainst ValueErrorR$tNO_INFOtINFO_MAXtNO_DEBUGt DEBUG_MAXtsetInfoLogLabelR(t TRACEBACKR&trangetsetattrtsetDebugLogLabeltsetInfoLogLevelR"tsetDebugLogLevelt setFormatt setDateFormattsetInfoLoggingRRtsetDebugLogging(Rtinfo_maxt debug_maxRFti((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRsX                     -cCshxat|j|jdD]F}||jkr5qnx(|j|D]\}}}|jqCWqWdS(s Close all logging targets iN(RWR(RTRLR(RR tdummyttarget((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR8s  REcCs.|j|||jkr'|j|S|jS(s Get info log level. (t _checkDomainRFtNOTHING(Rtdomain((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytgetInfoLogLevel@s  cCsT|j|||jkr(|j}n||jkrC|j}n||j|s  cOsM|j|ddd|j|j|d|d<|j||||dS(s Debug log using debug level [1..debug_max]. There are additional debugx functions according to debug_max from __init__RliRmR N(RoRTR}R~(RR RHR@RA((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRDs  cCs)|j|jtjdgdidS(NR@RA(R~RVt tracebackt format_exc(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt exceptionscCs8||ks||kr4td|||fndS(Ns*Level %d out of range, should be [%d..%d].(RP(RR RlRm((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRoscCsD|s dSx3|jD]%}|dkrtd|qqWdS(NtnlRstnofmts0Key '%s' is not allowed as argument for logging.(snlsfmtsnofmt(tkeysRP(RRAtkey((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR}s  cCs*| s|dkr&td|ndS(NR=sDomain '%s' is not valid.(RP(RRg((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRescCs||jkrt|ts-t|tr6|}n |g}x|D]J}|rq|j|ddd|jqF|j|d|jd|jqFWnY|rgt|j |jD] }|^q}n(gt|j|jD] }|^q}|S(s Generate log level array. RliRm( tALLt isinstancetlistttupleRoRTR(RRRWtDEBUG1(RR R RqRb((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRns    +(cCspt|tst|tr'|}n |g}x9|D]1}t|jts7td|jjq7q7W|S(s Generate target array. s '%s' is no valid logging target.(RRRt issubclasst __class__RRPR(RRdttargetst_target((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt _getTargetss   cCs|r.|j}|j}d|jdf}n(|j}|j}|j|jdf}t|dkru|jnxwt |d|dD]^}||krqnxC||D]7\}}}||kr|j |gj |qqWqWdS(s% Generate dict with domain by level. iiN( RORMRTRNRLR(RRR+tclearRWt setdefaulttappend(RR RNRLt_rangeR RgRc((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt _genDomainss       c Cs|j||j||}|j|}|r@|j}n |j}x5|D]-}x$|D]}|||fg|||SqqWx-|jD]"}|j||}|rL|SqLWdS(s@ Internal function to get calling class. Returns class or None. N( RtvaluesRRRRt __bases__RR(RRRRtbaset_obj((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs cOsd}d|kr|d}nd}d|kr>|d}nd}d|kr]|d}n|j||}|sydSt|dkr|||dRDRRoR}ReRnRRRrRtRwRzRRR~R(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRsdG   ;                      4(t__all__RRRRRRRR9tos.pathRtobjectRRRRRRR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyts(          -( 4PK!8^^rich.pycnu[ c`c@sdddddddddd d d d d ddddgZddlmZddlmZddlmZddlmZddlm Z de fdYZ de fdYZ de fdYZ de fdYZdefdYZde fdYZde fdYZde fdYZde fd YZd e fd!YZd e fd"YZd e fd#YZd e fd$YZd e fd%YZdefd&YZde fd'YZde fd(YZde fd)YZd*S(+t Rich_SourcetRich_Destinationt Rich_Servicet Rich_Portt Rich_ProtocoltRich_MasqueradetRich_IcmpBlockt Rich_IcmpTypetRich_SourcePorttRich_ForwardPorttRich_Logt Rich_Auditt Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_Markt Rich_Limitt Rich_Rulei(t functions(tcheck_ipset_name(t REJECT_TYPES(terrors(t FirewallErrorcBseZedZdZRS(cCs||_|jdkr$d|_n||_|jdksK|jdkrWd|_n$|jdk r{|jj|_n||_|jdkrd|_n||_|jdkr|jdkr|jdkrttjdndS(Ntsno address, mac and ipset( taddrtNonetmactuppertipsettinvertRRt INVALID_RULE(tselfRRRR((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyt__init__$s       - cCsd|jrdnd}|jdk r7|d|jS|jdk rU|d|jS|jdk rs|d|jSttjddS(Ns source%s s NOTRs address="%s"smac="%s"s ipset="%s"sno address, mac and ipset(RRRRRRRR(Rtret((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyt__str__5s (t__name__t __module__tFalseR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR#s cBseZedZdZRS(cCs||_||_dS(N(RR(RRR((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR Bs cCs d|jrdnd|jfS(Nsdestination %saddress="%s"snot R(RR(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Fs(R#R$R%R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRAs cBseZdZdZRS(cCs ||_dS(N(tname(RR&((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR KscCs d|jS(Nsservice name="%s"(R&(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Ns(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRJs cBseZdZdZRS(cCs||_||_dS(N(tporttprotocol(RR'R(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR Rs cCsd|j|jfS(Nsport port="%s" protocol="%s"(R'R((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Vs(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRQs cBseZdZRS(cCsd|j|jfS(Ns#source-port port="%s" protocol="%s"(R'R((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Zs (R#R$R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRYscBseZdZdZRS(cCs ||_dS(N(tvalue(RR)((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR _scCs d|jS(Nsprotocol value="%s"(R)(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"bs(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR^s cBseZdZdZRS(cCsdS(N((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR fscCsdS(Nt masquerade((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"is(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRes cBseZdZdZRS(cCs ||_dS(N(R&(RR&((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR mscCs d|jS(Nsicmp-block name="%s"(R&(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"ps(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRls cBseZdZdZRS(cCs ||_dS(N(R&(RR&((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR tscCs d|jS(Nsicmp-type name="%s"(R&(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"ws(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRss cBseZdZdZRS(cCs^||_||_||_||_|jdkr?d|_n|jdkrZd|_ndS(NR(R'R(tto_portt to_addressR(RR'R(R+R,((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR {s     cCsRd|j|j|jdkr+d|jnd|jdkrJd|jndfS(Ns(forward-port port="%s" protocol="%s"%s%sRs to-port="%s"s to-addr="%s"(R'R(R+R,(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s (R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR zs cBs#eZddddZdZRS(cCs||_||_||_dS(N(tprefixtleveltlimit(RR-R.R/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s  cCsSd|jrd|jnd|jr2d|jnd|jrKd|jndfS(Ns log%s%s%ss prefix="%s"Rs level="%s"s %s(R-R.R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"sN(R#R$RR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR scBseZddZdZRS(cCs ||_dS(N(R/(RR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR scCsd|jrd|jndS(Nsaudit%ss %sR(R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"sN(R#R$RR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cBseZddZdZRS(cCs ||_dS(N(R/(RR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR scCsd|jrd|jndS(Nsaccept%ss %sR(R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"sN(R#R$RR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cBs)eZdddZdZdZRS(cCs||_||_dS(N(ttypeR/(Rt_typeR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cCs:d|jrd|jnd|jr2d|jndfS(Ns reject%s%ss type="%s"Rs %s(R0R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"scCs|jr{|s$ttjdn|dkr{|jt|kr{djt|}ttjd|j|fq{ndS(Ns9When using reject type you must specify also rule family.tipv4tipv6s, s%Wrong reject type %s. Use one of: %s.(R2R3(R0RRRRtjoin(Rtfamilyt valid_types((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pytchecks  N(R#R$RR R"R7(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cBseZdZRS(cCsd|jrd|jndS(Nsdrop%ss %sR(R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s(R#R$R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRscBs&eZddZdZdZRS(cCs||_||_dS(N(tsetR/(Rt_setR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cCs'd|j|jrd|jndfS(Ns mark set=%s%ss %sR(R8R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s cCs|jdk r|j}nttjdd|kr|jd}t|dkrottj|ntj|d stj|d rttj|qn$tj|sttj|ndS(Ns no value sett/iii( R8RRRt INVALID_MARKtsplittlenRt checkUINT32(Rtxtsplits((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR7s  N(R#R$RR R"R7(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRs  cBs,eZdZdZdZdZRS(cCsu||_d|jkrq|jjd}t|dkrq|dd krqd|d |dd f|_qqndS( NR:iitsecondtminutethourtdays%s/%si(RARBRCRD(R)R<R=(RR)R@((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s  cCsd}d|jkr*|jjd}n| sCt|dkr[ttj|jn|\}}yt|}Wnttj|jnX|dks|dkrttj|jnd}|dkrd}n?|dkrd}n*|dkr d}n|dkr d}nd ||d krPttjd |jn|dkr|dkrttjd |jndS(NR:iitstmthtdi<ii'is %s too fasts %s too slow(RERFRGRHiiiQ(RR)R<R=RRt INVALID_LIMITtint(RR@tratetdurationtmult((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR7s6           cCs d|jS(Nslimit value="%s"(R)(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"scCsdS(NR((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pytcommand s(R#R$R R7R"RN(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRs  " cBs;eZdddZdZdZdZdZRS(cCsw|dk rt||_n d|_d|_d|_d|_d|_d|_d|_|rs|j |ndS(N( RtstrR5tsourcet destinationtelementtlogtaudittactiont_import_from_string(RR5trule_str((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s        cCsg}xtj|D]}d|kr|jd}t|dks_|d s_|d rxttjd|n|ji|dd6|dd6q|ji|d6qW|jid d6|S( s Lexical analysis t=iiisinternal error in _lexer(): %st attr_namet attr_valueRRtEOL(Rt splitArgsR<R=RRRtappend(RRWttokenstrtattr((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyt_lexers ( &c Cs |sttjdnd|_d|_d|_d|_d|_d|_ d|_ |j |}|r|dj ddkrttjdni}g}d}x ||j ddko|dgks ||j d}||j d}||j d}|rA|d?kr|ttjd|q|n;|d@krf|dkrw|jrwttjd)q||dkr|jrttjd*q||dAkr|jrttjd+||jfq||d kr|jrttjd,q||d!kr,|j r,ttjd-q||dBkr||j r|ttjd.||j fq|nttjd/|t |dkr|t |d0nd1} | d1kr<| r|r|dkrttjd2q9ttjd3||fq d|kr,ttjd4||fq |jdnx| dkr|dkr|dCkryttjd7|n||_q |r|dkrd8} nd9||f} ttj| q |j|n| dkrs|dDkr|||n|d0}qW|j$dS(LNs empty ruleiRRR[truleRYRZR5taddressRRRR)R'R(sto-portsto-addrR&R-R.R0R8sbad attribute '%s'RPRQtservices icmp-blocks icmp-typeR*s forward-ports source-portRSRTtaccepttdroptrejecttmarkR/tnottNOTsmore than one 'source' elements#more than one 'destination' elementsFmore than one element. There cannot be both '%s' and '%s' in one rule.smore than one 'log' elementsmore than one 'audit' elementsOmore than one 'action' element. There cannot be both '%s' and '%s' in one rule.sunknown element %siRs0'family' outside of rule. Use 'rule family=...'.s:'%s' outside of any element. Use 'rule %s= ...'.s,'%s' outside of rule. Use 'rule ... %s ...'.R2R3sH'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead.sdwrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'.sDattribute '%s' outside of any element. Use 'rule %s= ...'.sinvalid 'protocol' elementsinvalid 'service' elementsinvalid 'icmp-block' elementsinvalid 'icmp-type' elementsinvalid 'limit' element(sfamilyRcsmacsipsetsinvertsvaluesportsprotocolsto-portsto-addrsnamesprefixslevelstypesset(Rbssources destinationsprotocolRdsports icmp-blocks icmp-types masquerades forward-ports source-portslogsauditReRfRgsmarkslimitRiRjsEOL(sprotocolRdsports icmp-blocks icmp-types masquerades forward-ports source-port(ReRfRgsmark(sipv4sipv6(Rcsmacsipsetsinvert(RiRj(Rcsinvert(RiRj(sportsprotocol(sportsprotocolsto-portsto-addr(sportsprotocol(sprefixslevel(%RRRRR5RPRQRRRSRTRURatgetR=R]tTrueRR%tpoptclearRRRRRRRR RR R R RR RRR7( RRWR^tattrst in_elementstindexRRRYRZt in_elementterr_msg((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRV.st       +  "%,               ?        $            $                 <      $       0                      $             cCs |jdk r6|jdkr6ttj|jn|jdkr|jdk rf|jjdk su|jdk rttjnt |j t krttjqn|j dkr|j dkrttj dn|jdkr|jdkrttj dqnt |j tt tgkr}|jdkr}|jdkr}|j dkr}ttj dq}n|jdk r|jjdk rL|jdkrttjn|jjdk rttj dn|jjdk r ttj dntj|j|jjsttjt|jjqq|jjdk r|jjdk rttj dntj|jjsttjt|jjqq|jjdk rt|jjsttjt|jjqqttj d n|jdk r|jdkrKttjn|jjdksytj|j|jj rttjt|jjqnt |j tkr|j jdkst|j jd kr>ttjt|j jq>n>t |j t krutj!|j j"sEttj#|j j"n|j j$dkr>ttj%|j j$q>nt |j t&krtj'|j j(s>ttj%|j j(q>nt |j tkr/|j dk rttj dn|jdk r>|jjdk r>ttj dq>nt |j tkr|j jdksnt|j jd krttj)t|j jn|j r>ttj dq>nt |j t*kr|j jdkst|j jd kr>ttj)t|j jq>n+t |j t krtj!|j j"sXttj#|j j"n|j j$dkrttj%|j j$n|j j+dkr|j j,dkrttj#|j j+n|j j+dkrtj!|j j+ rttj#|j j+n|j j,dkrPtj-|j|j j, rPttj|j j,n|jdkrqttjn|j dk r>ttj dq>nt |j t.kr tj!|j j"sttj#|j j"n|j j$d kr>ttj%|j j$q>n1|j dk r>ttj dt |j n|jdk r|jj/r|jj/d!krttj0|jj/n|jj1dk r|jj1j2qn|jdk r! t |j t3t4t5gkrttj6t |j n|jj1dk r! |jj1j2q! n|j dk r t |j t4kr[ |j j2|jn%t |j t7kr |j j2n|j j1dk r |j j1j2q ndS("NR2R3sno element, no actions%no element, no source, no destinationsno action, no log, no auditsaddress and macsaddress and ipsets mac and ipsetsinvalid sourceittcptudptsctptdccpsmasquerade and actionsmasquerade and mac sourcesicmp-block and actionRsforward-port and actionsUnknown element %stemergtalerttcritterrortwarningtnoticetinfotdebug(sipv4sipv6(RtRuRvRw(RtRuRvRw(RtRuRvRw(RxRyRzserrorR|R}sinfosdebug(8R5RRRtINVALID_FAMILYRPRRQtMISSING_FAMILYR0RRR RURRRRSRTRRRt check_addresst INVALID_ADDRROt check_mact INVALID_MACRt INVALID_IPSETRR&R=tINVALID_SERVICERt check_portR't INVALID_PORTR(tINVALID_PROTOCOLRt checkProtocolR)tINVALID_ICMPTYPERR+R,tcheck_single_addressRR.tINVALID_LOG_LEVELR/R7R R RtINVALID_AUDIT_TYPER(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR7 s! $$$ $*$!*! *$$     cCsd}|jr#|d|j7}n|jr@|d|j7}n|jr]|d|j7}n|jrz|d|j7}n|jr|d|j7}n|jr|d|j7}n|jr|d|j7}ntjrtj |S|S(NRbs family="%s"s %s( R5RPRQRRRSRTRURtPY2tu2b(RR!((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s        N(R#R$RR RaRVR7R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s   N(t__all__tfirewallRtfirewall.core.ipsetRtfirewall.core.baseRRtfirewall.errorsRtobjectRRRRRRRRRR R R R R RRRR(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyts8       1PK!Ɵ8C$$ helper.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 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 . # """The helper maxnamelen""" HELPER_MAXNAMELEN = 32 PK!*<< fw_zone.pyonu[ c`c@s$ddlZddlmZmZmZddlmZddlmZm Z m Z m Z m Z m Z mZmZmZddlmZmZmZmZmZmZmZmZmZmZmZddlmZmZddl m!Z!ddl"m#Z#dd l$m%Z%d e&fd YZ'dS( iN(t SHORTCUTStDEFAULT_ZONE_TARGETtZONE_SOURCE_IPSET_TYPES(tlog( tportStrt checkIPnMaskt checkIP6nMaskt checkProtocoltenable_ip_forwardingtcheck_single_addresst check_mactportInPortRangetget_nf_conntrack_short_name( t Rich_Rulet Rich_Acceptt Rich_Markt Rich_Servicet Rich_Portt Rich_ProtocoltRich_MasqueradetRich_ForwardPorttRich_SourcePorttRich_IcmpBlockt Rich_IcmpType(tFirewallTransactiontFirewallZoneTransaction(terrors(t FirewallError(tLastUpdatedOrderedDictt FirewallZonecBsxeZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z dd Zd ZdZddZdZddZdZdZddZddZddZdZdZdZdZdZdddZdZ ddZ!ddZ"dd Z#d!Z$d"Z%d#Z&d$Z'd%Z(ddd&Z)d'Z*dd(Z+dd)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1ddd2Z4d3Z5dd4Z6dd5Z7d6Z8d7Z9d8Z:d9Z;d1ddd:Z<d;Z=dd<Z>d=Z?d>Z@d?ZAd@ZBdAZCdBZDd1dddCZEdDZFddEZGdFZHdGZIdHZJdIZKdJZLd1dddKZMdLZNddMZOdNZPdOZQdPZRdQZSd1dddRZTdSZUddTZVdUZWdVZXdWZYdXZZd1dddYZ[dZZ\dd[Z]d\Z^d]Z_ddd^Z`ddd_Zaddd1ddd`ZbdaZcddddbZddcZeddddZfdeZgdfZhdgZid1dddhZjdiZkddjZldkZmdlZndmZodnZpdddoZqdpZrdqZsddrZtdsZudtZvduZwexdvZydwZzdxZ{dyZ|dzZ}d{Z~d|Zd}Zd~ZdZdZdZdZddddZdZdZRS(cCs||_i|_i|_dS(N(t_fwt_chainst_zones(tselftfw((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__init__(s  cCsd|j|j|jfS(Ns %s(%r, %r)(t __class__RR (R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__repr__-scCs|jj|jjdS(N(RtclearR (R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytcleanup0s cCs t|jS(N(RR(R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytnew_transaction6scCst|j|S(N(RR(R!tzone((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytnew_zone_transaction9scCst|jjS(N(tsortedR tkeys(R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt get_zones>scCsE|j|}x/|jD]$}||j|jdkr|SqWdS(Nt interfaces(t_FirewallZone__interface_idR tsettingstNone(R!t interfacet interface_idR)((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_zone_of_interfaceAs cCsE|j|}x/|jD]$}||j|jdkr|SqWdS(Ntsources(t_FirewallZone__source_idR R0R1(R!tsourcet source_idR)((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_zone_of_sourceIs cCs|jj|}|j|S(N(Rt check_zoneR (R!R)tz((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_zoneQscOsQy||||Wn6tk rL}t|}tjd||fnXdS(Ns%s: %s(RtstrRtwarning(R!tftnametargstkwargsterrortmsg((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt_error2warningUs  c CsHddddddddd d d d g D|_||j|j^s R.R5tservicestportst masqueradet forward_portst source_portst icmp_blockstrulest protocolsticmp_block_inversion(R0R R@(R!tobj((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytadd_zone]scCsA|j|}|jr&|j|n|jj|j|=dS(N(R tappliedtunapply_zone_settingsR0R&(R!R)RQ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt remove_zonehs    c Cs|dkr|j}n|}x|jD]}|j|}|j|}|jrx|j|j|jd|nt |j dkst |j dkrt |_ ntjd|jx0|jD]%}|j|j|j|d|qWx0|jD]%}|j|j|jd||qWx0|jD]%}|j|j|j|d|q1Wx0|jD]%}|j|j|jd||qdWx0|jD]%}|j|j|j|d|qWx0|jD]%}|j|j|jd||qW|jr|j|j|jd|nx0|jD]%}|j|j|j|d|q%Wx0|j D]%}|j|j |j|d|qXWx0|j D]%}|j|j!|j|d|qW|j r.|j|j"t |j|q.q.W|dkr|j#t ndS(Ntuse_zone_transactionisApplying zone '%s'($R1R(R-R tzone_transactionRPREtadd_icmp_block_inversionR@tlenR.R5tTrueRSRtdebug1RMtadd_icmp_blockRKtadd_forward_portRHt add_serviceRItadd_portROt add_protocolRLtadd_source_portRJtadd_masqueradeRNtadd_rulet add_interfacet add_sourcet_icmp_block_inversiontexecute(R!tuse_transactiont transactionR)RQRWRA((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt apply_zonesos^    *           cCs|j|}||_dS(N(R RS(R!R)RSRQ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytset_zone_applieds cCsd|krdS|jd}t|dkr5dSd}x+tD]#}|dt|krB|}qBqBW|dk r|d|jkrdSt|dkst|dkr|dd kr|d|fSndS( Nt_iiiiRtdenytallow(slogRmRn(R1tsplitRYRR-(R!tchaintsplitst_chainRG((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytzone_from_chains     "c Cs|dkr|j|}|dk r|\}}|dkrN|j}n|}|j|t||fg||dkr|jtqqndS(Ntipv4tipv6(RtRu(RsR1R(tgen_chain_rulesRZRg( R!tipvttableRpRhRGt_zoneRrRi((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytcreate_zone_base_by_chains     cCsx|D]\}}|rD|jj|ij|gj|q|j||j|t|j||dkr|j||=nt|j|dkr|j|=qqWdS(Ni(Rt setdefaulttappendtremoveRY(R!R)tcreatetchainsRxRp((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt_register_chainss+cCs8itjd6|d6|d6}|r4||dRR=(R!R)R0t_objtkeyRARD((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt set_settingss@             (c Cs.|jj|}|j|}|r.|js?| rC|j rCdS|rUt|_n|dkrs|j|}n|}|j|}xd|D]\}xS||D]G} y|dkr|j||| |n|dkrwn|dkr |j d| d} |j |||d| | n|dkrE|j ||| |nx|dkru|j ||| d| d |nH|d kr|j ||| |n#|d kr|j||| d| d |n|d kr|j|||n|d krRd|j d | kr'|j d | d} nd} |j||td| | |nk|dkrw|j||| |nF|dkr|j||| d| d |ntjd||| Wqtk r} tjt| qXqWqW|r|jt|j|n|dkr*|j|ndS(NRMRPRKRtmark_idRHRIiiRORLRJRNRR.R5s3Zone '%s': Unknown setting '%s:%s', unable to apply(RR:R RSRZR1R*Rt _icmp_blockR0t _forward_portt_servicet_portt _protocolt _source_portt _masqueradet_FirewallZone__ruleR t _interfacet_sourceRR>RR=RfR@Rg( R!tenableR)RVRyRQRWR0RRARRD((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__zone_settings sj                        cCs|jt||dS(N(t_FirewallZone__zone_settingsRZ(R!R)RV((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytapply_zone_settings_scCs|jt||dS(N(RtFalse(R!R)RV((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRTbscCsK|j|}t|jdkrGt|jdkrG|j|ndS(Ni(R RYR.R5RT(R!R)RQ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytunapply_zone_settings_if_unusedes *cCst|j|j}|dtkr8d|d|S|dk r]|j||n|j|||}|S(N(RRR4R:R1tremove_interfaceRd(R!R)R2Rt _old_zonet _new_zoneRy((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs   cCs|jj|dkr(|j}n|}|j|}|j|||jt|d|dt|dk r|dkr|j|}|jt|d|dtn|dkr|j tndS(Nt+R|R( RRR1R(RWRRRZRRg(R!told_zonetnew_zoneRhRiRW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytchange_default_zones   c Cs|jj|j|}|dkrAttjd|n|dkrS|n|jj|}||krttjd|||fn|dkr|j |}n|}|j |}|j |}|j t ||||j|j|||dkr|jtn|S(Ns'%s' is not in any zoneRs"remove_interface(%s, %s): zoi='%s'(RRR4R1RRtUNKNOWN_INTERFACER:RR*R R/RRtadd_postRRgRZ( R!R)R2RVtzoiRyRWRR3((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs*   $     cCs(||jdkr$|jd|=ndS(NR.(R0(R!RR3((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__unregister_interfacescCs |j||j|dkS(NR.(R/R(R!R)R2((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytquery_interfacescCs|j|djS(NR.(RR,(R!R)((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR scCst|rdSt|r dSt|r0dS|jdrr|j|d|j|d|j|dSttj |dS(NRtRuRsipset:i( RRR t startswitht_check_ipset_type_for_sourcet_check_ipset_appliedt _ipset_familyRRt INVALID_ADDR(R!R7((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt check_sources   cCs|j|}||fS(N(R(R!R7Rw((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt __source_idsc Cs||jj|jj|}|j|}t|rG|j}n|j|}||jdkrtt j d||fn|j |dk rtt j d|n|dkr|j|}n|}|js|j|d||j|j|tn|jt||d|d||j|||||j|j|||dkrx|jtn|S(NR5s'%s' already bound to '%s's'%s' already bound to a zoneRVii(RRR:R R tupperR6R0RRRR9R1RR*RSRRRkRRRZt_FirewallZone__register_sourcet _FirewallZone__unregister_sourceRg( R!R)R7RRVRyRR8RW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRe s4        ! cCsC|jd||jd|<| p-|dk|jd|d|St|rY|j}n|dk rx|j||n|j|||}|S(N( RRR9R:R RR1t remove_sourceRe(R!R)R7RRRRy((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRLs    c CsE|jjt|r(|j}n|j|}|dkr\ttjd|n|dkrn|n|jj |}||krttj d|||fn|dkr|j |}n|}|j |}|j |}|jt||d|d||j|j|||dkrA|jtn|S(Ns'%s' is not in any zoneRsremove_source(%s, %s): zos='%s'ii(RRR RR9R1RRtUNKNOWN_SOURCER:RR*R R6RRRRRgRZ( R!R)R7RVtzosRyRWRR8((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR^s.    $    ! cCs(||jdkr$|jd|=ndS(NR5(R0(R!RR8((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__unregister_sourcescCs;t|r|j}n|j||j|dkS(NR5(R RR6R(R!R)R7((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt query_sources cCs.g|j|djD]}|d^qS(NR5i(RR,(R!R)tk((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRscCs|jdS(N(tcheck(R!trule((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt check_rulescCs|j|t|S(N(RR=(R!R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt __rule_ids cCs|s dS|jr<t|jr&dSt|jrdSndt|drX|jrXdSt|dr|jr|j|j|j|j|j |jSdS(NRtRutmacRtipset( R1taddrRRthasattrRRRRR(R!R7((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt_rule_source_ipvs cCs|j|||||dS(N(t _rule_prepare(R!RR)RRRW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__rulesic CsE|jj|}|jj||jj|j|}|j|}||jdkr}ttj d||fn|dkr|j |} n|} t |j tkr|jj} nd} |jr|jt||| | n|j||| ||| j|j||| |dkrA| jtn|S(NRNs'%s' already in '%s'(RR:t check_timeoutRR t_FirewallZone__rule_idR0RRtALREADY_ENABLEDR1R*ttypetelementRtnew_markRSRRZt_FirewallZone__register_ruleRt_FirewallZone__unregister_ruleRg( R!R)RRRRVRyRtrule_idRWR((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRcs*      cCs'|j||d||jd|(R!tmodulesRt_helpersRRt_module_short_namet_helper((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_helpers_for_service_modulesGs$    cCs$|jj||jj|dS(N(Rt check_portt check_tcpudp(R!tporttprotocol((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR ascCs#|j||t|d|fS(Nt-(R R(R!R R ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt __port_idesc Cs|jj|}|jj||jj|j|}|j||} | |jdkrttj d|||fn|dkr|j |} n|} |j r|j t|||| n|j|| ||| j|j|| |dkr| jtn|S(NRIs'%s:%s' already in '%s'(RR:RRR t_FirewallZone__port_idR0RRRR1R*RSRRZt_FirewallZone__register_portRt_FirewallZone__unregister_portRg( R!R)R R RRRVRyRtport_idRW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR_is&       cCs!|j|||jd||j|}|tkr:ttjd||fndS(Ns.ipset '%s' with type '%s' not usable as source(t_FirewallZone__ipset_typeRRRt INVALID_IPSET(R!R@t_type((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs  c Csx|r|jj|gn |jjD]}|js@q+nxr|jD]d}x[|j|D]J}|r|j||n|j|||||} |j|| qcWqMWq+WdS(N( Rtget_backend_by_ipvRVRWRXR\R]tbuild_zone_source_address_rulesRZ( R!RR)RwR7RWR[RxRpRN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs1  cCs |jdk r|jg}n1gddgD]}|jj|r+|^q+}|j|j}|dk r|dkr|jdk r|j|krttjd||jfqq|g}n||_ x t g|D]} |jj | ^qD] } t |j tkr|jjj|j j} g} t| jdkr|jrlttjdnxS|D];}|| jkrs| j|rs| j| j|qsqsWn | jdx| D]} |r |jdd|jjdkr |jd d q nt |jtkr|j| j|}g}x6|D].}|j}t|}|jjdkr.|jd d }|j||jdkr| j|j rqDnt|jd kr|j|qrx|jD]@\}}| j ||||| |j|}|j!| |qWqD|j|krD|j|j|jjd d }|j|qDqDW|j"|nxs| jD]h\}}|rt |jt#kr|jdd n| j$||||| |}|j!| |qWxj| j%D]_}|r:t |jt#kr:|jdd n| j&|||| |}|j!| |qWxs| j'D]h\}}|rt |jt#kr|jdd n| j(||||| |}|j!| |qsWqWqt |j t)kr|j j*}|j j+}|j,|||r<|jddn|rjt |jt#krj|jdd n| j$||||d|}|j!| |qt |j t-kr>|j j.}|j/||r|jddn|rt |jt#kr|jdd n| j&|||d|}|j!| |qt |j t0kr|r|jd d|jddx3|D](}| j|r|j1t2|qqWn| j3|||}|j!| |qt |j t4kr|j j*}|j j+}|j j5}|j j6}xX|D]P}| j|rT|j7|||||n|r#|r#|j1t2|q#q#W|sdnd}|r|jdd |jd d |jd|n| j8||||||||| }|j!| |qt |j t9kr|j j*}|j j+}|j,|||rR|jddn|rt |jt#kr|jdd n| j(||||d|}|j!| |qt |j t:kst |j t;kr |jj<j=|j j}t |j t:kr> |jr> t |jtkr> ttjdn|jr xv|D]k}||jkrN | j| rN ttjdt |j t:kr dnd|j j| jfqN qN Wnd}|r |j|d|j|dn| j>||||}|j!| |q|j dkr |rB |jddn|rp t |jt#krp |jdd n| j?|||}|j!| |qttjdt |j qW|S(NRtRuRs;Source address family '%s' conflicts with rule family '%s'.is"Destination conflict with service.tfiltertINPUTtrawt PREROUTINGt conntracktnatitmanglet POSTROUTINGt FORWARD_OUTt FORWARD_INs'IcmpBlock not usable with accept actionsIcmp%s %s not usable with %stBlocktTypesUnknown element %s(@tfamilyR1Rtis_ipv_enabledRR7RRt INVALID_RULEtipvstsetRkRRRRt get_serviceR@RYt destinationtis_ipv_supportedR|R]RtactionRR RRR treplaceRItbuild_zone_helper_ports_rulesRZt add_modulesRtbuild_zone_ports_rulesROtbuild_zone_protocol_rulesRLtbuild_zone_source_ports_rulesRR R R RtvalueRRRRtbuild_zone_masquerade_rulesRtto_portt to_addressR6tbuild_zone_forward_port_rulesRRRticmptypet get_icmptypetbuild_zone_icmp_block_rulest(build_zone_rich_source_destination_rules(R!RR)RRRWR|Rwt source_ipvRGR[tsvct destinationsRthelpersRRRRt nat_moduleR tprotoRNR R4R5t filter_chaintictRx((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRsH1   2            "                   # c CsJ|jjj|}|j|j|}|r|jjdkrU|jddnVg}x@|D]8}|j|j|jj dd} |j| qbW|j ||jddng} xdd gD]} |jj | sqn|jj | } t |jdkrE| |jkrm| j| |j| fqmq| df| kr| j| dfqqWx| D]\} } |jjdkr|x|D]}|j}t|}|jj dd} |j| |jd kr| j|j rqnt |jd kr'|j|qxK|jD]@\}}| j||||| |j|}|j| |q1WqWnxB|jD]7\}}| j||||| }|j| |qWx9|jD].}| j|||| }|j| |qWxB|jD]7\}}| j||||| }|j| |qWqxWdS( NiRoRpRqRrRmRnRtRuRi(RRR~R RRR]R|RRRRzRkRYRR1R t add_moduleRyRRIRR@RZRRORRLR(R!RR)RRWRRRRRt backends_ipvRwR[RRRR RRNR ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRsd       "  cCsn|r|jddnxN|jjD]=}|js>q)n|j||||}|j||q)WdS(NRmRn(R]RRVRWRRZ(R!RR)R R RWR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR3s  cCsk|r|jddnxK|jjD]:}|js>q)n|j|||}|j||q)WdS(NRmRn(R]RRVRWRRZ(R!RR)R RWR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR?s cCsn|r|jddnxN|jjD]=}|js>q)n|j||||}|j||q)WdS(NRmRn(R]RRVRWRRZ(R!RR)R R RWR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRJs cCsw|r)|jdd|jddnd}|jt||jj|}|j||}|j||dS(NRrRtRmRuRt(R]RRRRkRRZ(R!RR)RWRwR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRUsc Cstd|rd} nd} |s*dnd} |ri|jdd|jdd|jd| n|r|r|jt| n|jj| } | j||| |||||} |j| | dS( NRuRtRnRvRsRpRrRm(R R]RRRRkRRZ( R!RR)RWR R R4R5RRwRR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRas   c Cs|jjj|}|r>|jdd|jddnx|jjD]}|jscqNnt}|jrxBddgD]1}||jkr|j|st }PqqqWn|rqNn|j |||} |j || qNWdS(NRmRnRvRtRu( RRRR]RVRWRRRRZRRZ( R!RR)RARWRR[t skip_backendRwRN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRws$  cCs|j|j}|dkr dS|j| r@|dkr@dS|jdd|jdd|r|j||jnxH|jjD]7}|jsqn|j ||}|j ||qWdS( NtDROPs %%REJECT%%tREJECTtACCEPTRmRnRv(Rs %%REJECT%%R( R ttargetRR]RgR&RRVRWt%build_zone_icmp_block_inversion_rulesRZ(R!RR)RWRR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRfs    N(t__name__t __module__R#R%R'R(R*R-R4R9R<RERRRUR1RjRkRsRzRRRRRRRTRRRRR/RdRRRRRRRRR6ReRRRRRRRRRRRcRRRRRRRR^RRRRRR R RR_RRRRRRRR`RR RR"RR$RaR%R(R&R*RR,RbR-R1R.RR6R8R]R9R=R:R?RRBRDR\RERIRFRKRRMRXRNRORTRSRRvRRRRhRfRRRRRRRRRRRRf(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR's$            <      ) ?       '         &                                                                   (   (           A  ((Rtfirewall.core.baseRRRtfirewall.core.loggerRtfirewall.functionsRRRRRR R R R tfirewall.core.richR RRRRRRRRRRtfirewall.core.fw_transactionRRtfirewallRtfirewall.errorsRtfirewall.fw_typesRtobjectR(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyts @LPK!ө= __init__.pycnu[ c`c@sdS(N((((s:/usr/lib/python2.7/site-packages/firewall/core/__init__.pytsPK!'^ icmp.pycnu[ c`c@sddddgZi"dd6dd6dd6d d 6d d 6d d6dd6dd6dd6dd6dd6dd6dd6dd6dd 6d!d"6d#d$6d%d&6d'd(6d)d*6d+d,6d-d.6d/d06d/d16d2d36d4d56d6d76d8d96d:d;6d<d=6d>d?6d@dA6dBdC6dDdE6ZidFdG6dHd 6dIdJ6dKd6dLdM6dd76d d96d%dN6dOdP6dQdR6dSd06dSd16dTd6dTd6dUd56dVd36dWdX6dWdY6dZd[6dZd\6d]d^6Zd_Zd`ZdaZdbZdcS(dt ICMP_TYPESt ICMPV6_TYPEStcheck_icmp_typetcheck_icmpv6_types0/0s echo-replytpongs3/0snetwork-unreachables3/1shost-unreachables3/2sprotocol-unreachables3/3sport-unreachables3/4sfragmentation-neededs3/5ssource-route-faileds3/6snetwork-unknowns3/7s host-unknowns3/9snetwork-prohibiteds3/10shost-prohibiteds3/11sTOS-network-unreachables3/12sTOS-host-unreachables3/13scommunication-prohibiteds3/14shost-precedence-violations3/15sprecedence-cutoffs4/0s source-quenchs5/0snetwork-redirects5/1s host-redirects5/2sTOS-network-redirects5/3sTOS-host-redirects8/0s echo-requesttpings9/0srouter-advertisements10/0srouter-solicitations11/0sttl-zero-during-transits11/1sttl-zero-during-reassemblys12/0s ip-header-bads12/1srequired-option-missings13/0stimestamp-requests14/0stimestamp-replys17/0saddress-mask-requests18/0saddress-mask-replys1/0sno-routes1/1s1/3saddress-unreachables1/4s2/0spacket-too-bigs bad-headers4/1sunknown-header-types4/2sunknown-options128/0s129/0s133/0s134/0s135/0sneighbour-solicitationsneigbour-solicitations136/0sneighbour-advertisementsneigbour-advertisements137/0tredirectcCs|tkrtStS(N(RtTruetFalse(t_name((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pytcheck_icmp_nameVs cCs|tjkrtStS(N(RtvaluesRR(t_type((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pyR[scCs|tkrtStS(N(RRR(R ((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pytcheck_icmpv6_name`s cCs|tjkrtStS(N(RR RR(R ((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pyResN(t__all__RRR RR R(((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pyts|      PK!*<< fw_zone.pycnu[ c`c@s$ddlZddlmZmZmZddlmZddlmZm Z m Z m Z m Z m Z mZmZmZddlmZmZmZmZmZmZmZmZmZmZmZddlmZmZddl m!Z!ddl"m#Z#dd l$m%Z%d e&fd YZ'dS( iN(t SHORTCUTStDEFAULT_ZONE_TARGETtZONE_SOURCE_IPSET_TYPES(tlog( tportStrt checkIPnMaskt checkIP6nMaskt checkProtocoltenable_ip_forwardingtcheck_single_addresst check_mactportInPortRangetget_nf_conntrack_short_name( t Rich_Rulet Rich_Acceptt Rich_Markt Rich_Servicet Rich_Portt Rich_ProtocoltRich_MasqueradetRich_ForwardPorttRich_SourcePorttRich_IcmpBlockt Rich_IcmpType(tFirewallTransactiontFirewallZoneTransaction(terrors(t FirewallError(tLastUpdatedOrderedDictt FirewallZonecBsxeZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z dd Zd ZdZddZdZddZdZdZddZddZddZdZdZdZdZdZdddZdZ ddZ!ddZ"dd Z#d!Z$d"Z%d#Z&d$Z'd%Z(ddd&Z)d'Z*dd(Z+dd)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1ddd2Z4d3Z5dd4Z6dd5Z7d6Z8d7Z9d8Z:d9Z;d1ddd:Z<d;Z=dd<Z>d=Z?d>Z@d?ZAd@ZBdAZCdBZDd1dddCZEdDZFddEZGdFZHdGZIdHZJdIZKdJZLd1dddKZMdLZNddMZOdNZPdOZQdPZRdQZSd1dddRZTdSZUddTZVdUZWdVZXdWZYdXZZd1dddYZ[dZZ\dd[Z]d\Z^d]Z_ddd^Z`ddd_Zaddd1ddd`ZbdaZcddddbZddcZeddddZfdeZgdfZhdgZid1dddhZjdiZkddjZldkZmdlZndmZodnZpdddoZqdpZrdqZsddrZtdsZudtZvduZwexdvZydwZzdxZ{dyZ|dzZ}d{Z~d|Zd}Zd~ZdZdZdZdZddddZdZdZRS(cCs||_i|_i|_dS(N(t_fwt_chainst_zones(tselftfw((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__init__(s  cCsd|j|j|jfS(Ns %s(%r, %r)(t __class__RR (R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__repr__-scCs|jj|jjdS(N(RtclearR (R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytcleanup0s cCs t|jS(N(RR(R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytnew_transaction6scCst|j|S(N(RR(R!tzone((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytnew_zone_transaction9scCst|jjS(N(tsortedR tkeys(R!((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt get_zones>scCsE|j|}x/|jD]$}||j|jdkr|SqWdS(Nt interfaces(t_FirewallZone__interface_idR tsettingstNone(R!t interfacet interface_idR)((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_zone_of_interfaceAs cCsE|j|}x/|jD]$}||j|jdkr|SqWdS(Ntsources(t_FirewallZone__source_idR R0R1(R!tsourcet source_idR)((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_zone_of_sourceIs cCs|jj|}|j|S(N(Rt check_zoneR (R!R)tz((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_zoneQscOsQy||||Wn6tk rL}t|}tjd||fnXdS(Ns%s: %s(RtstrRtwarning(R!tftnametargstkwargsterrortmsg((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt_error2warningUs  c CsHddddddddd d d d g D|_||j|j^s R.R5tservicestportst masqueradet forward_portst source_portst icmp_blockstrulest protocolsticmp_block_inversion(R0R R@(R!tobj((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytadd_zone]scCsA|j|}|jr&|j|n|jj|j|=dS(N(R tappliedtunapply_zone_settingsR0R&(R!R)RQ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt remove_zonehs    c Cs|dkr|j}n|}x|jD]}|j|}|j|}|jrx|j|j|jd|nt |j dkst |j dkrt |_ ntjd|jx0|jD]%}|j|j|j|d|qWx0|jD]%}|j|j|jd||qWx0|jD]%}|j|j|j|d|q1Wx0|jD]%}|j|j|jd||qdWx0|jD]%}|j|j|j|d|qWx0|jD]%}|j|j|jd||qW|jr|j|j|jd|nx0|jD]%}|j|j|j|d|q%Wx0|j D]%}|j|j |j|d|qXWx0|j D]%}|j|j!|j|d|qW|j r.|j|j"t |j|q.q.W|dkr|j#t ndS(Ntuse_zone_transactionisApplying zone '%s'($R1R(R-R tzone_transactionRPREtadd_icmp_block_inversionR@tlenR.R5tTrueRSRtdebug1RMtadd_icmp_blockRKtadd_forward_portRHt add_serviceRItadd_portROt add_protocolRLtadd_source_portRJtadd_masqueradeRNtadd_rulet add_interfacet add_sourcet_icmp_block_inversiontexecute(R!tuse_transactiont transactionR)RQRWRA((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt apply_zonesos^    *           cCs|j|}||_dS(N(R RS(R!R)RSRQ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytset_zone_applieds cCsd|krdS|jd}t|dkr5dSd}x+tD]#}|dt|krB|}qBqBW|dk r|d|jkrdSt|dkst|dkr|dd kr|d|fSndS( Nt_iiiiRtdenytallow(slogRmRn(R1tsplitRYRR-(R!tchaintsplitst_chainRG((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytzone_from_chains     "c Cs|dkr|j|}|dk r|\}}|dkrN|j}n|}|j|t||fg||dkr|jtqqndS(Ntipv4tipv6(RtRu(RsR1R(tgen_chain_rulesRZRg( R!tipvttableRpRhRGt_zoneRrRi((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytcreate_zone_base_by_chains     cCsx|D]\}}|rD|jj|ij|gj|q|j||j|t|j||dkr|j||=nt|j|dkr|j|=qqWdS(Ni(Rt setdefaulttappendtremoveRY(R!R)tcreatetchainsRxRp((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt_register_chainss+cCs8itjd6|d6|d6}|r4||dRR=(R!R)R0t_objtkeyRARD((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt set_settingss@             (c Cs.|jj|}|j|}|r.|js?| rC|j rCdS|rUt|_n|dkrs|j|}n|}|j|}xd|D]\}xS||D]G} y|dkr|j||| |n|dkrwn|dkr |j d| d} |j |||d| | n|dkrE|j ||| |nx|dkru|j ||| d| d |nH|d kr|j ||| |n#|d kr|j||| d| d |n|d kr|j|||n|d krRd|j d | kr'|j d | d} nd} |j||td| | |nk|dkrw|j||| |nF|dkr|j||| d| d |ntjd||| Wqtk r} tjt| qXqWqW|r|jt|j|n|dkr*|j|ndS(NRMRPRKRtmark_idRHRIiiRORLRJRNRR.R5s3Zone '%s': Unknown setting '%s:%s', unable to apply(RR:R RSRZR1R*Rt _icmp_blockR0t _forward_portt_servicet_portt _protocolt _source_portt _masqueradet_FirewallZone__ruleR t _interfacet_sourceRR>RR=RfR@Rg( R!tenableR)RVRyRQRWR0RRARRD((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__zone_settings sj                        cCs|jt||dS(N(t_FirewallZone__zone_settingsRZ(R!R)RV((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytapply_zone_settings_scCs|jt||dS(N(RtFalse(R!R)RV((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRTbscCsK|j|}t|jdkrGt|jdkrG|j|ndS(Ni(R RYR.R5RT(R!R)RQ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytunapply_zone_settings_if_unusedes *cCst|j|j}|dtkr8d|d|S|dk r]|j||n|j|||}|S(N(RRR4R:R1tremove_interfaceRd(R!R)R2Rt _old_zonet _new_zoneRy((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs   cCs|jj|dkr(|j}n|}|j|}|j|||jt|d|dt|dk r|dkr|j|}|jt|d|dtn|dkr|j tndS(Nt+R|R( RRR1R(RWRRRZRRg(R!told_zonetnew_zoneRhRiRW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytchange_default_zones   c Cs|jj|j|}|dkrAttjd|n|dkrS|n|jj|}||krttjd|||fn|dkr|j |}n|}|j |}|j |}|j t ||||j|j|||dkr|jtn|S(Ns'%s' is not in any zoneRs"remove_interface(%s, %s): zoi='%s'(RRR4R1RRtUNKNOWN_INTERFACER:RR*R R/RRtadd_postRRgRZ( R!R)R2RVtzoiRyRWRR3((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs*   $     cCs(||jdkr$|jd|=ndS(NR.(R0(R!RR3((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__unregister_interfacescCs |j||j|dkS(NR.(R/R(R!R)R2((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytquery_interfacescCs|j|djS(NR.(RR,(R!R)((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR scCst|rdSt|r dSt|r0dS|jdrr|j|d|j|d|j|dSttj |dS(NRtRuRsipset:i( RRR t startswitht_check_ipset_type_for_sourcet_check_ipset_appliedt _ipset_familyRRt INVALID_ADDR(R!R7((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt check_sources   cCs|j|}||fS(N(R(R!R7Rw((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt __source_idsc Cs||jj|jj|}|j|}t|rG|j}n|j|}||jdkrtt j d||fn|j |dk rtt j d|n|dkr|j|}n|}|js|j|d||j|j|tn|jt||d|d||j|||||j|j|||dkrx|jtn|S(NR5s'%s' already bound to '%s's'%s' already bound to a zoneRVii(RRR:R R tupperR6R0RRRR9R1RR*RSRRRkRRRZt_FirewallZone__register_sourcet _FirewallZone__unregister_sourceRg( R!R)R7RRVRyRR8RW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRe s4        ! cCsC|jd||jd|<| p-|dk|jd|d|St|rY|j}n|dk rx|j||n|j|||}|S(N( RRR9R:R RR1t remove_sourceRe(R!R)R7RRRRy((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRLs    c CsE|jjt|r(|j}n|j|}|dkr\ttjd|n|dkrn|n|jj |}||krttj d|||fn|dkr|j |}n|}|j |}|j |}|jt||d|d||j|j|||dkrA|jtn|S(Ns'%s' is not in any zoneRsremove_source(%s, %s): zos='%s'ii(RRR RR9R1RRtUNKNOWN_SOURCER:RR*R R6RRRRRgRZ( R!R)R7RVtzosRyRWRR8((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR^s.    $    ! cCs(||jdkr$|jd|=ndS(NR5(R0(R!RR8((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__unregister_sourcescCs;t|r|j}n|j||j|dkS(NR5(R RR6R(R!R)R7((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt query_sources cCs.g|j|djD]}|d^qS(NR5i(RR,(R!R)tk((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRscCs|jdS(N(tcheck(R!trule((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt check_rulescCs|j|t|S(N(RR=(R!R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt __rule_ids cCs|s dS|jr<t|jr&dSt|jrdSndt|drX|jrXdSt|dr|jr|j|j|j|j|j |jSdS(NRtRutmacRtipset( R1taddrRRthasattrRRRRR(R!R7((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt_rule_source_ipvs cCs|j|||||dS(N(t _rule_prepare(R!RR)RRRW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt__rulesic CsE|jj|}|jj||jj|j|}|j|}||jdkr}ttj d||fn|dkr|j |} n|} t |j tkr|jj} nd} |jr|jt||| | n|j||| ||| j|j||| |dkrA| jtn|S(NRNs'%s' already in '%s'(RR:t check_timeoutRR t_FirewallZone__rule_idR0RRtALREADY_ENABLEDR1R*ttypetelementRtnew_markRSRRZt_FirewallZone__register_ruleRt_FirewallZone__unregister_ruleRg( R!R)RRRRVRyRtrule_idRWR((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRcs*      cCs'|j||d||jd|(R!tmodulesRt_helpersRRt_module_short_namet_helper((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pytget_helpers_for_service_modulesGs$    cCs$|jj||jj|dS(N(Rt check_portt check_tcpudp(R!tporttprotocol((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR ascCs#|j||t|d|fS(Nt-(R R(R!R R ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyt __port_idesc Cs|jj|}|jj||jj|j|}|j||} | |jdkrttj d|||fn|dkr|j |} n|} |j r|j t|||| n|j|| ||| j|j|| |dkr| jtn|S(NRIs'%s:%s' already in '%s'(RR:RRR t_FirewallZone__port_idR0RRRR1R*RSRRZt_FirewallZone__register_portRt_FirewallZone__unregister_portRg( R!R)R R RRRVRyRtport_idRW((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR_is&       cCs!|j|||jd||j|}|tkr:ttjd||fndS(Ns.ipset '%s' with type '%s' not usable as source(t_FirewallZone__ipset_typeRRRt INVALID_IPSET(R!R@t_type((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs  c Csx|r|jj|gn |jjD]}|js@q+nxr|jD]d}x[|j|D]J}|r|j||n|j|||||} |j|| qcWqMWq+WdS(N( Rtget_backend_by_ipvRVRWRXR\R]tbuild_zone_source_address_rulesRZ( R!RR)RwR7RWR[RxRpRN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRs1  cCs |jdk r|jg}n1gddgD]}|jj|r+|^q+}|j|j}|dk r|dkr|jdk r|j|krttjd||jfqq|g}n||_ x t g|D]} |jj | ^qD] } t |j tkr|jjj|j j} g} t| jdkr|jrlttjdnxS|D];}|| jkrs| j|rs| j| j|qsqsWn | jdx| D]} |r |jdd|jjdkr |jd d q nt |jtkr|j| j|}g}x6|D].}|j}t|}|jjdkr.|jd d }|j||jdkr| j|j rqDnt|jd kr|j|qrx|jD]@\}}| j ||||| |j|}|j!| |qWqD|j|krD|j|j|jjd d }|j|qDqDW|j"|nxs| jD]h\}}|rt |jt#kr|jdd n| j$||||| |}|j!| |qWxj| j%D]_}|r:t |jt#kr:|jdd n| j&|||| |}|j!| |qWxs| j'D]h\}}|rt |jt#kr|jdd n| j(||||| |}|j!| |qsWqWqt |j t)kr|j j*}|j j+}|j,|||r<|jddn|rjt |jt#krj|jdd n| j$||||d|}|j!| |qt |j t-kr>|j j.}|j/||r|jddn|rt |jt#kr|jdd n| j&|||d|}|j!| |qt |j t0kr|r|jd d|jddx3|D](}| j|r|j1t2|qqWn| j3|||}|j!| |qt |j t4kr|j j*}|j j+}|j j5}|j j6}xX|D]P}| j|rT|j7|||||n|r#|r#|j1t2|q#q#W|sdnd}|r|jdd |jd d |jd|n| j8||||||||| }|j!| |qt |j t9kr|j j*}|j j+}|j,|||rR|jddn|rt |jt#kr|jdd n| j(||||d|}|j!| |qt |j t:kst |j t;kr |jj<j=|j j}t |j t:kr> |jr> t |jtkr> ttjdn|jr xv|D]k}||jkrN | j| rN ttjdt |j t:kr dnd|j j| jfqN qN Wnd}|r |j|d|j|dn| j>||||}|j!| |q|j dkr |rB |jddn|rp t |jt#krp |jdd n| j?|||}|j!| |qttjdt |j qW|S(NRtRuRs;Source address family '%s' conflicts with rule family '%s'.is"Destination conflict with service.tfiltertINPUTtrawt PREROUTINGt conntracktnatitmanglet POSTROUTINGt FORWARD_OUTt FORWARD_INs'IcmpBlock not usable with accept actionsIcmp%s %s not usable with %stBlocktTypesUnknown element %s(@tfamilyR1Rtis_ipv_enabledRR7RRt INVALID_RULEtipvstsetRkRRRRt get_serviceR@RYt destinationtis_ipv_supportedR|R]RtactionRR RRR treplaceRItbuild_zone_helper_ports_rulesRZt add_modulesRtbuild_zone_ports_rulesROtbuild_zone_protocol_rulesRLtbuild_zone_source_ports_rulesRR R R RtvalueRRRRtbuild_zone_masquerade_rulesRtto_portt to_addressR6tbuild_zone_forward_port_rulesRRRticmptypet get_icmptypetbuild_zone_icmp_block_rulest(build_zone_rich_source_destination_rules(R!RR)RRRWR|Rwt source_ipvRGR[tsvct destinationsRthelpersRRRRt nat_moduleR tprotoRNR R4R5t filter_chaintictRx((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRsH1   2            "                   # c CsJ|jjj|}|j|j|}|r|jjdkrU|jddnVg}x@|D]8}|j|j|jj dd} |j| qbW|j ||jddng} xdd gD]} |jj | sqn|jj | } t |jdkrE| |jkrm| j| |j| fqmq| df| kr| j| dfqqWx| D]\} } |jjdkr|x|D]}|j}t|}|jj dd} |j| |jd kr| j|j rqnt |jd kr'|j|qxK|jD]@\}}| j||||| |j|}|j| |q1WqWnxB|jD]7\}}| j||||| }|j| |qWx9|jD].}| j|||| }|j| |qWxB|jD]7\}}| j||||| }|j| |qWqxWdS( NiRoRpRqRrRmRnRtRuRi(RRR~R RRR]R|RRRRzRkRYRR1R t add_moduleRyRRIRR@RZRRORRLR(R!RR)RRWRRRRRt backends_ipvRwR[RRRR RRNR ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRsd       "  cCsn|r|jddnxN|jjD]=}|js>q)n|j||||}|j||q)WdS(NRmRn(R]RRVRWRRZ(R!RR)R R RWR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR3s  cCsk|r|jddnxK|jjD]:}|js>q)n|j|||}|j||q)WdS(NRmRn(R]RRVRWRRZ(R!RR)R RWR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR?s cCsn|r|jddnxN|jjD]=}|js>q)n|j||||}|j||q)WdS(NRmRn(R]RRVRWRRZ(R!RR)R R RWR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRJs cCsw|r)|jdd|jddnd}|jt||jj|}|j||}|j||dS(NRrRtRmRuRt(R]RRRRkRRZ(R!RR)RWRwR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRUsc Cstd|rd} nd} |s*dnd} |ri|jdd|jdd|jd| n|r|r|jt| n|jj| } | j||| |||||} |j| | dS( NRuRtRnRvRsRpRrRm(R R]RRRRkRRZ( R!RR)RWR R R4R5RRwRR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRas   c Cs|jjj|}|r>|jdd|jddnx|jjD]}|jscqNnt}|jrxBddgD]1}||jkr|j|st }PqqqWn|rqNn|j |||} |j || qNWdS(NRmRnRvRtRu( RRRR]RVRWRRRRZRRZ( R!RR)RARWRR[t skip_backendRwRN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRws$  cCs|j|j}|dkr dS|j| r@|dkr@dS|jdd|jdd|r|j||jnxH|jjD]7}|jsqn|j ||}|j ||qWdS( NtDROPs %%REJECT%%tREJECTtACCEPTRmRnRv(Rs %%REJECT%%R( R ttargetRR]RgR&RRVRWt%build_zone_icmp_block_inversion_rulesRZ(R!RR)RWRR[RN((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyRfs    N(t__name__t __module__R#R%R'R(R*R-R4R9R<RERRRUR1RjRkRsRzRRRRRRRTRRRRR/RdRRRRRRRRR6ReRRRRRRRRRRRcRRRRRRRR^RRRRRR R RR_RRRRRRRR`RR RR"RR$RaR%R(R&R*RR,RbR-R1R.RR6R8R]R9R=R:R?RRBRDR\RERIRFRKRRMRXRNRORTRSRRvRRRRhRfRRRRRRRRRRRRf(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyR's$            <      ) ?       '         &                                                                   (   (           A  ((Rtfirewall.core.baseRRRtfirewall.core.loggerRtfirewall.functionsRRRRRR R R R tfirewall.core.richR RRRRRRRRRRtfirewall.core.fw_transactionRRtfirewallRtfirewall.errorsRtfirewall.fw_typesRtobjectR(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_zone.pyts @LPK!Ы99 nftables.pyonu[ c`c@s~ddlZddlZddlmZmZddlmZddlm Z ddl m Z m Z m Z mZmZddlmZddlmZmZmZmZmZmZddlmZmZmZmZd Zd Ziid d efd 6d6id defd 6d6id defd 6ddefd6d6iddefd6ddefd6d6Z iid6id6id6Z!ii"dd d!dd"d#gd$6dd d!gd!6dd d%gd%6dd d&gd&6dd d!dd"d'gd(6dd d!dd"d)gd*6dd d!dd"d+gd,6dd d-dd"d.gd/6dd d!dd"d0gd16dd d!dd"d.gd26dd d3dd"d.gd46dd d!dd"d5gd66dd d-dd"d7gd86dd d!dd"d9gd:6dd d!dd"d7gd;6dd d3gd36dd d!dd"d<gd=6dd d!dd"d>gd?6dd d!dd"d@gdA6dd d-gd-6dd d3dd"d.gdB6dd dCgdC6dd dDgdD6dd dEgdE6dd d!dd"dFgdG6dd dHgdH6dd dIgdI6dd dJgdJ6dd d-dd"d<gdK6dd d!dd"dLgdM6dd d-dd"d@gdN6dd d!dd"dOgdP6dd dHdd"d.gdQ6dd dHdd"d7gdR6dS6idTd d!dTd"d<gdU6dTd d3dTd"d7gdV6dTd d!dTd"d@gdW6dTd d!dTd"d.gd$6dTd d!gd!6dTd d%gd%6dTd d&gd&6dTd d!dTd"dFgdX6dTd dYgdZ6dTd d[gd\6dTd d!dTd"d7gd]6dTd d^gd^6dTd d3gd36dTd d!dTd"d'gd=6dTd d_gd-6dTd d!dTd"d9gd`6dTd dagdC6dTd dbgdD6dTd dHgdH6dTd dHdTd"d.gdQ6dTd dHdTd"d7gdR6dTd d3dTd"d.gdc6dTd d3dTd"d@gdd6de6Z"dfe#fdgYZ$dS(hiN(t SHORTCUTStDEFAULT_ZONE_TARGET(trunProg(tlog(t splitArgst check_mactportStrtcheck_single_addresst check_address(tconfig(t FirewallErrort UNKNOWN_ERRORt INVALID_RULEtINVALID_ICMPTYPEt INVALID_TYPEt INVALID_ENTRY(t Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_Markt firewalldi t preroutingit PREROUTINGtrawijtmangleit postroutingidt POSTROUTINGtnattinputitINPUTtforwardtFORWARDtfiltertinettiptip6ticmpttypesdestination-unreachabletcodet13scommunication-prohibiteds echo-replys echo-requestt4sfragmentation-neededt14shost-precedence-violationt10shost-prohibitedtredirectt1s host-redirectt7s host-unknownshost-unreachablesparameter-problems ip-header-badt8snetwork-prohibitedt0snetwork-redirectt6snetwork-unknownsnetwork-unreachablet3sport-unreachablet15sprecedence-cutofft2sprotocol-unreachablesrequired-option-missingsrouter-advertisementsrouter-solicitations source-quencht5ssource-route-faileds time-exceededstimestamp-replystimestamp-requeststos-host-redirectt12stos-host-unreachablestos-network-redirectt11stos-network-unreachablesttl-zero-during-reassemblysttl-zero-during-transittipv4ticmpv6saddress-unreachables bad-headers beyond-scopes failed-policysnd-neighbor-advertsneighbour-advertisementsnd-neighbor-solicitsneighbour-solicitationsno-routespacket-too-bigs nd-redirects reject-routesnd-router-advertsnd-router-solicitsunknown-header-typesunknown-optiontipv6tnftablescBseZdZeZdZdZdZdZdZ dZ dZ dZ d3d Zd Zd Zd Zd ZddZdZeddZddZddZdZdZdZdZdZdZdZdZ d3d3dZ!d3d3dZ"d3d3dZ#d Z$d3d!Z%d3d"Z&d#Z'd3d$Z(d%Z)d3d&Z*d'Z+ed(Z,d)Z-d*Z.d+Z/d3d,Z0d-Z1d.Z2d/Z3d0Z4d1Z5d2Z6RS(4R:cCsK||_tjd|_|jg|_i|_i|_i|_dS(Ntnft( t_fwR tCOMMANDSt_commandt fill_existstavailable_tablestrule_to_handletrule_ref_counttzone_source_index_cache(tselftfw((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt__init__s     cCs%tjj|j|_t|_dS(N(tostpathtexistsR>tcommand_existstFalsetrestore_command_exists(RD((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR?sc Csy?|jd}|j||j|}||df}WnLtk ry&|jd}|j|d}Wqtk rdSXnX|d}|r| r||kr|||kr||j|qn|r||krg||sitinsertitaddtindexs%d( RRtpopt ValueErrortNonetremovetappendtsortR<t_allow_zone_driftingtlenRP( RDtrule_addtruleRCtitzonet zone_sourcetfamilyRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_run_replace_zone_sourcesD                 c Csddg}|}|ddkrs|ddkrs|}d|dRUtTruetintt ExceptionR R RStjoinRKRBR Rtdebug2t __class__tcopytdeepcopyRCRaRARTRRRZtstrip( RDtargstnft_optst_argst _args_testtstatustoutputtrule_keyR[RCt _args_strtstrtoffset((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt__runs|           #!     cCsAy|j|}Wntk r'tSX||||d+tSdS(Ni(RRRTRKRi(RDR\tpatternt replacementR]((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt _rule_replace,s  cCs|}d|d<|S(NRbi((RDRrtret_args((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt reverse_rule5s cCsttddS(Nsnot implemented(R R (RDtrulest log_denied((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_rules:sc Csd}d|ks*d|ks*d|kr3d}n-d|ksWd|ksWd|kr`d}n|j|dd d |d d g|j|d dddgy|jd}Wntk rnDX|dkrdS|dkrd|g|||d+n |j||j|S(NticmpxR7R"R$R9R#R8s %%REJECT%%trejecttwithR%sadmin-prohibiteds%%ICMP%%tmetatl4protos{icmp, icmpv6}s %%LOGTYPE%%toffRetunicastt broadcastt multicasttpkttypei(RRR(RRRRTRSt_nftables__run(RDR\Rt icmp_keywordR]((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytset_ruleCs$$ $      cCs|r |gStjS(N(tIPTABLES_TO_NFT_HOOKtkeys(RDRc((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytget_available_tablesbscCsYi|_i|_i|_g}x1tjD]#}|jdd|dtgq.W|S(NRbRcs%s(RARBRCt OUR_CHAINSRRWt TABLE_NAME(RDRR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_flush_rulesfs   !cCstdd}g}|dkr|jddd|gxddgD]:}d |d ||d td f}|jt|qFWn5|d kr|jddd|gn ttd|S(Nt_t policy_droptDROPRQRcR!RRwsMadd chain inet %s %s_%s '{ type filter hook %s priority %d ; policy drop ; }'RiitACCEPTRbsnot implemented(RRWtNFT_HOOK_OFFSETRR R (RDtpolicyt table_nameRthookt _add_chain((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_set_policy_rulesps   cCsAt}x+tjD]}|jt|jqWt|S(N(tsettICMP_TYPES_FRAGMENTRtupdateRd(RDt supportedtipv((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytsupported_icmp_typess cCsAg}x+tjD]}|jd|tfqWtt|S(Nsadd table %s %s(RRRWRtmapR(RDtdefault_tablesR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_default_tablessRc Csg}ttddadd rule inet %s filter_%s ct state established,related acceptRs,add rule inet %s filter_%s iifname lo acceptsadd chain inet %s filter_%s_%ss,add rule inet %s filter_%s jump filter_%s_%sRs_add rule inet %s filter_%s ct state invalid %%%%LOGTYPE%%%% log prefix '"STATE_INVALID_DROP: "'s0add rule inet %s filter_%s ct state invalid dropsHadd rule inet %s filter_%s %%%%LOGTYPE%%%% log prefix '"FINAL_REJECT: "'sBadd rule inet %s filter_%s reject with icmpx type admin-prohibiteds$add chain inet %s filter_%s_IN_ZONESRtINtOUTs!add chain inet %s filter_%s_%s_%ss/add rule inet %s filter_%s jump filter_%s_%s_%stINPUT_ZONES_SOURCEt INPUT_ZONEStFORWARD_IN_ZONES_SOURCEtFORWARD_IN_ZONEStFORWARD_OUT_ZONES_SOURCEtFORWARD_OUT_ZONES( RRRRRWRR<RYRRR(RDRt default_rulestchaintdispatch_suffixR`t direction((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_default_ruless (0 (0  ( 4 (!  ((  cCsY|dkrdddgS|dkr,dgS|dkrBddgS|d krUdgSiS( NR Rt FORWARD_INt FORWARD_OUTRRRRR((RDRc((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytget_zone_table_chainss      R!c Cs|dkrr|dkrrg}|j|j||||||d|j|j||||||d|Sidd6dd6dd 6dd 6dd 6dd 6|} |t|d dkr|t|d  d}ntjdt|d|} d} |r3| r3dd|dtd||fdg} ne|r_dd|dtd||fg} n9dd|dtd||fg} |s| dg7} n|dkr| | d|| fg7} n(| | d|d| d|| fg7} | gS(NRR!R"R#tiifnameRtoifnameRRRRtOUTPUTit+t*RR^tgotoRPR\s%ss %s_%s_ZONESs%%ZONE_INTERFACE%%RQRbs%s_%ss"(textendt!build_zone_source_interface_rulesRZRtformatRR( RDtenableR^t interfaceRcRRWR`RtoptttargettactionR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyRs>  &# (cCsK|dkr|dkrg}|jdrI|j|td}nd}td|svt|sv|dkr|j|j|||||dntd|st|s|dkr|j|j|||||dn|Sidt6d t 6|} id d 6d d 6d d6d d6d d6d d6|} |j j r\d||f} nd||f} t j dt|d|} d} |jdr|td}|j|}d|}nCt|r| d krdSd}ntd|rd}nd}| d|dt| d||| || d|| fg }|gS(NRR!sipset:R7R"R9R#RPRbtsaddrRtdaddrRRRRRs%s_%s_ZONES_SOURCEs %s_%s_ZONESRR^Rt@RetetherR\s%ss%%ZONE_SOURCE%%s%s_%s(t startswitht_set_get_familyRZRURRRtbuild_zone_source_address_rulesRiRKR<RYRRRR(RDRR^taddressRcRR`Rt ipset_familytadd_delRtzone_dispatch_chainRRtipsett rule_familyR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR$sT''      c Cs.|dkr`|dkr`g}|j|j|||d|j|j|||d|Stjdt|d|}t||jt|d|d|d |gg}|jd d|d t d ||fg|jd d|d t d ||fg|jd d|d t d||fg|jd d|d t d||fg|jd d|d t d ||fdd ||fg|jd d|d t d ||fdd||fg|jd d|d t d ||fdd||fg|j j j |j }|j jdkr|dkr|d kr|d!kr|}|dkrud}n|jd d|d t d ||fdddd||fg qqn|dkr*|d"kr*|d#kr*|jd d|d t d ||f|dkr|jndgn|S($NRR!R"R#RR^s%s_logs%s_denys%s_allowRQs%ss%s_%ss %s_%s_logs %s_%s_denys %s_%s_allowR\tjumpRR RRRRtREJECTs %%REJECT%%Rs %%LOGTYPE%%Rtprefixs"filter_%s_%s: "R(sINPUTs FORWARD_INs FORWARD_OUTsOUTPUT(Rs %%REJECT%%sDROP(sACCEPTRs %%REJECT%%sDROP(sINPUTs FORWARD_INs FORWARD_OUTsOUTPUT(Rtbuild_zone_chain_rulesRRRRRRRWRR<R^t_zonesRtget_log_deniedtlower( RDR^RcRR`Rt_zoneRt log_suffix((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR^s^            %cCsiddddgd6ddddgd6ddddgd6ddddgd 6dddd gd 6dddd gd 6dd dd gd6dd dd gd6ddddgd6ddddgd6ddddgd6ddddgd6ddddgd6dd ddgd6ddddgd6ddddgd6ddddgd6dd ddgd6dd ddgd 6dd dd!gd"6dd dd!gd!6dd#d$gd%6dd#d$gd&6}||S('NRR$R%shost-prohibitedsicmp-host-prohibiteds host-prohibsnet-prohibitedsicmp-net-prohibiteds net-prohibsadmin-prohibitedsicmp-admin-prohibiteds admin-prohibR8sicmp6-adm-prohibitedsadm-prohibitedsnet-unreachablesicmp-net-unreachables net-unreachshost-unreachablesicmp-host-unreachables host-unreachsport-unreachablesicmp-port-unreachablesicmp6-port-unreachableRs port-unreachsprot-unreachablesicmp-proto-unreachables proto-unreachsaddr-unreachablesicmp6-addr-unreachables addr-unreachsno-routesicmp6-no-routettcptresets tcp-resetstcp-rst((RDt reject_typetfrags((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_reject_types_fragments2cCs|s gSidd6dd6dd6dd6}y|jjd }Wn tk rdttd nXd d |jd |!d ||j|dgS(Ntsecondtstminutetmthourthtdaytdt/sExpected '/' in limittlimittrateii(tvalueRRRTR R (RDRt rich_to_nftR]((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_limit_fragments  cCs|js gSidt6dt6|}|dddtd||fg}||dg7}|jjr|dd |jjg7}n|jjr|d d |jjg7}n||j|jj7}|S( NRQRbR\R!s%ss %s_%s_logRRs"%s"tlevel(RRiRKRRRRR(RDt rich_ruleRRcRt rule_fragmentRR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_logs   cCs||js gSidt6dt6|}|dddtd||fg}||ddd g7}||j|jj7}|S( NRQRbR\R!s%ss %s_%s_logRRtaudit(RRiRKRRR(RDRRRcRRRR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_audits c Cs|js gSidt6dt6|}t|jtkrVd||f}dg} nt|jtkrd||f}dg} |jjr^| |j|jj7} q^nt|jtkrd||f}dg} n~t|jtkrBt j dt d d |}d }d||f}d d d|jj g} nt tdt|j|dddt|g} | |7} | |j|jj7} | | 7} | S(NRQRbs %s_%s_allowtaccepts %s_%s_denyRtdropRRR^RRtmarkRsUnknown action %sR\R!s%s(RRiRKR%RRRRRRRRRR R RRR( RDR^RRRcRRRRt rule_actionR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_actions6        cCsS|s gS|dkr#dddgS|dkr<dddgSttd|dS(NR7RtnfprotoR9sInvalid family(R R (RDt rich_family((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_family_fragments    cCsx|s gSg}td|jr2|dg7}n |dg7}|jra|dd|jg7}n|d|jg7}|S(NR7R"R#Rs!=(Rtaddrtinvert(RDt rich_destR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_destination_fragments  cCsJ|s gSg}|jrtd|jr;|dg7}n |dg7}|jrj|dd|jg7}qF|d|jg7}nt|dr|jr|jr|ddd|jg7}qF|dd|jg7}npt|drF|jrF|j|j}|jr)||ddd |jg7}qF||dd |jg7}n|S( NR7R"R#Rs!=tmacRRR(RRRthasattrRRR(RDt rich_sourceRR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_source_fragment,s(      c Csidt6dt6|}d}tjdtdd|} g} |r_| |j|j7} n|rtd|r| dg7} n | d g7} | d |g7} n|r| |j|j 7} | |j |j 7} n| |d d t |d g7} | st |jtkr+| dddg7} ng} |r| j|j|||| | | j|j|||| | | j|j||||| | n5| j|ddd td|| fg| dg| S(NRQRbR RRR^R7R"R#Rtdports%st-tcttstates new,untrackedR\R!s %s_%s_allowR(RiRKRRRRR`RRt destinationR tsourceRR%RRRWRRRR( RDRR^tprototportRRRRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_ports_rulesIs2  ""(/c Csidt6dt6|}d}tjdtdd|}g} |r_| |j|j7} n|rtd|r| dg7} n | d g7} | d |g7} n|r| |j|j7} | |j|j 7} | |j |j 7} nd d |g} | st |j tkr0| d ddg7} ng} |r| j|j||||| | j|j||||| | j|j|||||| n/| j|dddtd|g| dg| S(NRQRbR RRR^R7R"R#RRRR R s new,untrackedR\R!s%ssfilter_%s_allowR(RiRKRRRRR`RRRR RR%RRRWRRRR( RDRR^tprotocolRRRRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_protocol_rulesjs4 ""()c Csidt6dt6|}d}tjdtdd|} g} |r_| |j|j7} n|rtd|r| dg7} n | d g7} | d |g7} n|r| |j|j 7} | |j |j 7} n| |d d t |d g7} | st |jtkr+| dddg7} ng} |r| j|j|||| | | j|j|||| | | j|j||||| | n5| j|ddd td|| fg| dg| S(NRQRbR RRR^R7R"R#Rtsports%sR R R s new,untrackedR\R!s %s_%s_allowR(RiRKRRRRR`RRRR RRR%RRRWRRRR( RDRR^RRRRRRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_source_ports_ruless2  ""(/c Csidt6dt6|}tjdtdd|} |dddtd | g} |rtd |rv| d g7} n | d g7} | d |g7} n| |ddt|dg7} | dddd||fg7} dddtd||fddd|d|ddg } | | gS(NRQRbRRR^R\R!s%ssfilter_%s_allowR7R"R#RR R R thelperRs"helper-%s-%s"s helper-%s-%st{R%s"%s"Rt;t}(RiRKRRRRRR( RDRR^RRRt helper_nametmodule_short_nameRRR\t helper_object((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_helper_ports_ruless"       cCsidt6dt6|}tjdtdd|}g}|ro||j|j7}||j|j7}n|d|dt d|g|d d d d ggS( NRQRbRRR^R\s%ss nat_%s_allowRs!=tlot masquerade( RiRKRRRRRR RR(RDRR^R`RRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt _build_zone_masquerade_nat_ruless cCsg}|rd|jr$|jdksB|jrdtd|jjrd|j|j||d|n}|r|jr|jdks|jrtd|jjr|j|j||d|n|j|j||d|idt6dt6|}tj dt dd |}g}|rP||j |j 7}||j |j7}n|j|d d d td |g|ddddg|S(NR9R#R7R"RQRbRRR^R\R!s%ssfilter_%s_allowR R s new,untrackedR(R`RRRRR!RiRKRRRRRR RWR(RDRR^RRRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_masquerade_ruless$"" 2c Csidt6dt6|}tjdtdd|} g} |rV| dd|g7} n| ddg7} |r|d kr| d t|d g7} n|d |d td| dd|g|| gS(NRQRbRRR^tdnatttoR+Res:%sR R\s%ss nat_%s_allowRR(RiRKRRRRR( RDRR^Rt mark_fragmentttoaddrttoportR`RRt dnat_fragment((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt"_build_zone_forward_port_nat_ruless c Csaidt6dt6|} d|} dd| g} tjdtdd|} g}| r||j| j7}||j| j7}||j | j 7}ng}|j | d d d t d | g||d |ddd| g| rC| jr| jdks|rCt d|rC|j|j|||| ||dn| r| jra| jdksv|rt d|r|j|j|||| ||dnh|rt d|r|j|j|||| ||dn(|j|j|||| ||dtjdt|d|} |j | d d d t d| dddg| dg|S(NRQRbs0x%xRRRRR^R\R!s%ssmangle_%s_allowR RR9R#R7R"sfilter_%s_allowR R s new,untrackedR(RiRKRRRRR`RRR RRWRRRR)(RDRR^t filter_chainRRR'R&tmark_idRRtmark_strR%RRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_forward_port_ruless@   2cCs<|t|krt||Sttd||jfdS(Ns"ICMP type '%s' not supported by %s(RR R tname(RDRt icmp_type((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_icmp_types_to_nft_fragment/s c Csd}idt6dt6|}|r9|jr9|j}n\|jrg}d|jkrg|jdnd|jkr|jdqn ddg}g}x/|D]'} xddgD]} tjdt| d |} |jj j |rd || f} d } nd || f} d } g}|rl||j |j 7}||j |j7}||j|j7}n||j| |j7}|r8|j|j|||| ||j|j|||| ||jr|j|j||||| |q|j|dddtd || fg|d gq|jjdkr| d kr|j|dddt| g|dddd||fgn|j|dddt| g|| gqWqW|S(NR RQRbR7R9RRRR^s %s_%s_allowRs %s_%s_denys %%REJECT%%R\R!s%sRs %%LOGTYPE%%RRs"%s_%s_ICMP_BLOCK: "(RiRKtipvsRRWRRRR<R^tquery_icmp_block_inversionRR`RR RR0R.RRRRRR(RDRR^tictRRcRR1RRRRt final_chaint final_targetR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_icmp_block_rules6sT      "" (2! -c Csd}g}xddgD]}tjdt|d|}djddtd ||fd d ||fg}|j|}|jjj|rd } nd } |rddddtd ||fd|g} n#ddddtd ||fg} | d| g7} |j | |jjj|r|jj dkr|rpddddtd ||fd|g} n#ddddtd ||fg} | ddddd||fg7} |j | qqqW|S(NR RRRR^RgR!s%ss%s_%sRs %s_%s_allows %%REJECT%%RRQR\RfRbs%%ICMP%%Rs %%LOGTYPE%%RRs"%s_%s_ICMP_BLOCK: "( RRRRlRRAR<R^R2RWR( RDRR^RcRRRRxt rule_handlet ibi_targetR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt%build_zone_icmp_block_inversion_rulesls<     cCsg}|jddddtdddd d d d d dddg|dkr|jddddtdddd d d d d dddddgn|jddddtdddddg |S(NRPR\R!s%ssraw_%sRRRR9tfibRt.tiiftoiftmissingRRRRs"rpfilter_DROP: "R8R%s){ nd-router-advert, nd-neighbor-solicit }Rtraw_PREROUTINGR?R?(RWR(RDRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_rpfilter_ruless   cCsd}tjdtdd|}g}||j|j7}||j|j7}||j|j7}g}|j |j ||||||j |j ||||||j |j |||||||S(NR RRR^( RRRRR`RRR RRWRRR(RDRR^RRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt(build_zone_rich_source_destination_ruless ""%cCs|dkrtStS(NR7R9teb(sipv4sipv6RB(RiRK(RDR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytis_ipv_supporteds cCs;idd6dd6}i ||gd6||ddgd6||dd ||gd 6||dd ||gd 6||d gd 6||gd6||ddgd6||dd ||gd6||dd ||gd6||dgd6dgd6}ydg||dgSWn$tk r6ttd|nXdS(Nt ipv4_addrR7t ipv6_addrR9shash:ips . inet_protos. inet_services hash:ip,ports. inet_service .shash:ip,port,ipshash:ip,port,nets. marks hash:ip,markshash:nets hash:net,portshash:net,port,ipshash:net,port,nets. ifnameshash:net,ifacet ether_addrshash:macR%Rs!ipset type name '%s' is not valid(tKeyErrorR R(RDRR%tipv_addrttypes((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_set_type_fragments(   c Cs)|r+d|kr+|ddkr+d}nd}|dg}||j||7}|rd|kr|d|dddg7}nd |kr|d |d dg7}qn| sd|krd |kr|d d dg7}n|dg7}x4dddgD]#}|jdd|tg|qWdS(NR`tinet6R9R7RttimeoutRRtmaxelemtsizet,tflagstintervalRR!R"R#RQR(RJRR(RDR.R%toptionsRtcmdR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_creates "      cCs:x3dddgD]"}|jdd|t|gqWdS(NR!R"R#RbR(RR(RDR.R`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_destroyscCs)|jjj|jddjd}|jd}t|t|krdttdng}xtt|D]}||dkry||jd}Wn(t k r|dd||g7}qX|||| d|||dg7}n|j |||j dq}W|d S( Nt:iROs+Number of values does not match ipset type.RRR;i( R<Rtget_typetsplitRZR RtrangeRRRTRW(RDR.tentryt type_formatt entry_tokenstfragmentR]RR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_set_entry_fragments +  *cCsTxMdddgD]<}|jdd|t|dg|j||dgqWdS(NR!R"R#RQtelementRR(RRR^(RDR.RZR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytset_addscCsTxMdddgD]<}|jdd|t|dg|j||dgqWdS(NR!R"R#RbR_RR(RRR^(RDR.RZR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_deletescCs:x3dddgD]"}|jdd|t|gqWdS(NR!R"R#tflushR(RR(RDR.R`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_flushscCsk|jjj|}|jdkr-d}n:|jrad|jkra|jddkrad}nd}|S(Nshash:macRR`RKR#R"(R<Rt get_ipsetR%RR(RDR.RR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR!s  N(7t__name__t __module__R.Ritzones_supportedRFR?RaRRRRRRURRRRRRRRKRRRRRRRRRRR RRRRR!R"R)R-R0R6R9R@RARCRJRTRUR^R`RaRcR(((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR:sf  - U      T  + 9 @   "  !#!     ,  6 2          (%tos.pathRGRotfirewall.core.baseRRtfirewall.core.progRtfirewall.core.loggerRtfirewall.functionsRRRRRtfirewallR tfirewall.errorsR R R R RRtfirewall.core.richRRRRRRRRRtobjectR:(((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyts  (."   PK!/>EE fw_test.pyonu[ c`c@sdgZddlZddlZddlZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#m$Z$ddl%m&Z&ddl'm(Z(ddl)m*Z*ddlm+Z+ddl,m-Z-de.fdYZ/dS(t Firewall_testiN(tconfig(t functions(tFirewallIcmpType(tFirewallService(t FirewallZone(tFirewallDirect(tFirewallConfig(tFirewallPolicies(t FirewallIPSet(tFirewallHelper(tlog(tfirewalld_conf(tDirect(tservice_reader(ticmptype_reader(t zone_readertZone(t ipset_reader(t IPSET_TYPES(t helper_reader(terrors(t FirewallErrorcBs+eZdZdZdZdZeedZdZedZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZedZdZdZdZdZdZdZdZdZdZdZdZ dZ!RS(cCsttj|_t|_t|_t|_t|_t |_ t ||_ t ||_t||_t||_t||_t|_t||_t||_|jdS(N(R RtFIREWALLD_CONFt_firewalld_conftFalsetip4tables_enabledtip6tables_enabledtebtables_enabledt ipset_enabledRtipset_supported_typesRticmptypeRtserviceRtzoneRtdirectRRtpoliciesR tipsetR thelpert_Firewall_test__init_vars(tself((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt__init__8s      cCshd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |j|jfS(Ns>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)(t __class__RRRt_statet_panict _default_zonet_module_refcountt_markst _min_marktcleanup_on_exittipv6_rpfilter_enabledRt_individual_callst _log_deniedt_automatic_helpers(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt__repr__LscCsyd|_t|_d|_i|_g|_tj|_tj |_ tj |_ tj |_tj|_tj|_dS(NtINITt(R*RR+R,R-R.RtFALLBACK_MINIMAL_MARKR/tFALLBACK_CLEANUP_ON_EXITR0tFALLBACK_IPV6_RPFILTERR1tFALLBACK_INDIVIDUAL_CALLSR2tFALLBACK_LOG_DENIEDR3tFALLBACK_AUTOMATIC_HELPERSR4(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt __init_varsUs          cCs|jS(N(R2(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytindividual_callscsc Cstj}tjdtjy|jjWntk rMtjdn X|jj dru|jj d}n|jj drt |jj d|_ n|jj dr|jj d}|dk r|j d-krt|_qn|jj drp|jj d}|dk rp|j d.krptjd y|jjWqmtk riqmXqpn|jj d r|jj d }|dk r|j d/krt|_n|j d0krt|_qqn|jrtjd n tjd|jj drf|jj d}|dk rf|j d1krftjdt|_qfn|jj dr|jj d}|dks|j dkrd|_q|j |_tjd|jn|jj drm|jj d}|dk rm|j d2kr'd|_n-|j d3krEd |_n|j |_tjd|jqmn|jjtj|jtjdy|jjjWn]tk r }|jjrtjd|jjj|q tjd|jjj|nX|jjtj|j|j tj!d|j tj"d|j tj#d|j tj$dt%|j&j'dkrtjdn|j tj(d|j tj)d|j tj*d|j tj+dt%|j,j-dkrtjdn|j tj.d|j tj/dt%|j0j1dkrrtj2d t3j4d!nt}xEd"d#d$gD]4}||j0j1krtj2d%|t}qqW|rt3j4d!n||j0j1krId&|j0j1kr d&}n$d'|j0j1kr'd'}nd"}tjd(|||}ntjd)|t5tj6} t7j8j9tj6rtjd*tj6y| jWqtk r}tjd+tj6|qXn|jj:tj| |j;||_<d,|_=dS(4Ns"Loading firewalld config file '%s's0Using fallback firewalld configuration settings.t DefaultZonet MinimalMarkt CleanupOnExittnotfalsetLockdowntyesttruesLockdown is enabledt IPv6_rpfiltersIPv6 rpfilter is enabledsIPV6 rpfilter is disabledtIndividualCallssIndividualCalls is enabledt LogDeniedtoffsLogDenied is set to '%s'tAutomaticHelperssAutomaticHelpers is set to '%s'sLoading lockdown whitelists*Failed to load lockdown whitelist '%s': %sR$RisNo icmptypes found.R%R sNo services found.R!sNo zones found.itblocktdropttrustedsZone '%s' is not available.tpublictexternals+Default zone '%s' is not valid. Using '%s'.sUsing default zone '%s'sLoading direct rules file '%s's)Failed to load direct rules file '%s': %stRUNNING(RCRD(syesRG(RCRD(syesRG(syesRG(RCRD(syesRG(>Rt FALLBACK_ZONER tdebug1RRtreadt ExceptiontwarningtgettintR/tNonetlowerRR0R#tenable_lockdownRR1tTrueR2R3R4tset_firewalld_conftcopytdeepcopytlockdown_whitelisttquery_lockdownterrortfilenamet set_policiest_loadertFIREWALLD_IPSETStETC_FIREWALLD_IPSETStFIREWALLD_ICMPTYPEStETC_FIREWALLD_ICMPTYPEStlenRt get_icmptypestFIREWALLD_HELPERStETC_FIREWALLD_HELPERStFIREWALLD_SERVICEStETC_FIREWALLD_SERVICESR t get_servicestFIREWALLD_ZONEStETC_FIREWALLD_ZONESR!t get_zonestfataltsystexitR tFIREWALLD_DIRECTtostpathtexistst set_directt check_zoneR,R*( R'treloadtcomplete_reloadt default_zonetvaluetmsgRctzR!tobj((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt_startfs                            cCs|jdS(N(R(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytstartsc Cstjj|sdS|r|jtjr}|dkr}t}tjj||_|j |j||_t |_ qt }nxt tj |D]}|jds|jtjr|dkrtjjd||fr|jd||f|dtqqnd||f}tjd||y|dkrt||}|j|jjkr|jj|j}tjd||j|j|j|jj|jn!|jjtjrt|_ n|jj||jjtj|n |dkrt||}|j|jjkr|jj|j}tjd||j|j|j|jj |jn!|jjtjrt|_ n|jj!||jj!tj|n>|dkrht"||d |}|r@dtjj|tjj|d d !f|_|j |jntj|} |j|j#j$kr|j#j%|j}|j#j&|j|j'rtjd ||j|||j(|qtjd||j|j|jn*|jjtjrt|_ t| _ n|jj)| |rUtjd ||j|||j(|q|j#j)|n|d kr5t*||}|j|j+j,kr|j+j-|j}tjd||j|j|j|j+j.|jn!|jjtjr t|_ n|j+j/||jj/tj|n|dkrt0||}|j|j1j2kr|j1j3|j}tjd||j|j|j|j1j4|jn!|jjtjrt|_ n|j1j5||jj5tj|ntj6d|Wqt7k r>} tj8d||| qt9k rktj8d||tj:qXqW|r|j'r|j|j#j$kr|j#j%|j}tjd||j|j|jy|j#j&|jWnnX|jj;|jn|j#j)|ndS(NR!s.xmls%s/%stcombinesLoading %s file '%s'Rs Overloads %s '%s' ('%s/%s')R t no_check_nameiis Combining %s '%s' ('%s/%s')R$R%sUnknown reader type %ssFailed to load %s file '%s': %ssFailed to load %s file '%s':s0 Overloading and deactivating %s '%s' ('%s/%s')(<RyRztisdirt startswithRt ETC_FIREWALLDRtbasenametnamet check_nameRtdefaulttsortedtlistdirtendswithRfR]R RTRRRlt get_icmptypeRdtremove_icmptypet add_icmptypeR_R`RR Rqt get_servicetremove_servicet add_serviceRR!Rttget_zonet remove_zonetcombinedRtadd_zoneRR$t get_ipsetst get_ipsett remove_ipsett add_ipsetRR%t get_helperst get_helpert remove_helpert add_helperRuRRcRVt exceptiont forget_zone( R'Rzt reader_typeRt combined_zoneRdRRtorig_objt config_objR((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRfs                                             cCs|jj|jj|jj|jj|jj|jj|jj|jj|j j|j dS(N( RtcleanupR R!R$R%RR"R#RR&(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRs         cCs|jdS(N(R(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytstopscCsdS(N((R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_panicscCsV|}| s|dkr(|j}n||jjkrRttj|n|S(NR7(tget_default_zoneR!RtRRt INVALID_ZONE(R'R!t_zone((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR}s cCs(tj|s$ttj|ndS(N(RtcheckInterfaceRRtINVALID_INTERFACE(R't interface((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytcheck_interfacescCs|jj|dS(N(R t check_service(R'R ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRscCs tj|}|dksY|dksY|dksYt|dkr|d|dkr|dkrytjd|nz|dkrtjd|nZ|dkrtjd|n:t|dkr|d|dkrtjd |nttj|ndS( Niiiiis'%s': port > 65535s'%s': port is invalids'%s': port is ambiguouss'%s': range start >= end( Rt getPortRangeRZRkR RTRRt INVALID_PORT(R'tporttrange((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_ports$&   &cCsA|sttjn|dkr=ttjd|ndS(Nttcptudptsctptdccps''%s' not in {'tcp'|'udp'|'sctp'|'dccp'}(RRRR(RRtMISSING_PROTOCOLtINVALID_PROTOCOL(R'tprotocol((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_tcpudps   cCs(tj|s$ttj|ndS(N(RtcheckIPRRt INVALID_ADDR(R'tip((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytcheck_ipscCs||dkr3tj|sxttj|qxnE|dkrftj|sxttj|qxnttjddS(Ntipv4tipv6s'%s' not in {'ipv4'|'ipv6'}(Rt checkIPnMaskRRRt checkIP6nMaskt INVALID_IPV(R'tipvtsource((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_addresss   cCs|jj|dS(N(Rtcheck_icmptype(R'ticmp((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRscCsdS(N((R'R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR~scCs|jS(N(R*(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt get_statescCsdS(N((R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytenable_panic_modescCsdS(N((R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytdisable_panic_modescCs|jS(N(R+(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytquery_panic_modescCs|jS(N(R3(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytget_log_deniedscCs|tjkr:ttjd|djtjfn||jkr||_|jj d||jj |j nttj |dS(Ns'%s', choose from '%s's','RJ( RtLOG_DENIED_VALUESRRt INVALID_VALUEtjoinRR3RtsettwriteR~t ALREADY_SET(R'R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytset_log_denieds    cCs|jS(N(R4(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytget_automatic_helpersscCs|tjkr:ttjd|djtjfn||jkr||_|jj d||jj |j nttj |dS(Ns'%s', choose from '%s's','RL( RtAUTOMATIC_HELPERS_VALUESRRRRRR4RRRR~R(R'R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytset_automatic_helperss    cCs|jS(N(R,(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRscCs`|j|}||jkrJ||_|jjd||jjnttj|dS(NR@(R}R,RRRRRtZONE_ALREADY_SET(R'R!R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytset_default_zones  cCs$|jjdd|jjdS(NRERF(RRR(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR\(scCs$|jjdd|jjdS(NRERC(RRR(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytdisable_lockdown,s("t__name__t __module__R(R5R&R?RRRRfRRRR}RRRRRRRR~RRRRRRRRRRR\R(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR7s>                        (0t__all__tos.pathRyRvR_tfirewallRRtfirewall.core.fw_icmptypeRtfirewall.core.fw_serviceRtfirewall.core.fw_zoneRtfirewall.core.fw_directRtfirewall.core.fw_configRtfirewall.core.fw_policiesRtfirewall.core.fw_ipsetR tfirewall.core.fw_helperR tfirewall.core.loggerR tfirewall.core.io.firewalld_confR tfirewall.core.io.directR tfirewall.core.io.serviceRtfirewall.core.io.icmptypeRtfirewall.core.io.zoneRRtfirewall.core.io.ipsetRtfirewall.core.ipsetRtfirewall.core.io.helperRRtfirewall.errorsRtobjectR(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyts2    PK!%77 ipXtables.pyonu[ c`c@sddlZddlZddlmZmZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZddlmZmZmZddlmZmZmZmZddlZid d d gd 6d d gd6d dd d d gd6d dd gd6d d d gd6Zidd6dd6Z idd6dd6Z!dZ"dZ#dZ$de%fdYZ&de&fdYZ'dS( iN(t SHORTCUTStDEFAULT_ZONE_TARGET(trunProg(tlog(ttempFiletreadfilet splitArgst check_mactportStrtcheck_single_addresst check_addresst normalizeIP6(tconfig(t FirewallErrortINVALID_PASSTHROUGHt INVALID_RULE(t Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_MarktINPUTtOUTPUTtFORWARDtsecurityt PREROUTINGtrawt POSTROUTINGtmangletnattfiltersicmp-host-prohibitedtipv4sicmp6-adm-prohibitedtipv6ticmps ipv6-icmpcCsidd6dd6dd6dd6dd6d d 6}|}x|D]}y|j|}Wntk rmq>nX|d kryt||d Wntk rqX|j|d n||||W|S( s Inverse valid rule s-Ds-As--deletes--appends-Is--inserts-Xs-Ns--delete-chains --new-chaini(s-Is--insert(tindext Exceptiontinttpop(targst replace_argstret_argstargtidx((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcommon_reverse_rule7s*     cCsidd6dd6dd6dd6dd6d d 6}|}x|D]}y|j|}Wntk rmq>nX|dkryt||d Wntk rqX|j|d n||||<|SWttd d S(s Reverse valid passthough rule s-Ds-As--deletes--appends-Is--inserts-Xs-Ns--delete-chains --new-chainisno '-A', '-I' or '-N' argN(s-Is--insert(R!t ValueErrorR#R$R R(R%R&R'txR)((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcommon_reverse_passthrough\s.     cCst|}tddddddddd d d d d dddddddg}t||@dkrttdt||@dntddddddg}t||@dkrttdndS(sZ Check if passthough rule is valid (only add, insert and new chain rules are allowed) s-Cs--checks-Ds--deletes-Rs --replaces-Ls--lists-Ss --list-ruless-Fs--flushs-Zs--zeros-Xs--delete-chains-Ps--policys-Es--rename-chainisarg '%s' is not alloweds-As--appends-Is--inserts-Ns --new-chainsno '-A', '-I' or '-N' argN(tsettlenR Rtlist(R%t not_allowedtneeded((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcommon_check_passthroughs*   t ip4tablescBseZdZdZeZdZdZdZd.dZ dZ dZ dZ d Zd Zd Zd Zd ZdZdZdZd.dZdZdZdZdZdZdZddZdZedZ dZ!dZ"dZ#dZ$d Z%d!Z&d"Z'd#Z(d.d.d$Z)d.d.d%Z*d.d.d&Z+d'Z,d.d(Z-d.d)Z.d.d*Z/d+Z0d,Z1d-Z2RS(/RR4cCsz||_tj|j|_tjd|j|_|j|_|j|_ |j g|_ g|_ i|_ dS(Ns %s-restore(t_fwR tCOMMANDStipvt_commandt_restore_commandt_detect_wait_optiont wait_optiont_detect_restore_wait_optiontrestore_wait_optiont fill_existstavailable_tablestzone_source_index_cachet our_chains(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt__init__s    cCs4tjj|j|_tjj|j|_dS(N(tostpathtexistsR8tcommand_existsR9trestore_command_exists(RB((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyR>scCs|jrB|j|krB|jgg|D]}d|^q(}ng|D]}d|^qI}tjd|j|jdj|t|j|\}}|dkrtd|jdj||fn|S(Ns%ss %s: %s %st is'%s %s' failed: %s(R;Rtdebug2t __class__R8tjoinRR+(RBR%titemt_argststatustret((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt__runs*%  c Cs|dkr|Sg}x|D]}t}x|D]}y|j|}Wntk r\q0Xt||kr0d||dkr0t}||djd}x3|D](} |} | | |d<|j| qWq0q0W|s|j|qqW|S(s5Split values combined with commas for options in optst,iN(tNonetFalseR!R+R/tTruetsplittappend( RBtrulestoptst out_rulestrulet processedtopttititemsRNt_rule((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt split_values(    & cCsAy|j|}Wntk r'tSX||||d+tSdS(Ni(R!R+RURV(RBR\tpatternt replacementR_((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt _rule_replaces  cCs|tko|t|kS(N(tBUILT_IN_CHAINS(RBR7ttabletchain((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytis_chain_builtins cCsCd|g}|r"|jdn |jd|j||gS(Ns-ts-Ns-X(RX(RBtaddRgRhR\((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytbuild_chain_ruless    cCsLd|g}|r.|d|t|g7}n|d|g7}||7}|S(Ns-ts-Is-D(tstr(RBRjRgRhR!R%R\((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt build_rules   cCs t|S(N(R*(RBR%((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt reverse_rulescCst|dS(N(R3(RBR%((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcheck_passthroughscCs t|S(N(R-(RBR%((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytreverse_passthrough scCsd}y|jd}Wntk r,n(Xt||dkrT||d}nd}xndddddd gD]T}y|j|}Wntk rqsXt||dkrs||d}qsqsW||fS( NRs-tis-As--appends-Is--inserts-Ns --new-chain(R!R+R/RT(RBR%RgR_RhR^((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytpassthrough_parse_table_chain s$   cCsyb|jd}|j||j|}d|dkrQ||df}n||df}WnLtk ry&|jd}|j|d}Wqtk rdSXnXt}|ddkrt}n|r| r||kr|j|qn|r|rI||kr7|j||jd d n|j|}n!|j j r^d}n t |}d |d<|j d d|dndS(Ns%%ZONE_SOURCE%%s-miiis%%ZONE_INTERFACE%%is-Ds--deletetkeycSs|dS(Ni((R,((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt@ss-Iis%di(s-Ds--delete( R!R$R+RTRVRUtremoveRXtsortR5t_allow_zone_driftingR/tinsert(RBR\R@R_tzonet zone_sourcetrule_addR!((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt_run_replace_zone_source#s>               cCs#t}i}tj|j}x|D]}|}|j|dddt|jg|j|dt|jgy|jd}Wnt k rnLX|dkrq(n|d&krd d d |g|||d +n |j ||j ||d} xpddgD]b} y|j| }Wnt k r6q Xt ||d kr |j ||j |} q q Wxzt t |D]f}x]tjD]R} | ||kr||jdo||jd rd||||i}|jdrg|dRRTRbReRiRkRmRnRoRpRqR{RRRR:R<RRRRRRRURRRRRRRRRRRRR R RRR R!R"(((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyR4s\        ) ^    !  i   7 ,    !     , 1 # t ip6tablescBs eZdZdZedZRS(RR&c Csg}|jddddddddd g |d krk|jddddddddd d d g n|jdddddddddg |jdddddddddg |S(Ns-IRs-tRs-mtrpfilters--inverts-jRR}Rs --log-prefixsrpfilter_DROP: s-ps ipv6-icmps$--icmpv6-type=neighbour-solicitationRs"--icmpv6-type=router-advertisement(RX(RBRRY((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytbuild_rpfilter_ruless"    (R#R$R7RRUR((((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyR&s((tos.pathRERtfirewall.core.baseRRtfirewall.core.progRtfirewall.core.loggerRtfirewall.functionsRRRRRR R R tfirewallR tfirewall.errorsR RRtfirewall.core.richRRRRRRfRRR*R-R3tobjectR4R&(((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyts<  :"     % * PK!YL;; fw_direct.pycnu[ c`c@sdgZddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z defd YZd S( tFirewallDirecti(tLastUpdatedOrderedDict(t ipXtables(tebtables(tFirewallTransaction(tlog(terrors(t FirewallErrorcBsdeZdZdZdZdZdZdZdZd$dZ dZ d Z d$d Z d Zd Zd ZdZd$dZd$dZdZdZdZd$dZd$dZdZdZdZdZdZdZd$dZd$dZ dZ!dZ"d Z#d!Z$d"Z%d#Z&RS(%cCs||_|jdS(N(t_fwt_FirewallDirect__init_vars(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt__init__'s cCs d|j|j|j|jfS(Ns%s(%r, %r, %r)(t __class__t_chainst_rulest_rule_priority_positions(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt__repr__+scCs1i|_i|_i|_i|_d|_dS(N(RRRt _passthroughstNonet_obj(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt __init_vars/s     cCs|jdS(N(R (R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pytcleanup6scCs t|jS(N(RR(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pytnew_transaction;scCs ||_dS(N(R(R tobj((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pytset_permanent_config@scCs|t|jt|jt|jdkr3tSt|jjt|jjt|jjdkrxtSt S(Ni( tlenRRRtTrueRtget_all_chainst get_all_rulestget_all_passthroughstFalse(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pythas_configurationCs /%cCsu|dkr|j}n|}|j|jj|jj|jjf||dkrq|jtndS(N( RRt set_configRRRRtexecuteR(R tuse_transactiont transaction((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt apply_directLs   c Csi}i}i}xi|jD]^}|\}}xI|j|D]:}|jj|||s<|j|gj|q<q<WqWx|jD]}|\}}}xl|j|D]]\} } |jj|||| | s||krt||dddg}||kr:ttjd||fndS(Ntipv4tipv6tebs'%s' not in '%s'(RRt INVALID_IPV(R R/tipvs((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt _check_ipvs  cCsf|j||dkr(tjjn tjj}||krbttjd||fndS(NR>R?s'%s' not in '%s'(sipv4sipv6(RCRtBUILT_IN_CHAINStkeysRRRt INVALID_TABLE(R R/R0ttables((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt_check_ipv_tables    cCs|dkrJtj|}|jjr.i}qd|jj|j|}ntj|}tj|}||krtt j d|n||krtt j d|n|dkr|jj j |dk rtt jd|qndS(NR>R?schain '%s' is built-in chainschain '%s' is reservedsChain '%s' is reserved(sipv4sipv6(sipv4sipv6(RRDRtnftables_enabledtget_direct_backend_by_ipvt our_chainsRt OUR_CHAINSRRt BUILTIN_CHAINtzonetzone_from_chainRt INVALID_CHAIN(R R/R0R1tbuilt_in_chainsRK((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt_check_builtin_chains"            cCsc|r%|jj|gj|n:|j|j|t|j|dkr_|j|=ndS(Ni(RR'R(tremoveR(R R.R1tadd((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt_register_chains cCsZ|dkr|j}n|}|jt|||||dkrV|jtndS(N(RRt_chainRR"(R R/R0R1R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR7s   cCsZ|dkr|j}n|}|jt|||||dkrV|jtndS(N(RRRVRR"R(R R/R0R1R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt remove_chains   cCsO|j|||j|||||f}||jkoN||j|kS(N(RHRRR(R R/R0R1R.((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR&s  cCs:|j||||f}||jkr6|j|SgS(N(RHR(R R/R0R.((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt get_chainss   cCsXg}xK|jD]@}|\}}x+|j|D]}|j|||fq0WqW|S(N(RR((R trtkeyR/R0R1((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyRs  cCs`|dkr|j}n|}|jt|||||||dkr\|jtndS(N(RRt_ruleRR"(R R/R0R1R3R4R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR:s   cCs`|dkr|j}n|}|jt|||||||dkr\|jtndS(N(RRR[RR"R(R R/R0R1R3R4R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt remove_rule s   cCsE|j|||||f}||jkoD||f|j|kS(N(RHR(R R/R0R1R3R4R2((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR)scCsI|j|||||f}||jkrEt|j|jSgS(N(RHRtlistRE(R R/R0R1R2((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt get_ruless c Csmg}x`|jD]U}|\}}}x=|j|D].\}}|j||||t|fq3WqW|S(N(RR(R](R RYRZR/R0R1R3R4((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR%s *cCs|r||jkr(t|j|R?s %s_directit_directs"rule '%s' already is in '%s:%s:%s'srule '%s' is not in '%s:%s:%s'ii(sipv4sipv6(RHRRIRNtcreate_zone_base_by_chainRJtis_chain_builtinRRRtALREADY_ENABLEDt NOT_ENABLEDRtsortedRERR:t build_ruleRatadd_fail(R R`R/R0R1R3R4R$RVtbackendR2R_tindext positionstj((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR[{sL         (%% cCs"|j|||j|||||f}|r|||jkr||j|krttjd|||fqnD||jks||j|krttjd|||fn|jj|}|j ||j ||||j ||||j |j ||| dS(Ns chain '%s' already is in '%s:%s'schain '%s' is not in '%s:%s'( RHRRRRRRqRrRRJt add_rulestbuild_chain_rulesRURu(R RTR/R0R1R$R.Rv((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyRVs$   c Csn|j|t|}|rc||jkr||j|krttjd||fqnA||jks||j|krttjd||fn|jj|}|r|j ||dkr|j |\}}|r|r|jj j |||qn|} n|j |} |j|| |j||||j|j||| dS(Nspassthrough '%s', '%s'R>R?(sipv4sipv6(RCRlRRRRqRrRRJtcheck_passthroughtpassthrough_parse_table_chainRNRotreverse_passthroughR:RiRu( R R`R/R4R$t tuple_argsRvR0R1t_args((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyRjs0        N('t__name__t __module__R RR RRRR RR%R5R6R!RCRHRRRUR7RWR&RXRR:R\R)R^RRaRhRiR;RkR*RRmR[RVRj(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR&sH          '              _ N(t__all__tfirewall.fw_typesRt firewall.coreRRtfirewall.core.fw_transactionRtfirewall.core.loggerRtfirewallRtfirewall.errorsRtobjectR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyts PK![Domm logger.pyonu[ c`c@sddddgZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z de fdYZ de fdYZ d e fd YZd e fd YZde fd YZde fdYZeZdS(t LogTargettFileLogtLoggertlogiNcBs5eZdZdZddZdZdZRS(s% Abstract class for logging targets. cCs d|_dS(N(tNonetfd(tself((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt__init__(sicCstddS(Ns%LogTarget.write is an abstract method(tNotImplementedError(Rtdatatleveltloggertis_debug((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytwrite+scCstddS(Ns%LogTarget.flush is an abstract method(R(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytflush.scCstddS(Ns%LogTarget.close is an abstract method(R(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytclose1s(t__name__t __module__t__doc__RR RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR&s    t _StdoutLogcBs/eZdZddZdZdZRS(cCstj|tj|_dS(N(RRtsyststdoutR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR8s icCs|jj||jdS(N(RR R(RR R R R ((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR <scCs|jdS(N(R(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRAscCs|jjdS(N(RR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRDs(RRRR RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR7s   t _StderrLogcBseZdZRS(cCstj|tj|_dS(N(RRRtstderrR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRKs (RRR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRJst _SyslogLogcBs/eZdZddZdZdZRS(cCs=tj|tjtjjtjdtj tj dS(Ni( RRtsyslogtopenlogtostpathtbasenameRtargvtLOG_PIDt LOG_DAEMON(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRSs icCsd}|rtj}nl||jkr3tj}nQ||jkrNtj}n6||jkritj}n||j krtj }n|j dr|t |d }nt |dkr|dkrtj|qtj||ndS(Ns ii( RRt LOG_DEBUGtINFO1tLOG_INFOtWARNINGt LOG_WARNINGtERRORtLOG_ERRtFATALtLOG_CRITtendswithtlen(RR R R R tpriority((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR as"      cCstjdS(N(Rtcloselog(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRwscCsdS(N((R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRzs(RRRR RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRRs   cBsAeZdZddZdZddZdZdZRS(s< FileLog class. File will be opened on the first write. twcCs#tj|||_||_dS(N(RRtfilenametmode(RR/R0((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs  cCs|jr dStjtjB}|jjdr?|tjO}ntj|j|d|_tj |jdtj |j|j|_t j |jt j t j dS(Ntai(RRtO_CREATtO_WRONLYR0t startswithtO_APPENDtopenR/tfchmodtfdopentfcntltF_SETFDt FD_CLOEXEC(Rtflags((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR6s icCs7|js|jn|jj||jjdS(N(RR6R R(RR R R R ((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR s  cCs'|js dS|jjd|_dS(N(RRR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs  cCs|js dS|jjdS(N(RR(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs (RRRRR6R RR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs    cBseZdZdZdZdZdZdZdZe Z e Z e Zddd Zd Zd d Zd d Zd dZd dZdZdZdZdZdZdZed2dZed2dZed2dZed2dZed2dZ ed2dZ!dZ"dZ#dZ$dZ%d Z&d!Z'd"Z(d#Z)d$Z*d%Z+d&Z,dd'Z-d(Z.dd)Z/ed2dd*Z0ed2dd+Z1ed2dd,Z2dd-Z3d.Z4d/Z5d0Z6dd1Z7RS(3sL Format string: %(class)s Calling class the function belongs to, else empty %(date)s Date using Logger.date_format, see time module %(domain)s Full Domain: %(module)s.%(class)s.%(function)s %(file)s Filename of the module %(function)s Function name, empty in __main__ %(label)s Label according to log function call from Logger.label %(level)d Internal logging level %(line)d Line number in module %(module)s Module name %(message)s Log message Standard levels: FATAL Fatal error messages ERROR Error messages WARNING Warning messages INFOx, x in [1..5] Information DEBUGy, y in [1..10] Debug messages NO_INFO No info output NO_DEBUG No debug output INFO_MAX Maximum info level DEBUG_MAX Maximum debug level x and y depend on info_max and debug_max from Logger class initialization. See __init__ function. Default logging targets: stdout Logs to stdout stderr Logs to stderr syslog Logs to syslog Additional arguments for logging functions (fatal, error, warning, info and debug): nl Disable newline at the end with nl=0, default is nl=1. fmt Format string for this logging entry, overloads global format string. Example: fmt="%(file)s:%(line)d %(message)s" nofmt Only output message with nofmt=1. The nofmt argument wins over the fmt argument. Example: from logger import log log.setInfoLogLevel(log.INFO1) log.setDebugLogLevel(log.DEBUG1) for i in range(1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: " "%(level)d %(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.addDebugLogging("*", fl) log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug3("debug3") log.debug2("debug2") log.debug1("debug1") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error\n", nl=0) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) iiiiiiii cCsi|_i|_d|_d|_i|_i|_i|_i|_i|_i|_ |dkryt d|n|dkrt d|n|j |_ ||_ d|_||_|j|jd|j|jd|j|jd|j|j dxbtd|j dD]J}t|d |||j|dt|d |d ||q"Wxftd|jdD]N}t|d |||j|d |t|d|d||qW|j|j|j|j|jd|jd|jd|j|j|j|j g|jd|jgt|j|j dD] }|^qd|jd|jgtd|jdD] }|^qdS(s Logger class initialization tisLogger: info_max %d is too lowisLogger: debug_max %d is too lows FATAL ERROR: sERROR: s WARNING: sINFO%dsinfo%dcsfdS(Ncsj|||S(N(tinfo(tmessagetargstkwargs(Rtx(s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt s((RRB((RRBs8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRCssDEBUG%ds DEBUG%d: sdebug%dcsfdS(Ncsj|||S(N(tdebug(R?R@RA(RRB(s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRC)s((RRB((RRBs8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRC(ss%(label)s%(message)ss%d %b %Y %H:%M:%St*N( t_levelt _debug_levelt_formatt _date_formatt_labelt _debug_labelt_loggingt_debug_loggingt_domainst_debug_domainst ValueErrorR$tNO_INFOtINFO_MAXtNO_DEBUGt DEBUG_MAXtsetInfoLogLabelR(t TRACEBACKR&trangetsetattrtsetDebugLogLabeltsetInfoLogLevelR"tsetDebugLogLevelt setFormatt setDateFormattsetInfoLoggingRRtsetDebugLogging(Rtinfo_maxt debug_maxRFti((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRsX                     -cCshxat|j|jdD]F}||jkr5qnx(|j|D]\}}}|jqCWqWdS(s Close all logging targets iN(RWR(RTRLR(RR tdummyttarget((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR8s  REcCs.|j|||jkr'|j|S|jS(s Get info log level. (t _checkDomainRFtNOTHING(Rtdomain((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pytgetInfoLogLevel@s  cCsT|j|||jkr(|j}n||jkrC|j}n||j|s  cOsM|j|ddd|j|j|d|d<|j||||dS(s Debug log using debug level [1..debug_max]. There are additional debugx functions according to debug_max from __init__RliRmR N(RoRTR}R~(RR RHR@RA((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRDs  cCs)|j|jtjdgdidS(NR@RA(R~RVt tracebackt format_exc(R((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt exceptionscCs8||ks||kr4td|||fndS(Ns*Level %d out of range, should be [%d..%d].(RP(RR RlRm((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRoscCsD|s dSx3|jD]%}|dkrtd|qqWdS(NtnlRstnofmts0Key '%s' is not allowed as argument for logging.(snlsfmtsnofmt(tkeysRP(RRAtkey((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyR}s  cCs*| s|dkr&td|ndS(NR=sDomain '%s' is not valid.(RP(RRg((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRescCs||jkrt|ts-t|tr6|}n |g}x|D]J}|rq|j|ddd|jqF|j|d|jd|jqFWnY|rgt|j |jD] }|^q}n(gt|j|jD] }|^q}|S(s Generate log level array. RliRm( tALLt isinstancetlistttupleRoRTR(RRRWtDEBUG1(RR R RqRb((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRns    +(cCspt|tst|tr'|}n |g}x9|D]1}t|jts7td|jjq7q7W|S(s Generate target array. s '%s' is no valid logging target.(RRRt issubclasst __class__RRPR(RRdttargetst_target((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt _getTargetss   cCs|r.|j}|j}d|jdf}n(|j}|j}|j|jdf}t|dkru|jnxwt |d|dD]^}||krqnxC||D]7\}}}||kr|j |gj |qqWqWdS(s% Generate dict with domain by level. iiN( RORMRTRNRLR(RRR+tclearRWt setdefaulttappend(RR RNRLt_rangeR RgRc((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyt _genDomainss       c Cs|j||j||}|j|}|r@|j}n |j}x5|D]-}x$|D]}|||fg|||SqqWx-|jD]"}|j||}|rL|SqLWdS(s@ Internal function to get calling class. Returns class or None. N( RtvaluesRRRRt __bases__RR(RRRRtbaset_obj((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRs cOsd}d|kr|d}nd}d|kr>|d}nd}d|kr]|d}n|j||}|sydSt|dkr|||dRDRRoR}ReRnRRRrRtRwRzRRR~R(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyRsdG   ;                      4(t__all__RRRRRRRR9tos.pathRtobjectRRRRRRR(((s8/usr/lib/python2.7/site-packages/firewall/core/logger.pyts(          -( 4PK!²]22 watcher.pycnu[ c`c@s9dgZddlmZmZdefdYZdS(tWatcheri(tGiotGLibcBskeZdZdZdZdZdZdZdZdZ dZ d Z d Z RS( cCs1||_||_i|_i|_g|_dS(N(t _callbackt_timeoutt _monitorst _timeoutst_blocked(tselftcallbackttimeout((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt__init__s     cCsOtjj|}|jtjjd|j|<|j|jd|j dS(Ntchanged( RtFilet new_for_pathtmonitor_directorytFileMonitorFlagstNONEtNoneRtconnectt_file_changed_cb(Rt directorytgfile((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt add_watch_dir"scCsOtjj|}|jtjjd|j|<|j|jd|j dS(NR ( RR Rt monitor_fileRRRRRR(RtfilenameR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pytadd_watch_file(scCs |jjS(N(Rtkeys(R((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt get_watches.scCs ||jkS(N(R(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt has_watch1scCs|j|=dS(N(R(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt remove_watch4scCs&||jkr"|jj|ndS(N(Rtappend(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt block_source7scCs&||jkr"|jj|ndS(N(Rtremove(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pytunblock_source;scCsBx;t|jjD]$}tj|j||j|=qWdS(N(tlistRRRt source_remove(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pytclear_timeouts?scCs-||jkr|j|n|j|=dS(N(RRR(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt_call_callbackDscCs|j}||jkrO||jkrKtj|j||j|=ndS|tjjks|tjjks|tjj ks|tjj kr||jkrtj|j||j|=ntj |j |j ||j|s PK! prog.pycnu[ c`c@s(ddlZdgZdddZdS(iNtrunProgc Cs|dkrg}n|g|}d}|r[t|d}|jj}WdQXnidd6}y:tj|dtjdtjdtjdtd|}Wnt k rd SX|j |\}} |j d d }|j |fS(NtrtCtLANGtstdintstderrtstdoutt close_fdstenvitsutf-8treplace(iR ( tNonetopentreadtencodet subprocesstPopentPIPEtSTDOUTtTruetOSErrort communicatetdecodet returncode( tprogtargvRtargst input_stringthandleRtprocesstoutputt err_output((s6/usr/lib/python2.7/site-packages/firewall/core/prog.pyRs$       (Rt__all__R R(((s6/usr/lib/python2.7/site-packages/firewall/core/prog.pyts  PK!Er## fw_ipset.pynu[# -*- 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 backend""" __all__ = [ "FirewallIPSet" ] from firewall.core.logger import log from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts from firewall.core.io.ipset import IPSet from firewall import errors from firewall.errors import FirewallError class FirewallIPSet(object): def __init__(self, fw): self._fw = fw self._ipsets = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._ipsets) # ipsets def cleanup(self): self._ipsets.clear() def check_ipset(self, name): if name not in self.get_ipsets(): raise FirewallError(errors.INVALID_IPSET, name) def query_ipset(self, name): return name in self.get_ipsets() def get_ipsets(self): return sorted(self._ipsets.keys()) def has_ipsets(self): return len(self._ipsets) > 0 def get_ipset(self, name, applied=False): self.check_ipset(name) obj = self._ipsets[name] if applied: self.check_applied_obj(obj) return obj def _error2warning(self, f, name, *args): # transform errors into warnings try: f(name, *args) except FirewallError as error: msg = str(error) log.warning("%s: %s" % (name, msg)) def backends(self): backends = [] if self._fw.nftables_enabled: backends.append(self._fw.nftables_backend) if self._fw.ipset_enabled: backends.append(self._fw.ipset_backend) return backends def add_ipset(self, obj): if obj.type not in self._fw.ipset_supported_types: raise FirewallError(errors.INVALID_TYPE, "'%s' is not supported by ipset." % obj.type) self._ipsets[obj.name] = obj def remove_ipset(self, name, keep=False): obj = self._ipsets[name] if obj.applied and not keep: try: for backend in self.backends(): backend.set_destroy(name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: log.debug1("Keeping ipset '%s' because of timeout option", name) del self._ipsets[name] def apply_ipsets(self): for name in self.get_ipsets(): obj = self._ipsets[name] obj.applied = False log.debug1("Applying ipset '%s'" % name) for backend in self.backends(): if backend.name == "ipset": active = backend.set_get_active_terse() if name in active and ("timeout" not in obj.options or \ obj.options["timeout"] == "0" or \ obj.type != active[name][0] or \ rm_def_cr_opts(obj.options) != \ active[name][1]): try: backend.set_destroy(name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) if self._fw.individual_calls() \ or backend.name == "nftables": try: backend.set_create(obj.name, obj.type, obj.options) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True if "timeout" in obj.options and \ obj.options["timeout"] != "0": # no entries visible for ipsets with timeout continue for entry in obj.entries: try: backend.set_add(obj.name, entry) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: try: backend.set_restore(obj.name, obj.type, obj.entries, obj.options, None) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True # TYPE def get_type(self, name): return self.get_ipset(name, applied=True).type # DIMENSION def get_dimension(self, name): return len(self.get_ipset(name, applied=True).type.split(",")) def check_applied(self, name): obj = self.get_ipset(name) self.check_applied_obj(obj) def check_applied_obj(self, obj): if not obj.applied: raise FirewallError( errors.NOT_APPLIED, obj.name) # OPTIONS def get_family(self, name): obj = self.get_ipset(name, applied=True) if "family" in obj.options: if obj.options["family"] == "inet6": return "ipv6" return "ipv4" # ENTRIES def __entry_id(self, entry): return entry def __entry(self, enable, name, entry): pass def add_entry(self, name, entry): obj = self.get_ipset(name, applied=True) IPSet.check_entry(entry, obj.options, obj.type) if entry in obj.entries: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already is in '%s'" % (entry, name)) try: for backend in self.backends(): backend.set_add(obj.name, entry) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: if "timeout" not in obj.options or obj.options["timeout"] == "0" \ and entry not in obj.entries: # no entries visible for ipsets with timeout obj.entries.append(entry) def remove_entry(self, name, entry): obj = self.get_ipset(name, applied=True) # no entry check for removal if entry not in obj.entries: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (entry, name)) try: for backend in self.backends(): backend.set_delete(obj.name, entry) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: if "timeout" not in obj.options or obj.options["timeout"] == "0" \ and entry not in obj.entries: # no entries visible for ipsets with timeout obj.entries.remove(entry) def query_entry(self, name, entry): obj = self.get_ipset(name, applied=True) if "timeout" in obj.options and obj.options["timeout"] != "0": # no entries visible for ipsets with timeout raise FirewallError(errors.IPSET_WITH_TIMEOUT, name) return entry in obj.entries def get_entries(self, name): obj = self.get_ipset(name, applied=True) return obj.entries def set_entries(self, name, entries): obj = self.get_ipset(name, applied=True) for entry in entries: IPSet.check_entry(entry, obj.options, obj.type) if "timeout" not in obj.options or obj.options["timeout"] == "0": # no entries visible for ipsets with timeout obj.entries = entries try: for backend in self.backends(): backend.set_flush(obj.name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True try: for backend in self.backends(): if self._fw.individual_calls() \ or backend.name == "nftables": for entry in obj.entries: backend.set_add(obj.name, entry) else: backend.set_restore(obj.name, obj.type, obj.entries, obj.options, None) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True return PK!@@ modules.pycnu[ c`c@sYdZdgZddlmZddlmZddlmZdefdYZ dS(smodules backendtmodulesi(trunProg(tlog(tCOMMANDScBsPeZdZdZdZdZdZdZdZdZ RS(cCstd|_td|_dS(Ntmodprobetrmmod(Rt _load_commandt_unload_command(tself((s9/usr/lib/python2.7/site-packages/firewall/core/modules.pyt__init__s cCs d|jS(Ns%s(t __class__(R((s9/usr/lib/python2.7/site-packages/firewall/core/modules.pyt__repr__$sc Csg}i}tdd}x|D]y}|s5Pn|j}|j}|j|d|ddkr|djdd ||ds  PK!V_P)) fw_helper.pynu[# -*- 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 . # """helper backend""" __all__ = [ "FirewallHelper" ] from firewall import errors from firewall.errors import FirewallError class FirewallHelper(object): def __init__(self, fw): self._fw = fw self._helpers = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._helpers) # helpers def cleanup(self): self._helpers.clear() def check_helper(self, name): if name not in self.get_helpers(): raise FirewallError(errors.INVALID_HELPER, name) def query_helper(self, name): return name in self.get_helpers() def get_helpers(self): return sorted(self._helpers.keys()) def has_helpers(self): return len(self._helpers) > 0 def get_helper(self, name): self.check_helper(name) return self._helpers[name] def add_helper(self, obj): self._helpers[obj.name] = obj def remove_helper(self, name): if name not in self._helpers: raise FirewallError(errors.INVALID_HELPER, name) del self._helpers[name] PK!²]22 watcher.pyonu[ c`c@s9dgZddlmZmZdefdYZdS(tWatcheri(tGiotGLibcBskeZdZdZdZdZdZdZdZdZ dZ d Z d Z RS( cCs1||_||_i|_i|_g|_dS(N(t _callbackt_timeoutt _monitorst _timeoutst_blocked(tselftcallbackttimeout((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt__init__s     cCsOtjj|}|jtjjd|j|<|j|jd|j dS(Ntchanged( RtFilet new_for_pathtmonitor_directorytFileMonitorFlagstNONEtNoneRtconnectt_file_changed_cb(Rt directorytgfile((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt add_watch_dir"scCsOtjj|}|jtjjd|j|<|j|jd|j dS(NR ( RR Rt monitor_fileRRRRRR(RtfilenameR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pytadd_watch_file(scCs |jjS(N(Rtkeys(R((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt get_watches.scCs ||jkS(N(R(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt has_watch1scCs|j|=dS(N(R(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt remove_watch4scCs&||jkr"|jj|ndS(N(Rtappend(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt block_source7scCs&||jkr"|jj|ndS(N(Rtremove(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pytunblock_source;scCsBx;t|jjD]$}tj|j||j|=qWdS(N(tlistRRRt source_remove(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pytclear_timeouts?scCs-||jkr|j|n|j|=dS(N(RRR(RR((s9/usr/lib/python2.7/site-packages/firewall/core/watcher.pyt_call_callbackDscCs|j}||jkrO||jkrKtj|j||j|=ndS|tjjks|tjjks|tjj ks|tjj kr||jkrtj|j||j|=ntj |j |j ||j|s PK!Dprog.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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 subprocess __all__ = ["runProg"] def runProg(prog, argv=None, stdin=None): if argv is None: argv = [] args = [prog] + argv input_string = None if stdin: with open(stdin, 'r') as handle: input_string = handle.read().encode() env = {'LANG': 'C'} try: process = subprocess.Popen(args, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, close_fds=True, env=env) except OSError: return (255, '') (output, err_output) = process.communicate(input_string) output = output.decode('utf-8', 'replace') return (process.returncode, output) PK!%77 ipXtables.pycnu[ c`c@sddlZddlZddlmZmZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZddlmZmZmZddlmZmZmZmZddlZid d d gd 6d d gd6d dd d d gd6d dd gd6d d d gd6Zidd6dd6Z idd6dd6Z!dZ"dZ#dZ$de%fdYZ&de&fdYZ'dS( iN(t SHORTCUTStDEFAULT_ZONE_TARGET(trunProg(tlog(ttempFiletreadfilet splitArgst check_mactportStrtcheck_single_addresst check_addresst normalizeIP6(tconfig(t FirewallErrortINVALID_PASSTHROUGHt INVALID_RULE(t Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_MarktINPUTtOUTPUTtFORWARDtsecurityt PREROUTINGtrawt POSTROUTINGtmangletnattfiltersicmp-host-prohibitedtipv4sicmp6-adm-prohibitedtipv6ticmps ipv6-icmpcCsidd6dd6dd6dd6dd6d d 6}|}x|D]}y|j|}Wntk rmq>nX|d kryt||d Wntk rqX|j|d n||||W|S( s Inverse valid rule s-Ds-As--deletes--appends-Is--inserts-Xs-Ns--delete-chains --new-chaini(s-Is--insert(tindext Exceptiontinttpop(targst replace_argstret_argstargtidx((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcommon_reverse_rule7s*     cCsidd6dd6dd6dd6dd6d d 6}|}x|D]}y|j|}Wntk rmq>nX|dkryt||d Wntk rqX|j|d n||||<|SWttd d S(s Reverse valid passthough rule s-Ds-As--deletes--appends-Is--inserts-Xs-Ns--delete-chains --new-chainisno '-A', '-I' or '-N' argN(s-Is--insert(R!t ValueErrorR#R$R R(R%R&R'txR)((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcommon_reverse_passthrough\s.     cCst|}tddddddddd d d d d dddddddg}t||@dkrttdt||@dntddddddg}t||@dkrttdndS(sZ Check if passthough rule is valid (only add, insert and new chain rules are allowed) s-Cs--checks-Ds--deletes-Rs --replaces-Ls--lists-Ss --list-ruless-Fs--flushs-Zs--zeros-Xs--delete-chains-Ps--policys-Es--rename-chainisarg '%s' is not alloweds-As--appends-Is--inserts-Ns --new-chainsno '-A', '-I' or '-N' argN(tsettlenR Rtlist(R%t not_allowedtneeded((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcommon_check_passthroughs*   t ip4tablescBseZdZdZeZdZdZdZd.dZ dZ dZ dZ d Zd Zd Zd Zd ZdZdZdZd.dZdZdZdZdZdZdZddZdZedZ dZ!dZ"dZ#dZ$d Z%d!Z&d"Z'd#Z(d.d.d$Z)d.d.d%Z*d.d.d&Z+d'Z,d.d(Z-d.d)Z.d.d*Z/d+Z0d,Z1d-Z2RS(/RR4cCsz||_tj|j|_tjd|j|_|j|_|j|_ |j g|_ g|_ i|_ dS(Ns %s-restore(t_fwR tCOMMANDStipvt_commandt_restore_commandt_detect_wait_optiont wait_optiont_detect_restore_wait_optiontrestore_wait_optiont fill_existstavailable_tablestzone_source_index_cachet our_chains(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt__init__s    cCs4tjj|j|_tjj|j|_dS(N(tostpathtexistsR8tcommand_existsR9trestore_command_exists(RB((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyR>scCs|jrB|j|krB|jgg|D]}d|^q(}ng|D]}d|^qI}tjd|j|jdj|t|j|\}}|dkrtd|jdj||fn|S(Ns%ss %s: %s %st is'%s %s' failed: %s(R;Rtdebug2t __class__R8tjoinRR+(RBR%titemt_argststatustret((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt__runs*%  c Cs|dkr|Sg}x|D]}t}x|D]}y|j|}Wntk r\q0Xt||kr0d||dkr0t}||djd}x3|D](} |} | | |d<|j| qWq0q0W|s|j|qqW|S(s5Split values combined with commas for options in optst,iN(tNonetFalseR!R+R/tTruetsplittappend( RBtrulestoptst out_rulestrulet processedtopttititemsRNt_rule((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt split_values(    & cCsAy|j|}Wntk r'tSX||||d+tSdS(Ni(R!R+RURV(RBR\tpatternt replacementR_((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt _rule_replaces  cCs|tko|t|kS(N(tBUILT_IN_CHAINS(RBR7ttabletchain((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytis_chain_builtins cCsCd|g}|r"|jdn |jd|j||gS(Ns-ts-Ns-X(RX(RBtaddRgRhR\((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytbuild_chain_ruless    cCsLd|g}|r.|d|t|g7}n|d|g7}||7}|S(Ns-ts-Is-D(tstr(RBRjRgRhR!R%R\((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt build_rules   cCs t|S(N(R*(RBR%((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt reverse_rulescCst|dS(N(R3(RBR%((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytcheck_passthroughscCs t|S(N(R-(RBR%((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytreverse_passthrough scCsd}y|jd}Wntk r,n(Xt||dkrT||d}nd}xndddddd gD]T}y|j|}Wntk rqsXt||dkrs||d}qsqsW||fS( NRs-tis-As--appends-Is--inserts-Ns --new-chain(R!R+R/RT(RBR%RgR_RhR^((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytpassthrough_parse_table_chain s$   cCsyb|jd}|j||j|}d|dkrQ||df}n||df}WnLtk ry&|jd}|j|d}Wqtk rdSXnXt}|ddkrt}n|r| r||kr|j|qn|r|rI||kr7|j||jd d n|j|}n!|j j r^d}n t |}d |d<|j d d|dndS(Ns%%ZONE_SOURCE%%s-miiis%%ZONE_INTERFACE%%is-Ds--deletetkeycSs|dS(Ni((R,((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt@ss-Iis%di(s-Ds--delete( R!R$R+RTRVRUtremoveRXtsortR5t_allow_zone_driftingR/tinsert(RBR\R@R_tzonet zone_sourcetrule_addR!((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyt_run_replace_zone_source#s>               cCs#t}i}tj|j}x|D]}|}|j|dddt|jg|j|dt|jgy|jd}Wnt k rnLX|dkrq(n|d&krd d d |g|||d +n |j ||j ||d} xpddgD]b} y|j| }Wnt k r6q Xt ||d kr |j ||j |} q q Wxzt t |D]f}x]tjD]R} | ||kr||jdo||jd rd||||i}|jdrg|dRRTRbReRiRkRmRnRoRpRqR{RRRR:R<RRRRRRRURRRRRRRRRRRRR R RRR R!R"(((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyR4s\        ) ^    !  i   7 ,    !     , 1 # t ip6tablescBs eZdZdZedZRS(RR&c Csg}|jddddddddd g |d krk|jddddddddd d d g n|jdddddddddg |jdddddddddg |S(Ns-IRs-tRs-mtrpfilters--inverts-jRR}Rs --log-prefixsrpfilter_DROP: s-ps ipv6-icmps$--icmpv6-type=neighbour-solicitationRs"--icmpv6-type=router-advertisement(RX(RBRRY((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pytbuild_rpfilter_ruless"    (R#R$R7RRUR((((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyR&s((tos.pathRERtfirewall.core.baseRRtfirewall.core.progRtfirewall.core.loggerRtfirewall.functionsRRRRRR R R tfirewallR tfirewall.errorsR RRtfirewall.core.richRRRRRRfRRR*R-R3tobjectR4R&(((s;/usr/lib/python2.7/site-packages/firewall/core/ipXtables.pyts<  :"     % * PK!Y++fw_transaction.pycnu[ c`c@sdZddgZddlmZddlmZddlmZddlm Z de fd YZ de fd YZ de fd YZ d S( s!Transaction classes for firewalldtFirewallTransactiontFirewallZoneTransactioni(tlog(terrors(t FirewallError(tLastUpdatedOrderedDicttSimpleFirewallTransactioncBseZdZdZdZdZdZdZdZdZ dZ d Z ddd Z d Zd Zd ZRS(s>Base class for FirewallTransaction and FirewallZoneTransactioncCs1||_i|_g|_g|_g|_dS(N(tfwtrulest pre_funcst post_funcst fail_funcs(tselfR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt__init__"s     cCs&|jj|j2|j2|j2dS(N(RtclearR R R (R ((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR)s cCs#|jj|jgj|dS(N(Rt setdefaulttnametappend(R tbackendtrule((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_rule/scCs%x|D]}|j||qWdS(N(R(R RRR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_rules2s cCs&|j|jko%||j|jkS(N(RR(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt query_rule6scCsF|j|jkrB||j|jkrB|j|jj|ndS(N(RRtremove(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_rule9s(cGs|jj||fdS(N(R R(R tfunctargs((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_pre=scGs|jj||fdS(N(R R(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_post@scGs|jj||fdS(N(R R(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_failCscCstjdt||df|dkr5i}n|dkrJg}n|sx|jD]R}xIt|j|D]4}|j|gj|jj |j |qtWqZWn4x1|jD]&}|j|gj |j|qW||fS(Ns%s.prepare(%s, %s)s...( Rtdebug4ttypetNoneRtreversedRRRtget_backend_by_namet reverse_ruletextend(R tenableRtmodulest backend_nameR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytprepareFs     '$cCs1tjdt||f|j|\}}|jt}d}g}xe|D]]}y|jj|||Wn,tk r}t }|}tj |qUX|j |qUW|s|jj ||} | r| \} }| rtj |qqn|r#i} xY|D]Q}g| |t||D],} | |j |jj|j| q3WqWxL| D]D}y|jj|| |Wqntk r}tj |qnXqnWxU|jD]J\} }y| |Wqtk r }tj d| ||fqXqWttj|n|jdS(Ns%s.execute(%s)ts#Calling fail func %s(%s) failed: %s(RRRR(tpretFalseRRt ExceptiontTrueterrorRthandle_modulestdebug1R!R"R#R RRtCOMMAND_FAILEDtpost(R R%RR&R.terrorMsgtdoneR'tmsgt module_returntstatust undo_rulesRRR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytexecuteZsP      $  cCsstjdt|xU|jD]J\}}y||Wq!tk rj}tjd|||fq!Xq!WdS(Ns%s.pre()s"Calling pre func %s(%s) failed: %s(RRRR R,R.(R RRR5((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR*s cCsstjdt|xU|jD]J\}}y||Wq!tk rj}tjd|||fq!Xq!WdS(Ns %s.post()s#Calling post func %s(%s) failed: %s(RRRR R,R.(R RRR5((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR2s N(t__name__t __module__t__doc__R RRRRRRRRR R(R9R*R2(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs          = cBsJeZdZdZdZdZdddZdZdZ RS(s<General FirewallTransaction, contains also zone transactionscCs&tt|j|t|_dS(N(tsuperRR Rtzone_transactions(R R((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR scCs$tt|j|jjdS(N(R=RRR>(R ((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRscCs9||jkr.t|j|||j|RR(R tzone((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytzone_transactionscCstjdt||dftt|j|||\}}x|jD]}yR|j|j||x4|j|jD]"}||kr|j|qqWWqNt k r}tj dt |qNXqNW||fS(Ns%s.prepare(%s, %s)s...s1Failed to prepare transaction rules for zone '%s'( RRRR=RR(R>R&RRR.tstr(R R%RR&R?tmoduleR5((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR(s   cCsStjdt|tt|jx"|jD]}|j|jq4WdS(Ns%s.pre()(RRRR=RR*R>(R R?((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR*scCsStjdt|tt|jx"|jD]}|j|jq4WdS(Ns %s.post()(RRRR=RR2R>(R R?((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR2sN( R:R;R<R RR@R R(R*R2(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs    cBseZdZd dZdZd d dZdZdZdZ dZ dZ d Z d Z d Zd ZRS(s;Zone transaction with additional chain and module interfacecCs>tt|j|||_||_g|_g|_dS(N(R=RR R?tfw_transactiontchainsR&(R RR?RC((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR s    cCs|jr~tt|jjx}|jjjD]E}tt|jj|j|jj|j2|jj|j2q2Wn!tt|j|j2|j2dS(N( RCR=RRR>tkeysRRDR&(R R?((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs cCs~tjdt||dftt|j|||\}}x-|jD]"}||krN|j|qNqNW||fS(Ns%s.prepare(%s, %s)s...(RRRR=RR(R&R(R R%RR&RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR(s  cCs6|jr|jj|ntt|j|dS(N(RCR9R=R(R R%((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR9s cCsT||f}||jkrP|jjj|jt|g||jj|ndS(N(RDRR?tgen_chain_rulesR-R(R ttabletchaint table_chain((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_chains "cCs2||f}||jkr.|jj|ndS(N(RDR(R RGRHRI((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_chains cCs?x8|D]0}||jkr|j|d|dqqWdS(Nii(RDRJ(R RDRI((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_chainss cCs7x0|D](}||jkr|jj|qqWdS(N(RDR(R RDRI((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_chains s cCs&||jkr"|jj|ndS(N(R&R(R RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_module%scCs&||jkr"|jj|ndS(N(R&R(R RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_module)scCs"x|D]}|j|qWdS(N(RN(R R&RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_modules-s cCs"x|D]}|j|qWdS(N(RO(R R&RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytremove_modules1s N(R:R;R<R R RR(R9RJRKRLRMRNRORPRQ(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs         N(R<t__all__tfirewall.core.loggerRtfirewallRtfirewall.errorsRtfirewall.fw_typesRtobjectRRR(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyts 5PK!n%?-fw_service.pycnu[ c`c@sCdgZddlmZddlmZdefdYZdS(tFirewallServicei(terrors(t FirewallErrorcBsPeZdZdZdZdZdZdZdZdZ RS(cCs||_i|_dS(N(t_fwt _services(tselftfw((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt__init__s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt__repr__ scCs|jjdS(N(Rtclear(R((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pytcleanup#scCst|jjS(N(tsortedRtkeys(R((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt get_services(scCs(||jkr$ttj|ndS(N(RRRtINVALID_SERVICE(Rtservice((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt check_service+scCs|j||j|S(N(RR(RR((s</usr/lib/python2.7/site-packages/firewall/core/fw_service.pyt get_service/s cCs||j|js PK!4Hzz fw_config.pycnu[ c`c@sdgZddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZmZmZddlmZmZmZdd lmZmZmZdd lmZdd lmZde fd YZ!dS( tFirewallConfigiN(tconfig(tlog(tIcmpTypeticmptype_readerticmptype_writer(tServicetservice_readertservice_writer(tZonet zone_readert zone_writer(tIPSett ipset_readert ipset_writer(tHelpert helper_readert helper_writer(terrors(t FirewallErrorcBseZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!d Z"d!Z#d"Z$d#Z%d$Z&d%Z'd&Z(d'Z)d(Z*d)Z+d*Z,d+Z-d,Z.d-Z/d.Z0d/Z1d0Z2d1Z3d2Z4d3Z5d4Z6d5Z7d6Z8d7Z9d8Z:d9Z;d:Z<d;Z=d<Z>d=Z?d>Z@d?ZAd@ZBdAZCdBZDdCZEdDZFdEZGdFZHdGZIdHZJdIZKdJZLdKZMdLZNdMZOdNZPdOZQdPZRRS(QcCs||_|jdS(N(t_fwt_FirewallConfig__init_vars(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt__init__'s cCs\d|j|j|j|j|j|j|j|j|j|j |j |j |j |j fS(Ns6%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)(t __class__t_ipsetst _icmptypest _servicest_zonest_helperst_builtin_ipsetst_builtin_icmptypest_builtin_servicest_builtin_zonest_builtin_helperst_firewalld_conft _policiest_direct(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt__repr__+s cCsyi|_i|_i|_i|_i|_i|_i|_i|_i|_i|_ d|_ d|_ d|_ dS(N(RRRRRRR R!R"R#tNoneR$R%R&(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt __init_vars4s            cCsx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=qQWx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=q=Wx8t|j jD]!}|j |j|j |=qxWx8t|j jD]!}|j |j|j |=qWx8t|j jD]!}|j |j|j |=qWx8t|j jD]!}|j |j|j |=q)W|j rv|j j|` d|_ n|jr|jj|`d|_n|jr|jj|`d|_n|jdS(N(tlistRtkeystcleanupRR RR!RR"RR#RR$R(R%R&R(Rtx((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyR,CsV         cCs|jjjS(N(Rtpoliciestquery_lockdown(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytlockdown_enabledzscCs|jjj||S(N(RR.t access_check(Rtkeytvalue((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyR1}scCs ||_dS(N(R$(Rtconf((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytset_firewalld_confscCs|jS(N(R$(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytget_firewalld_confscCs6tjjtjs%|jjn |jjdS(N(tostpathtexistsRtFIREWALLD_CONFR$tcleartread(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytupdate_firewalld_confscCs ||_dS(N(R%(RR.((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt set_policiesscCs|jS(N(R%(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt get_policiesscCs<tjjtjs(|jjjn|jjjdS(N( R7R8R9RtLOCKDOWN_WHITELISTR%tlockdown_whitelistR,R<(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytupdate_lockdown_whitelistscCs ||_dS(N(R&(Rtdirect((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt set_directscCs|jS(N(R&(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt get_directscCs6tjjtjs%|jjn |jjdS(N(R7R8R9RtFIREWALLD_DIRECTR&R,R<(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt update_directscCs2ttt|jjt|jjS(N(tsortedtsetR*RR+R(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt get_ipsetsscCs0|jr||j|jR?RBRDRERGRJRNRPRSRUR[R`RjRRRoRpRrRqRsRtRvRxRyR{R|R}RwRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyR&s   7                  E            E            E             M            E    ("t__all__RVR7tos.pathRltfirewallRtfirewall.core.loggerRtfirewall.core.io.icmptypeRRRtfirewall.core.io.serviceRRRtfirewall.core.io.zoneR R R tfirewall.core.io.ipsetR R Rtfirewall.core.io.helperRRRRtfirewall.errorsRtobjectR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyts     PK!ф$$ fw_ipset.pyonu[ c`c@sydZdgZddlmZddlmZddlmZddl m Z ddl m Z de fdYZd S( s ipset backendt FirewallIPSeti(tlog(tremove_default_create_options(tIPSet(terrors(t FirewallErrorcBseZdZdZdZdZdZdZdZe dZ dZ d Z d Z e d Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZRS(cCs||_i|_dS(N(t_fwt_ipsets(tselftfw((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt__init__!s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt__repr__%scCs|jjdS(N(Rtclear(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pytcleanup*scCs+||jkr'ttj|ndS(N(t get_ipsetsRRt INVALID_IPSET(Rtname((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt check_ipset-scCs||jkS(N(R(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt query_ipset1scCst|jjS(N(tsortedRtkeys(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyR4scCst|jdkS(Ni(tlenR(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt has_ipsets7scCs4|j||j|}|r0|j|n|S(N(RRtcheck_applied_obj(RRtappliedtobj((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_ipset:s   cGsNy|||Wn6tk rI}t|}tjd||fnXdS(Ns%s: %s(RtstrRtwarning(RtfRtargsterrortmsg((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt_error2warningAs  cCsNg}|jjr(|j|jjn|jjrJ|j|jjn|S(N(Rtnftables_enabledtappendtnftables_backendt ipset_enabledt ipset_backend(Rtbackends((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyR(Is   cCsE|j|jjkr1ttjd|jn||j|jR)(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pytget_typescCs%t|j|dtjjdS(NRt,(RRR>R)tsplit(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_dimensionscCs |j|}|j|dS(N(RR(RRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt check_appliedscCs%|js!ttj|jndS(N(RRRt NOT_APPLIEDR(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyRs cCsB|j|dt}d|jkr>|jddkr>dSndS(NRtfamilytinet6tipv6tipv4(RR>R:(RRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_familys cCs|S(N((RRD((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt __entry_idscCsdS(N((RtenableRRD((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt__entryscCs|j|dt}tj||j|j||jkr\ttj d||fny.x'|j D]}|j |j |qlWWn%t k r}ttj|nEXd|jks|jddkr||jkr|jj|ndS(NRs'%s' already is in '%s'R5R6(RR>Rt check_entryR:R)R?RRtALREADY_ENABLEDR(R@RR.R/R$(RRRDRR2R!((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt add_entrys "cCs|j|dt}||jkrCttjd||fny.x'|jD]}|j|j|qSWWn%t k r}ttj |nEXd|j ks|j ddkr||jkr|jj |ndS(NRs'%s' not in '%s'R5R6( RR>R?RRt NOT_ENABLEDR(t set_deleteRR.R/R:tremove(RRRDRR2R!((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt remove_entrys "cCsY|j|dt}d|jkrL|jddkrLttj|n||jkS(NRR5R6(RR>R:RRtIPSET_WITH_TIMEOUTR?(RRRDR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt query_entrys"cCs|j|dt}|jS(NR(RR>R?(RRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_entriessc Cs|j|dt}x'|D]}tj||j|jqWd|jksa|jddkrm||_ny+x$|jD]}|j|j q}WWn%t k r}t t j |n Xt|_yx|jD]s}|jjs|j dkr'xL|jD]}|j|j |qWq|j|j |j|j|jdqWWn%t k rx}t t j |n Xt|_dS(NRR5R6R7(RR>RRTR:R)R?R(t set_flushRR.RRR/RRR<R@RARB(RRR?RRDR2R!((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt set_entriess. "   (t__name__t __module__R R RRRRRR8RR"R(R,R3RERFRIRJRRPt_FirewallIPSet__entry_idt_FirewallIPSet__entryRVRZR\R]R_(((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyR s2            3          N(t__doc__t__all__tfirewall.core.loggerRtfirewall.core.ipsetRR;tfirewall.core.io.ipsetRtfirewallRtfirewall.errorsRtobjectR(((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyts PK!ф$$ fw_ipset.pycnu[ c`c@sydZdgZddlmZddlmZddlmZddl m Z ddl m Z de fdYZd S( s ipset backendt FirewallIPSeti(tlog(tremove_default_create_options(tIPSet(terrors(t FirewallErrorcBseZdZdZdZdZdZdZdZe dZ dZ d Z d Z e d Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZRS(cCs||_i|_dS(N(t_fwt_ipsets(tselftfw((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt__init__!s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt__repr__%scCs|jjdS(N(Rtclear(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pytcleanup*scCs+||jkr'ttj|ndS(N(t get_ipsetsRRt INVALID_IPSET(Rtname((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt check_ipset-scCs||jkS(N(R(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt query_ipset1scCst|jjS(N(tsortedRtkeys(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyR4scCst|jdkS(Ni(tlenR(R((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt has_ipsets7scCs4|j||j|}|r0|j|n|S(N(RRtcheck_applied_obj(RRtappliedtobj((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_ipset:s   cGsNy|||Wn6tk rI}t|}tjd||fnXdS(Ns%s: %s(RtstrRtwarning(RtfRtargsterrortmsg((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt_error2warningAs  cCsNg}|jjr(|j|jjn|jjrJ|j|jjn|S(N(Rtnftables_enabledtappendtnftables_backendt ipset_enabledt ipset_backend(Rtbackends((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyR(Is   cCsE|j|jjkr1ttjd|jn||j|jR)(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pytget_typescCs%t|j|dtjjdS(NRt,(RRR>R)tsplit(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_dimensionscCs |j|}|j|dS(N(RR(RRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt check_appliedscCs%|js!ttj|jndS(N(RRRt NOT_APPLIEDR(RR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyRs cCsB|j|dt}d|jkr>|jddkr>dSndS(NRtfamilytinet6tipv6tipv4(RR>R:(RRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_familys cCs|S(N((RRD((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt __entry_idscCsdS(N((RtenableRRD((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt__entryscCs|j|dt}tj||j|j||jkr\ttj d||fny.x'|j D]}|j |j |qlWWn%t k r}ttj|nEXd|jks|jddkr||jkr|jj|ndS(NRs'%s' already is in '%s'R5R6(RR>Rt check_entryR:R)R?RRtALREADY_ENABLEDR(R@RR.R/R$(RRRDRR2R!((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt add_entrys "cCs|j|dt}||jkrCttjd||fny.x'|jD]}|j|j|qSWWn%t k r}ttj |nEXd|j ks|j ddkr||jkr|jj |ndS(NRs'%s' not in '%s'R5R6( RR>R?RRt NOT_ENABLEDR(t set_deleteRR.R/R:tremove(RRRDRR2R!((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt remove_entrys "cCsY|j|dt}d|jkrL|jddkrLttj|n||jkS(NRR5R6(RR>R:RRtIPSET_WITH_TIMEOUTR?(RRRDR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt query_entrys"cCs|j|dt}|jS(NR(RR>R?(RRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt get_entriessc Cs|j|dt}x'|D]}tj||j|jqWd|jksa|jddkrm||_ny+x$|jD]}|j|j q}WWn%t k r}t t j |n Xt|_yx|jD]s}|jjs|j dkr'xL|jD]}|j|j |qWq|j|j |j|j|jdqWWn%t k rx}t t j |n Xt|_dS(NRR5R6R7(RR>RRTR:R)R?R(t set_flushRR.RRR/RRR<R@RARB(RRR?RRDR2R!((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyt set_entriess. "   (t__name__t __module__R R RRRRRR8RR"R(R,R3RERFRIRJRRPt_FirewallIPSet__entry_idt_FirewallIPSet__entryRVRZR\R]R_(((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyR s2            3          N(t__doc__t__all__tfirewall.core.loggerRtfirewall.core.ipsetRR;tfirewall.core.io.ipsetRtfirewallRtfirewall.errorsRtobjectR(((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ipset.pyts PK!YL;; fw_direct.pyonu[ c`c@sdgZddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z defd YZd S( tFirewallDirecti(tLastUpdatedOrderedDict(t ipXtables(tebtables(tFirewallTransaction(tlog(terrors(t FirewallErrorcBsdeZdZdZdZdZdZdZdZd$dZ dZ d Z d$d Z d Zd Zd ZdZd$dZd$dZdZdZdZd$dZd$dZdZdZdZdZdZdZd$dZd$dZ dZ!dZ"d Z#d!Z$d"Z%d#Z&RS(%cCs||_|jdS(N(t_fwt_FirewallDirect__init_vars(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt__init__'s cCs d|j|j|j|jfS(Ns%s(%r, %r, %r)(t __class__t_chainst_rulest_rule_priority_positions(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt__repr__+scCs1i|_i|_i|_i|_d|_dS(N(RRRt _passthroughstNonet_obj(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt __init_vars/s     cCs|jdS(N(R (R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pytcleanup6scCs t|jS(N(RR(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pytnew_transaction;scCs ||_dS(N(R(R tobj((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pytset_permanent_config@scCs|t|jt|jt|jdkr3tSt|jjt|jjt|jjdkrxtSt S(Ni( tlenRRRtTrueRtget_all_chainst get_all_rulestget_all_passthroughstFalse(R ((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pythas_configurationCs /%cCsu|dkr|j}n|}|j|jj|jj|jjf||dkrq|jtndS(N( RRt set_configRRRRtexecuteR(R tuse_transactiont transaction((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt apply_directLs   c Csi}i}i}xi|jD]^}|\}}xI|j|D]:}|jj|||s<|j|gj|q<q<WqWx|jD]}|\}}}xl|j|D]]\} } |jj|||| | s||krt||dddg}||kr:ttjd||fndS(Ntipv4tipv6tebs'%s' not in '%s'(RRt INVALID_IPV(R R/tipvs((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt _check_ipvs  cCsf|j||dkr(tjjn tjj}||krbttjd||fndS(NR>R?s'%s' not in '%s'(sipv4sipv6(RCRtBUILT_IN_CHAINStkeysRRRt INVALID_TABLE(R R/R0ttables((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt_check_ipv_tables    cCs|dkrJtj|}|jjr.i}qd|jj|j|}ntj|}tj|}||krtt j d|n||krtt j d|n|dkr|jj j |dk rtt jd|qndS(NR>R?schain '%s' is built-in chainschain '%s' is reservedsChain '%s' is reserved(sipv4sipv6(sipv4sipv6(RRDRtnftables_enabledtget_direct_backend_by_ipvt our_chainsRt OUR_CHAINSRRt BUILTIN_CHAINtzonetzone_from_chainRt INVALID_CHAIN(R R/R0R1tbuilt_in_chainsRK((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt_check_builtin_chains"            cCsc|r%|jj|gj|n:|j|j|t|j|dkr_|j|=ndS(Ni(RR'R(tremoveR(R R.R1tadd((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt_register_chains cCsZ|dkr|j}n|}|jt|||||dkrV|jtndS(N(RRt_chainRR"(R R/R0R1R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR7s   cCsZ|dkr|j}n|}|jt|||||dkrV|jtndS(N(RRRVRR"R(R R/R0R1R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt remove_chains   cCsO|j|||j|||||f}||jkoN||j|kS(N(RHRRR(R R/R0R1R.((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR&s  cCs:|j||||f}||jkr6|j|SgS(N(RHR(R R/R0R.((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt get_chainss   cCsXg}xK|jD]@}|\}}x+|j|D]}|j|||fq0WqW|S(N(RR((R trtkeyR/R0R1((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyRs  cCs`|dkr|j}n|}|jt|||||||dkr\|jtndS(N(RRt_ruleRR"(R R/R0R1R3R4R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR:s   cCs`|dkr|j}n|}|jt|||||||dkr\|jtndS(N(RRR[RR"R(R R/R0R1R3R4R#R$((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt remove_rule s   cCsE|j|||||f}||jkoD||f|j|kS(N(RHR(R R/R0R1R3R4R2((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR)scCsI|j|||||f}||jkrEt|j|jSgS(N(RHRtlistRE(R R/R0R1R2((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyt get_ruless c Csmg}x`|jD]U}|\}}}x=|j|D].\}}|j||||t|fq3WqW|S(N(RR(R](R RYRZR/R0R1R3R4((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR%s *cCs|r||jkr(t|j|R?s %s_directit_directs"rule '%s' already is in '%s:%s:%s'srule '%s' is not in '%s:%s:%s'ii(sipv4sipv6(RHRRIRNtcreate_zone_base_by_chainRJtis_chain_builtinRRRtALREADY_ENABLEDt NOT_ENABLEDRtsortedRERR:t build_ruleRatadd_fail(R R`R/R0R1R3R4R$RVtbackendR2R_tindext positionstj((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR[{sL         (%% cCs"|j|||j|||||f}|r|||jkr||j|krttjd|||fqnD||jks||j|krttjd|||fn|jj|}|j ||j ||||j ||||j |j ||| dS(Ns chain '%s' already is in '%s:%s'schain '%s' is not in '%s:%s'( RHRRRRRRqRrRRJt add_rulestbuild_chain_rulesRURu(R RTR/R0R1R$R.Rv((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyRVs$   c Csn|j|t|}|rc||jkr||j|krttjd||fqnA||jks||j|krttjd||fn|jj|}|r|j ||dkr|j |\}}|r|r|jj j |||qn|} n|j |} |j|| |j||||j|j||| dS(Nspassthrough '%s', '%s'R>R?(sipv4sipv6(RCRlRRRRqRrRRJtcheck_passthroughtpassthrough_parse_table_chainRNRotreverse_passthroughR:RiRu( R R`R/R4R$t tuple_argsRvR0R1t_args((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyRjs0        N('t__name__t __module__R RR RRRR RR%R5R6R!RCRHRRRUR7RWR&RXRR:R\R)R^RRaRhRiR;RkR*RRmR[RVRj(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyR&sH          '              _ N(t__all__tfirewall.fw_typesRt firewall.coreRRtfirewall.core.fw_transactionRtfirewall.core.loggerRtfirewallRtfirewall.errorsRtobjectR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_direct.pyts PK!nF"]9X9X fw_test.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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__ = [ "Firewall_test" ] import os.path import sys import copy from firewall import config from firewall import functions from firewall.core.fw_icmptype import FirewallIcmpType from firewall.core.fw_service import FirewallService from firewall.core.fw_zone import FirewallZone from firewall.core.fw_direct import FirewallDirect from firewall.core.fw_config import FirewallConfig from firewall.core.fw_policies import FirewallPolicies from firewall.core.fw_ipset import FirewallIPSet from firewall.core.fw_helper import FirewallHelper from firewall.core.logger import log from firewall.core.io.firewalld_conf import firewalld_conf from firewall.core.io.direct import Direct from firewall.core.io.service import service_reader from firewall.core.io.icmptype import icmptype_reader from firewall.core.io.zone import zone_reader, Zone from firewall.core.io.ipset import ipset_reader from firewall.core.ipset import IPSET_TYPES from firewall.core.io.helper import helper_reader from firewall import errors from firewall.errors import FirewallError ############################################################################ # # class Firewall # ############################################################################ class Firewall_test(object): def __init__(self): self._firewalld_conf = firewalld_conf(config.FIREWALLD_CONF) self.ip4tables_enabled = False self.ip6tables_enabled = False self.ebtables_enabled = False self.ipset_enabled = False self.ipset_supported_types = IPSET_TYPES self.icmptype = FirewallIcmpType(self) self.service = FirewallService(self) self.zone = FirewallZone(self) self.direct = FirewallDirect(self) self.config = FirewallConfig(self) self.policies = FirewallPolicies() self.ipset = FirewallIPSet(self) self.helper = FirewallHelper(self) self.__init_vars() def __repr__(self): return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \ (self.__class__, self.ip4tables_enabled, self.ip6tables_enabled, self.ebtables_enabled, self._state, self._panic, self._default_zone, self._module_refcount, self._marks, self._min_mark, self.cleanup_on_exit, self.ipv6_rpfilter_enabled, self.ipset_enabled, self._individual_calls, self._log_denied, self._automatic_helpers) def __init_vars(self): self._state = "INIT" self._panic = False self._default_zone = "" self._module_refcount = { } self._marks = [ ] # fallback settings will be overloaded by firewalld.conf self._min_mark = config.FALLBACK_MINIMAL_MARK self.cleanup_on_exit = config.FALLBACK_CLEANUP_ON_EXIT self.ipv6_rpfilter_enabled = config.FALLBACK_IPV6_RPFILTER self._individual_calls = config.FALLBACK_INDIVIDUAL_CALLS self._log_denied = config.FALLBACK_LOG_DENIED self._automatic_helpers = config.FALLBACK_AUTOMATIC_HELPERS def individual_calls(self): return self._individual_calls def _start(self, reload=False, complete_reload=False): # initialize firewall default_zone = config.FALLBACK_ZONE # load firewalld config log.debug1("Loading firewalld config file '%s'", config.FIREWALLD_CONF) try: self._firewalld_conf.read() except Exception: log.warning("Using fallback firewalld configuration settings.") else: if self._firewalld_conf.get("DefaultZone"): default_zone = self._firewalld_conf.get("DefaultZone") if self._firewalld_conf.get("MinimalMark"): self._min_mark = int(self._firewalld_conf.get("MinimalMark")) if self._firewalld_conf.get("CleanupOnExit"): value = self._firewalld_conf.get("CleanupOnExit") if value is not None and value.lower() in [ "no", "false" ]: self.cleanup_on_exit = False if self._firewalld_conf.get("Lockdown"): value = self._firewalld_conf.get("Lockdown") if value is not None and value.lower() in [ "yes", "true" ]: log.debug1("Lockdown is enabled") try: self.policies.enable_lockdown() except FirewallError: # already enabled, this is probably reload pass if self._firewalld_conf.get("IPv6_rpfilter"): value = self._firewalld_conf.get("IPv6_rpfilter") if value is not None: if value.lower() in [ "no", "false" ]: self.ipv6_rpfilter_enabled = False if value.lower() in [ "yes", "true" ]: self.ipv6_rpfilter_enabled = True if self.ipv6_rpfilter_enabled: log.debug1("IPv6 rpfilter is enabled") else: log.debug1("IPV6 rpfilter is disabled") if self._firewalld_conf.get("IndividualCalls"): value = self._firewalld_conf.get("IndividualCalls") if value is not None and value.lower() in [ "yes", "true" ]: log.debug1("IndividualCalls is enabled") self._individual_calls = True if self._firewalld_conf.get("LogDenied"): value = self._firewalld_conf.get("LogDenied") if value is None or value.lower() == "no": self._log_denied = "off" else: self._log_denied = value.lower() log.debug1("LogDenied is set to '%s'", self._log_denied) if self._firewalld_conf.get("AutomaticHelpers"): value = self._firewalld_conf.get("AutomaticHelpers") if value is not None: if value.lower() in [ "no", "false" ]: self._automatic_helpers = "no" elif value.lower() in [ "yes", "true" ]: self._automatic_helpers = "yes" else: self._automatic_helpers = value.lower() log.debug1("AutomaticHelpers is set to '%s'", self._automatic_helpers) self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf)) # load lockdown whitelist log.debug1("Loading lockdown whitelist") try: self.policies.lockdown_whitelist.read() except Exception as msg: if self.policies.query_lockdown(): log.error("Failed to load lockdown whitelist '%s': %s", self.policies.lockdown_whitelist.filename, msg) else: log.debug1("Failed to load lockdown whitelist '%s': %s", self.policies.lockdown_whitelist.filename, msg) # copy policies to config interface self.config.set_policies(copy.deepcopy(self.policies)) # load ipset files self._loader(config.FIREWALLD_IPSETS, "ipset") self._loader(config.ETC_FIREWALLD_IPSETS, "ipset") # load icmptype files self._loader(config.FIREWALLD_ICMPTYPES, "icmptype") self._loader(config.ETC_FIREWALLD_ICMPTYPES, "icmptype") if len(self.icmptype.get_icmptypes()) == 0: log.error("No icmptypes found.") # load helper files self._loader(config.FIREWALLD_HELPERS, "helper") self._loader(config.ETC_FIREWALLD_HELPERS, "helper") # load service files self._loader(config.FIREWALLD_SERVICES, "service") self._loader(config.ETC_FIREWALLD_SERVICES, "service") if len(self.service.get_services()) == 0: log.error("No services found.") # load zone files self._loader(config.FIREWALLD_ZONES, "zone") self._loader(config.ETC_FIREWALLD_ZONES, "zone") if len(self.zone.get_zones()) == 0: log.fatal("No zones found.") sys.exit(1) # check minimum required zones error = False for z in [ "block", "drop", "trusted" ]: if z not in self.zone.get_zones(): log.fatal("Zone '%s' is not available.", z) error = True if error: sys.exit(1) # check if default_zone is a valid zone if default_zone not in self.zone.get_zones(): if "public" in self.zone.get_zones(): zone = "public" elif "external" in self.zone.get_zones(): zone = "external" else: zone = "block" # block is a base zone, therefore it has to exist log.error("Default zone '%s' is not valid. Using '%s'.", default_zone, zone) default_zone = zone else: log.debug1("Using default zone '%s'", default_zone) # load direct rules obj = Direct(config.FIREWALLD_DIRECT) if os.path.exists(config.FIREWALLD_DIRECT): log.debug1("Loading direct rules file '%s'" % \ config.FIREWALLD_DIRECT) try: obj.read() except Exception as msg: log.error("Failed to load direct rules file '%s': %s", config.FIREWALLD_DIRECT, msg) self.config.set_direct(copy.deepcopy(obj)) self._default_zone = self.check_zone(default_zone) self._state = "RUNNING" def start(self): self._start() def _loader(self, path, reader_type, combine=False): # combine: several zone files are getting combined into one obj if not os.path.isdir(path): return if combine: if path.startswith(config.ETC_FIREWALLD) and reader_type == "zone": combined_zone = Zone() combined_zone.name = os.path.basename(path) combined_zone.check_name(combined_zone.name) combined_zone.path = path combined_zone.default = False else: combine = False for filename in sorted(os.listdir(path)): if not filename.endswith(".xml"): if path.startswith(config.ETC_FIREWALLD) and \ reader_type == "zone" and \ os.path.isdir("%s/%s" % (path, filename)): self._loader("%s/%s" % (path, filename), reader_type, combine=True) continue name = "%s/%s" % (path, filename) log.debug1("Loading %s file '%s'", reader_type, name) try: if reader_type == "icmptype": obj = icmptype_reader(filename, path) if obj.name in self.icmptype.get_icmptypes(): orig_obj = self.icmptype.get_icmptype(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.icmptype.remove_icmptype(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.icmptype.add_icmptype(obj) # add a deep copy to the configuration interface self.config.add_icmptype(copy.deepcopy(obj)) elif reader_type == "service": obj = service_reader(filename, path) if obj.name in self.service.get_services(): orig_obj = self.service.get_service(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.service.remove_service(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.service.add_service(obj) # add a deep copy to the configuration interface self.config.add_service(copy.deepcopy(obj)) elif reader_type == "zone": obj = zone_reader(filename, path, no_check_name=combine) if combine: # Change name for permanent configuration obj.name = "%s/%s" % ( os.path.basename(path), os.path.basename(filename)[0:-4]) obj.check_name(obj.name) # Copy object before combine config_obj = copy.deepcopy(obj) if obj.name in self.zone.get_zones(): orig_obj = self.zone.get_zone(obj.name) self.zone.remove_zone(orig_obj.name) if orig_obj.combined: log.debug1(" Combining %s '%s' ('%s/%s')", reader_type, obj.name, path, filename) obj.combine(orig_obj) else: log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True config_obj.default = True self.config.add_zone(config_obj) if combine: log.debug1(" Combining %s '%s' ('%s/%s')", reader_type, combined_zone.name, path, filename) combined_zone.combine(obj) else: self.zone.add_zone(obj) elif reader_type == "ipset": obj = ipset_reader(filename, path) if obj.name in self.ipset.get_ipsets(): orig_obj = self.ipset.get_ipset(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.ipset.remove_ipset(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.ipset.add_ipset(obj) # add a deep copy to the configuration interface self.config.add_ipset(copy.deepcopy(obj)) elif reader_type == "helper": obj = helper_reader(filename, path) if obj.name in self.helper.get_helpers(): orig_obj = self.helper.get_helper(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.helper.remove_helper(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.helper.add_helper(obj) # add a deep copy to the configuration interface self.config.add_helper(copy.deepcopy(obj)) else: log.fatal("Unknown reader type %s", reader_type) except FirewallError as msg: log.error("Failed to load %s file '%s': %s", reader_type, name, msg) except Exception: log.error("Failed to load %s file '%s':", reader_type, name) log.exception() if combine and combined_zone.combined: if combined_zone.name in self.zone.get_zones(): orig_obj = self.zone.get_zone(combined_zone.name) log.debug1(" Overloading and deactivating %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) try: self.zone.remove_zone(combined_zone.name) except: pass self.config.forget_zone(combined_zone.name) self.zone.add_zone(combined_zone) def cleanup(self): self.icmptype.cleanup() self.service.cleanup() self.zone.cleanup() self.ipset.cleanup() self.helper.cleanup() self.config.cleanup() self.direct.cleanup() self.policies.cleanup() self._firewalld_conf.cleanup() self.__init_vars() def stop(self): self.cleanup() # check functions def check_panic(self): return def check_zone(self, zone): _zone = zone if not _zone or _zone == "": _zone = self.get_default_zone() if _zone not in self.zone.get_zones(): raise FirewallError(errors.INVALID_ZONE, _zone) return _zone def check_interface(self, interface): if not functions.checkInterface(interface): raise FirewallError(errors.INVALID_INTERFACE, interface) def check_service(self, service): self.service.check_service(service) def check_port(self, port): range = functions.getPortRange(port) if range == -2 or range == -1 or range is None or \ (len(range) == 2 and range[0] >= range[1]): if range == -2: log.debug1("'%s': port > 65535" % port) elif range == -1: log.debug1("'%s': port is invalid" % port) elif range is None: log.debug1("'%s': port is ambiguous" % port) elif len(range) == 2 and range[0] >= range[1]: log.debug1("'%s': range start >= end" % port) raise FirewallError(errors.INVALID_PORT, port) def check_tcpudp(self, protocol): if not protocol: raise FirewallError(errors.MISSING_PROTOCOL) if protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, "'%s' not in {'tcp'|'udp'|'sctp'|'dccp'}" % \ protocol) def check_ip(self, ip): if not functions.checkIP(ip): raise FirewallError(errors.INVALID_ADDR, ip) def check_address(self, ipv, source): if ipv == "ipv4": if not functions.checkIPnMask(source): raise FirewallError(errors.INVALID_ADDR, source) elif ipv == "ipv6": if not functions.checkIP6nMask(source): raise FirewallError(errors.INVALID_ADDR, source) else: raise FirewallError(errors.INVALID_IPV, "'%s' not in {'ipv4'|'ipv6'}") def check_icmptype(self, icmp): self.icmptype.check_icmptype(icmp) # RELOAD def reload(self, stop=False): return # STATE def get_state(self): return self._state # PANIC MODE def enable_panic_mode(self): return def disable_panic_mode(self): return def query_panic_mode(self): return self._panic # LOG DENIED def get_log_denied(self): return self._log_denied def set_log_denied(self, value): if value not in config.LOG_DENIED_VALUES: raise FirewallError(errors.INVALID_VALUE, "'%s', choose from '%s'" % \ (value, "','".join(config.LOG_DENIED_VALUES))) if value != self.get_log_denied(): self._log_denied = value self._firewalld_conf.set("LogDenied", value) self._firewalld_conf.write() # now reload the firewall self.reload() else: raise FirewallError(errors.ALREADY_SET, value) # AUTOMATIC HELPERS def get_automatic_helpers(self): return self._automatic_helpers def set_automatic_helpers(self, value): if value not in config.AUTOMATIC_HELPERS_VALUES: raise FirewallError(errors.INVALID_VALUE, "'%s', choose from '%s'" % \ (value, "','".join(config.AUTOMATIC_HELPERS_VALUES))) if value != self.get_automatic_helpers(): self._automatic_helpers = value self._firewalld_conf.set("AutomaticHelpers", value) self._firewalld_conf.write() # now reload the firewall self.reload() else: raise FirewallError(errors.ALREADY_SET, value) # DEFAULT ZONE def get_default_zone(self): return self._default_zone def set_default_zone(self, zone): _zone = self.check_zone(zone) if _zone != self._default_zone: self._default_zone = _zone self._firewalld_conf.set("DefaultZone", _zone) self._firewalld_conf.write() else: raise FirewallError(errors.ZONE_ALREADY_SET, _zone) # lockdown def enable_lockdown(self): self._firewalld_conf.set("Lockdown", "yes") self._firewalld_conf.write() def disable_lockdown(self): self._firewalld_conf.set("Lockdown", "no") self._firewalld_conf.write() PK!|:vPvP fw_direct.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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__ = [ "FirewallDirect" ] from firewall.fw_types import LastUpdatedOrderedDict from firewall.core import ipXtables from firewall.core import ebtables from firewall.core.fw_transaction import FirewallTransaction from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError ############################################################################ # # class Firewall # ############################################################################ class FirewallDirect(object): def __init__(self, fw): self._fw = fw self.__init_vars() def __repr__(self): return '%s(%r, %r, %r)' % (self.__class__, self._chains, self._rules, self._rule_priority_positions) def __init_vars(self): self._chains = { } self._rules = { } self._rule_priority_positions = { } self._passthroughs = { } self._obj = None def cleanup(self): self.__init_vars() # transaction def new_transaction(self): return FirewallTransaction(self._fw) # configuration def set_permanent_config(self, obj): self._obj = obj def has_configuration(self): if len(self._chains) + len(self._rules) + len(self._passthroughs) > 0: return True if len(self._obj.get_all_chains()) + \ len(self._obj.get_all_rules()) + \ len(self._obj.get_all_passthroughs()) > 0: return True return False def apply_direct(self, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction # Apply permanent configuration and save the obj to be able to # remove permanent configuration settings within get_runtime_config # for use in firewalld reload. self.set_config((self._obj.get_all_chains(), self._obj.get_all_rules(), self._obj.get_all_passthroughs()), transaction) if use_transaction is None: transaction.execute(True) def get_runtime_config(self): # Return only runtime changes # Remove all chains, rules and passthroughs that are in self._obj # (permanent config applied in firewalld _start. chains = { } rules = { } passthroughs = { } for table_id in self._chains: (ipv, table) = table_id for chain in self._chains[table_id]: if not self._obj.query_chain(ipv, table, chain): chains.setdefault(table_id, [ ]).append(chain) for chain_id in self._rules: (ipv, table, chain) = chain_id for (priority, args) in self._rules[chain_id]: if not self._obj.query_rule(ipv, table, chain, priority, args): if chain_id not in rules: rules[chain_id] = LastUpdatedOrderedDict() rules[chain_id][(priority, args)] = priority for ipv in self._passthroughs: for args in self._passthroughs[ipv]: if not self._obj.query_passthrough(ipv, args): if ipv not in passthroughs: passthroughs[ipv] = [ ] passthroughs[ipv].append(args) return (chains, rules, passthroughs) def get_config(self): return (self._chains, self._rules, self._passthroughs) def set_config(self, conf, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction (_chains, _rules, _passthroughs) = conf for table_id in _chains: (ipv, table) = table_id for chain in _chains[table_id]: if not self.query_chain(ipv, table, chain): try: self.add_chain(ipv, table, chain, use_transaction=transaction) except FirewallError as error: log.warning(str(error)) for chain_id in _rules: (ipv, table, chain) = chain_id for (priority, args) in _rules[chain_id]: if not self.query_rule(ipv, table, chain, priority, args): try: self.add_rule(ipv, table, chain, priority, args, use_transaction=transaction) except FirewallError as error: log.warning(str(error)) for ipv in _passthroughs: for args in _passthroughs[ipv]: if not self.query_passthrough(ipv, args): try: self.add_passthrough(ipv, args, use_transaction=transaction) except FirewallError as error: log.warning(str(error)) if use_transaction is None: transaction.execute(True) def _check_ipv(self, ipv): ipvs = ['ipv4', 'ipv6', 'eb'] if ipv not in ipvs: raise FirewallError(errors.INVALID_IPV, "'%s' not in '%s'" % (ipv, ipvs)) def _check_ipv_table(self, ipv, table): self._check_ipv(ipv) tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in [ 'ipv4', 'ipv6' ] \ else ebtables.BUILT_IN_CHAINS.keys() if table not in tables: raise FirewallError(errors.INVALID_TABLE, "'%s' not in '%s'" % (table, tables)) def _check_builtin_chain(self, ipv, table, chain): if ipv in ['ipv4', 'ipv6']: built_in_chains = ipXtables.BUILT_IN_CHAINS[table] if self._fw.nftables_enabled: our_chains = {} else: our_chains = self._fw.get_direct_backend_by_ipv(ipv).our_chains[table] else: built_in_chains = ebtables.BUILT_IN_CHAINS[table] our_chains = ebtables.OUR_CHAINS[table] if chain in built_in_chains: raise FirewallError(errors.BUILTIN_CHAIN, "chain '%s' is built-in chain" % chain) if chain in our_chains: raise FirewallError(errors.BUILTIN_CHAIN, "chain '%s' is reserved" % chain) if ipv in [ "ipv4", "ipv6" ]: if self._fw.zone.zone_from_chain(chain) is not None: raise FirewallError(errors.INVALID_CHAIN, "Chain '%s' is reserved" % chain) def _register_chain(self, table_id, chain, add): if add: self._chains.setdefault(table_id, [ ]).append(chain) else: self._chains[table_id].remove(chain) if len(self._chains[table_id]) == 0: del self._chains[table_id] def add_chain(self, ipv, table, chain, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction #TODO: policy="ACCEPT" self._chain(True, ipv, table, chain, transaction) if use_transaction is None: transaction.execute(True) def remove_chain(self, ipv, table, chain, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._chain(False, ipv, table, chain, transaction) if use_transaction is None: transaction.execute(True) def query_chain(self, ipv, table, chain): self._check_ipv_table(ipv, table) self._check_builtin_chain(ipv, table, chain) table_id = (ipv, table) return (table_id in self._chains and chain in self._chains[table_id]) def get_chains(self, ipv, table): self._check_ipv_table(ipv, table) table_id = (ipv, table) if table_id in self._chains: return self._chains[table_id] return [ ] def get_all_chains(self): r = [ ] for key in self._chains: (ipv, table) = key for chain in self._chains[key]: r.append((ipv, table, chain)) return r def add_rule(self, ipv, table, chain, priority, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._rule(True, ipv, table, chain, priority, args, transaction) if use_transaction is None: transaction.execute(True) def remove_rule(self, ipv, table, chain, priority, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._rule(False, ipv, table, chain, priority, args, transaction) if use_transaction is None: transaction.execute(True) def query_rule(self, ipv, table, chain, priority, args): self._check_ipv_table(ipv, table) chain_id = (ipv, table, chain) return chain_id in self._rules and \ (priority, args) in self._rules[chain_id] def get_rules(self, ipv, table, chain): self._check_ipv_table(ipv, table) chain_id = (ipv, table, chain) if chain_id in self._rules: return list(self._rules[chain_id].keys()) return [ ] def get_all_rules(self): r = [ ] for key in self._rules: (ipv, table, chain) = key for (priority, args) in self._rules[key]: r.append((ipv, table, chain, priority, list(args))) return r def _register_rule(self, rule_id, chain_id, priority, enable): if enable: if chain_id not in self._rules: self._rules[chain_id] = LastUpdatedOrderedDict() self._rules[chain_id][rule_id] = priority if chain_id not in self._rule_priority_positions: self._rule_priority_positions[chain_id] = { } if priority in self._rule_priority_positions[chain_id]: self._rule_priority_positions[chain_id][priority] += 1 else: self._rule_priority_positions[chain_id][priority] = 1 else: del self._rules[chain_id][rule_id] if len(self._rules[chain_id]) == 0: del self._rules[chain_id] self._rule_priority_positions[chain_id][priority] -= 1 # DIRECT PASSTHROUGH (untracked) def passthrough(self, ipv, args): try: return self._fw.rule(self._fw.get_direct_backend_by_ipv(ipv).name, args) except Exception as msg: log.debug2(msg) raise FirewallError(errors.COMMAND_FAILED, msg) def _register_passthrough(self, ipv, args, enable): if enable: if ipv not in self._passthroughs: self._passthroughs[ipv] = [ ] self._passthroughs[ipv].append(args) else: self._passthroughs[ipv].remove(args) if len(self._passthroughs[ipv]) == 0: del self._passthroughs[ipv] def add_passthrough(self, ipv, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._passthrough(True, ipv, list(args), transaction) if use_transaction is None: transaction.execute(True) def remove_passthrough(self, ipv, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._passthrough(False, ipv, list(args), transaction) if use_transaction is None: transaction.execute(True) def query_passthrough(self, ipv, args): return ipv in self._passthroughs and \ tuple(args) in self._passthroughs[ipv] def get_all_passthroughs(self): r = [ ] for ipv in self._passthroughs: for args in self._passthroughs[ipv]: r.append((ipv, list(args))) return r def get_passthroughs(self, ipv): r = [ ] if ipv in self._passthroughs: for args in self._passthroughs[ipv]: r.append(list(args)) return r def _rule(self, enable, ipv, table, chain, priority, args, transaction): self._check_ipv_table(ipv, table) # Do not create zone chains if we're using nftables. Only allow direct # rules in the built in chains. if not self._fw.nftables_enabled \ and ipv in [ "ipv4", "ipv6" ]: self._fw.zone.create_zone_base_by_chain(ipv, table, chain, transaction) _chain = chain backend = self._fw.get_direct_backend_by_ipv(ipv) # if nftables is in use, just put the direct rules in the chain # specified by the user. i.e. don't append _direct. if not self._fw.nftables_enabled \ and backend.is_chain_builtin(ipv, table, chain): _chain = "%s_direct" % (chain) elif self._fw.nftables_enabled and chain[-7:] == "_direct" \ and backend.is_chain_builtin(ipv, table, chain[:-7]): # strip _direct suffix. If we're using nftables we don't bother # creating the *_direct chains for builtin chains. _chain = chain[:-7] chain_id = (ipv, table, chain) rule_id = (priority, args) if enable: if chain_id in self._rules and \ rule_id in self._rules[chain_id]: raise FirewallError(errors.ALREADY_ENABLED, "rule '%s' already is in '%s:%s:%s'" % \ (args, ipv, table, chain)) else: if chain_id not in self._rules or \ rule_id not in self._rules[chain_id]: raise FirewallError(errors.NOT_ENABLED, "rule '%s' is not in '%s:%s:%s'" % \ (args, ipv, table, chain)) # get priority of rule priority = self._rules[chain_id][rule_id] # If a rule gets added, the initial rule index position within the # ipv, table and chain combination (chain_id) is 1. # Tf the chain_id exists in _rule_priority_positions, there are already # other rules for this chain_id. The number of rules for a priority # less or equal to the priority of the new rule will increase the # index of the new rule. The index is the ip*tables -I insert rule # number. # # Example: We have the following rules for chain_id (ipv4, filter, # INPUT) already: # ipv4, filter, INPUT, 1, -i, foo1, -j, ACCEPT # ipv4, filter, INPUT, 2, -i, foo2, -j, ACCEPT # ipv4, filter, INPUT, 2, -i, foo2_1, -j, ACCEPT # ipv4, filter, INPUT, 3, -i, foo3, -j, ACCEPT # This results in the following _rule_priority_positions structure: # _rule_priority_positions[(ipv4,filter,INPUT)][1] = 1 # _rule_priority_positions[(ipv4,filter,INPUT)][2] = 2 # _rule_priority_positions[(ipv4,filter,INPUT)][3] = 1 # The new rule # ipv4, filter, INPUT, 2, -i, foo2_2, -j, ACCEPT # has the same pritority as the second rule before and will be added # right after it. # The initial index is 1 and the chain_id is already in # _rule_priority_positions. Therefore the index will increase for # the number of rules in every rule position in # _rule_priority_positions[(ipv4,filter,INPUT)].keys() # where position is smaller or equal to the entry in keys. # With the example from above: # The priority of the new rule is 2. Therefore for all keys in # _rule_priority_positions[chain_id] where priority is 1 or 2, the # number of the rules will increase the index of the rule. # For _rule_priority_positions[chain_id][1]: index += 1 # _rule_priority_positions[chain_id][2]: index += 2 # index will be 4 in the end and the rule in the table chain # combination will be added at index 4. # If there are no rules in the table chain combination, a new rule # has index 1. index = 1 if chain_id in self._rule_priority_positions: positions = sorted(self._rule_priority_positions[chain_id].keys()) j = 0 while j < len(positions) and priority >= positions[j]: index += self._rule_priority_positions[chain_id][positions[j]] j += 1 transaction.add_rule(backend, backend.build_rule(enable, table, _chain, index, args)) self._register_rule(rule_id, chain_id, priority, enable) transaction.add_fail(self._register_rule, rule_id, chain_id, priority, not enable) def _chain(self, add, ipv, table, chain, transaction): self._check_ipv_table(ipv, table) self._check_builtin_chain(ipv, table, chain) table_id = (ipv, table) if add: if table_id in self._chains and \ chain in self._chains[table_id]: raise FirewallError(errors.ALREADY_ENABLED, "chain '%s' already is in '%s:%s'" % \ (chain, ipv, table)) else: if table_id not in self._chains or \ chain not in self._chains[table_id]: raise FirewallError(errors.NOT_ENABLED, "chain '%s' is not in '%s:%s'" % \ (chain, ipv, table)) backend = self._fw.get_direct_backend_by_ipv(ipv) transaction.add_rules(backend, backend.build_chain_rules(add, table, chain)) self._register_chain(table_id, chain, add) transaction.add_fail(self._register_chain, table_id, chain, not add) def _passthrough(self, enable, ipv, args, transaction): self._check_ipv(ipv) tuple_args = tuple(args) if enable: if ipv in self._passthroughs and \ tuple_args in self._passthroughs[ipv]: raise FirewallError(errors.ALREADY_ENABLED, "passthrough '%s', '%s'" % (ipv, args)) else: if ipv not in self._passthroughs or \ tuple_args not in self._passthroughs[ipv]: raise FirewallError(errors.NOT_ENABLED, "passthrough '%s', '%s'" % (ipv, args)) backend = self._fw.get_direct_backend_by_ipv(ipv) if enable: backend.check_passthrough(args) # try to find out if a zone chain should be used if ipv in [ "ipv4", "ipv6" ]: table, chain = backend.passthrough_parse_table_chain(args) if table and chain: self._fw.zone.create_zone_base_by_chain(ipv, table, chain) _args = args else: _args = backend.reverse_passthrough(args) transaction.add_rule(backend, _args) self._register_passthrough(ipv, tuple_args, enable) transaction.add_fail(self._register_passthrough, ipv, tuple_args, not enable) PK!i֑ fw_icmptype.pycnu[ c`c@s_dgZddlZddlmZddlmZddlmZdefdYZ dS(tFirewallIcmpTypeiN(tlog(terrors(t FirewallErrorcBsPeZdZdZdZdZdZdZdZdZ RS(cCs||_i|_dS(N(t_fwt _icmptypes(tselftfw((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt__init__s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt__repr__"scCs|jjdS(N(Rtclear(R((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pytcleanup%scCst|jjS(N(tsortedRtkeys(R((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt get_icmptypes*scCs(||jkr$ttj|ndS(N(RRRtINVALID_ICMPTYPE(Rticmptype((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pytcheck_icmptype-scCs|j||j|S(N(RR(RR((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt get_icmptype1s cCs_|j}t|dkr*ddg}n|}x|D]}|dkrk|jjs\q8n|jj}n3|dkr|jjsq8n|jj}ng}|jj|kr8t j d|j|f|j |q8q8Wt|t|krKt|dkr t t jdntj|}||_||j|js  PK!e&$$ ipset.pycnu[ c`c @sdZdddgZddlZddlmZddlmZddlm Z dd l m Z dd l m Z mZdd lmZd Zd ddddddddddg Zidd6dd6dd6dd6Zidd6d d6d!d6Zdefd"YZd#Zd$ZdS(%sThe ipset command wrappertipsettcheck_ipset_nametremove_default_create_optionsiN(terrors(t FirewallError(trunProg(tlog(ttempFiletreadfile(tCOMMANDSi shash:ips hash:ip,portshash:ip,port,ipshash:ip,port,nets hash:ip,markshash:nets hash:net,nets hash:net,portshash:net,port,netshash:net,ifaceshash:macs inet|inet6tfamilytvaluethashsizetmaxelems value in secsttimeouttinett1024t65536cBseZdZdZdZdZdZdZddZ dZ dZ d Z dd Z ddd Zd Zdd ZdddZdZdZdZdZRS(sipset command wrapper classcCstd|_d|_dS(NR(R t_commandtname(tself((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt__init__Js cCsg|D]}d|^q}tjd|j|jdj|t|j|\}}|dkrtd|jdj||fn|S(sCall ipset with argss%ss %s: %s %st is'%s %s' failed: %s(Rtdebug2t __class__RtjoinRt ValueError(Rtargstitemt_argststatustret((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt__runNs%  cCs/t|tkr+ttjd|ndS(sCheck ipset namesipset name '%s' is not validN(tlentIPSET_MAXNAMELENRRt INVALID_NAME(RR((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt check_nameYs cCsg}d}y|jdg}Wn$tk rH}tjd|nX|j}t}x{|D]s}|r|jjdd}|d|kr|dt kr|j |dqn|j drbt }qbqbW|S(s?Return types that are supported by the ipset command and kernelts--helpsipset error: %siisSupported set types:N( t _ipset__runRRtdebug1t splitlinestFalsetstriptsplittNonet IPSET_TYPEStappendt startswithtTrue(RRtoutputtextlinestin_typestlinetsplits((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pytset_supported_types_s     cCs;t|tks|tkr7ttjd|ndS(sCheck ipset types!ipset type name '%s' is not validN(R!R"R-RRt INVALID_TYPE(Rt type_name((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt check_typets cCs|j||j|d||g}t|trxF|jD]5\}}|j||dkrE|j|qEqEWn|j|S(s+Create an ipset with name, type and optionstcreateR%(R$R:t isinstancetdicttitemsR.R&(Rtset_nameR9toptionsRtkeytval((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_createzs    cCs |j||jd|gS(Ntdestroy(R$R&(RR?((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_destroys cCsd||g}|j|S(Ntadd(R&(RR?tentryR((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pytset_addscCsd||g}|j|S(Ntdel(R&(RR?RGR((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_deletescCs?d||g}|r2|jddj|n|j|S(Nttests%sR(R.RR&(RR?RGR@R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRKscCsKdg}|r|j|n|r5|j|n|j|jdS(Ntlists (R.textendR&R+(RR?R@R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pytset_lists  c Cs|jddg}i}d}}i}x|D]z}t|dkrPq2ng|jddD]}|j^qc}t|dkrq2q2|ddkr|d}q2|ddkr|d}q2|dd kr2|dj} d} xz| t| kro| | } | dkrbt| | krK| d7} | | || R.twriteRtclosetoststatRRRRRtst_sizeRtgetDebugLogLevelRt Exceptiontdebug3tendswithtunlinkR(RR?R9tentriestcreate_optionst entry_optionst temp_fileRRARBRGRfRRR[R5((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_restoresV              #  cCs,dg}|r|j|n|j|S(Ntflush(R.R&(RR?R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyt set_flushs cCs|jd||gS(Ntrename(R&(Rt old_set_namet new_set_name((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRt scCs|jd||gS(Ntswap(R&(Rt set_name_1t set_name_2((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRwscCs|jdgS(Ntversion(R&(R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRzsN(t__name__t __module__t__doc__RR&R$R7R:R,RCRERHRJRKRNR]R^RqRsRtRwRz(((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRGs&         ' 7   cCst|tkrtStS(s"Return true if ipset name is valid(R!R"R)R0(R((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRscCsK|j}x8tD]0}||krt|||kr||=qqW|S(s( Return only non default create options (tcopytIPSET_DEFAULT_CREATE_OPTIONS(R@RXR\((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyRs    (R}t__all__tos.pathRetfirewallRtfirewall.errorsRtfirewall.core.progRtfirewall.core.loggerRtfirewall.functionsRRtfirewall.configR R"R-tIPSET_CREATE_OPTIONSRtobjectRRR(((s7/usr/lib/python2.7/site-packages/firewall/core/ipset.pyts@     PK!zzfw.pyonu[ c`c@sdgZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddl m Z ddl mZdd l mZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl$m%Z%ddl&m'Z'ddl(m)Z)ddl*m+Z+ddl,m-Z-m.Z.ddl/m0Z0ddl1m2Z2ddlm3Z3ddl4m5Z5de6fdYZ7dS(tFirewalliN(tconfig(t functions(t ipXtables(tebtables(tnftables(tipset(tmodules(tFirewallIcmpType(tFirewallService(t FirewallZone(tFirewallDirect(tFirewallConfig(tFirewallPolicies(t FirewallIPSet(tFirewallTransaction(tFirewallHelper(tlog(tfirewalld_conf(tDirect(tservice_reader(ticmptype_reader(t zone_readertZone(t ipset_reader(t helper_reader(terrors(t FirewallErrorcBseZdZdZdZdZdZdZeedZ dZ edZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZedZedZedZedZdZdZdZ dZ!dZ"dZ#d Z$d!Z%d"Z&d#Z'd$Z(d%Z)ed&Z*d'Z+d(Z,d)Z-d*Z.d+Z/d,Z0d-Z1d.Z2d/Z3d0Z4RS(1cCs@ttj|_tj||_t|_g|_ tj ||_ t|_ g|_ tj|_t|_tj|_t|_g|_tj||_t|_tj|_t||_t||_t||_t ||_!t"||_t#|_$t%||_t&||_'|j(dS(N()RRtFIREWALLD_CONFt_firewalld_confRt ip4tablestip4tables_backendtTruetip4tables_enabledtip4tables_supported_icmp_typest ip6tablestip6tables_backendtip6tables_enabledtip6tables_supported_icmp_typesRtebtables_backendtebtables_enabledRt ipset_backendt ipset_enabledtipset_supported_typesRtnftables_backendtnftables_enabledRtmodules_backendRticmptypeR tserviceR tzoneR tdirectR R tpoliciesRRthelpert_Firewall__init_vars(tself((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt__init__?s0         cCshd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |j|jfS(Ns>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)(t __class__R!R%R(t_statet_panict _default_zonet_module_refcountt_markst _min_marktcleanup_on_exittipv6_rpfilter_enabledR*t_individual_callst _log_deniedt_automatic_helpers(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt__repr__]scCsd|_t|_d|_i|_g|_tj|_tj |_ tj |_ tj |_tj|_tj|_tj|_d|_tj|_dS(NtINITti(R9tFalseR:R;R<R=RtFALLBACK_MINIMAL_MARKR>tFALLBACK_CLEANUP_ON_EXITR?tFALLBACK_IPV6_RPFILTERR@tFALLBACK_INDIVIDUAL_CALLSRAtFALLBACK_LOG_DENIEDRBtFALLBACK_AUTOMATIC_HELPERSRCtFALLBACK_FIREWALL_BACKENDt_firewall_backendtnf_conntrack_helper_settingtFALLBACK_ALLOW_ZONE_DRIFTINGt_allow_zone_drifting(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt __init_varsfs             cCs|jS(N(RA(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytindividual_callswscCs|jr=d|jdjkr=tjdt|_n|jrzd|jdjkrztjdt|_n|jrd|jdjkrtjdt|_n|j r|j r|j rtj dt j d ndS( Ntfiltertipv4s-iptables not usable, disabling IPv4 firewall.tipv6s.ip6tables not usable, disabling IPv6 firewall.tebs8ebtables not usable, disabling ethernet bridge firewall.sNo IPv4 and IPv6 firewall.i( R!tget_backend_by_ipvtget_available_tablesRtwarningRGR%R(R-tfataltsystexit(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt _check_tableszs            cCsy|jjWn0tk rCtjdt|_g|_nX|jj|_|j j |j j s|j j rtjdqtjdt|_ n|j r|j j|_n g|_|jj |jj s|jj rtjdqtjdt|_n|jr7|jj|_n g|_|jj |jj s|jj rutjdqtjdt|_n|jr|j r|jj rtjdndS( Ns4ipset not usable, disabling ipset usage in firewall.sFiptables-restore is missing, using individual calls for IPv4 firewall.sCiptables-restore and iptables are missing, disabling IPv4 firewall.sGip6tables-restore is missing, using individual calls for IPv6 firewall.sEip6tables-restore and ip6tables are missing, disabling IPv6 firewall.sHebtables-restore is missing, using individual calls for bridge firewall.sEebtables-restore and ebtables are missing, disabling bridge firewall.sSebtables-restore is not supporting the --noflush option, will therefore not be used(R)tset_listt ValueErrorRR[RGR*R+tset_supported_typesRt fill_existstrestore_command_existstcommand_existsR!tsupported_icmp_typesR"R$R%R&R'R(RAtrestore_noflush_optiontdebug1(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt _start_checksD                        cCsw tj}tjdtjy|jjWn-tk r\}tj|tjdnX|jj dr|jj d}n|jj drt |jj d|_ n|jj dr|jj d}|dk r|j d<krt|_ntjd|jn|jj d r|jj d }|dk r|j d=krtjd y|jjWqtk rqXqn|jj d r|jj d }|dk r|j d>krt|_n|j d?krt|_qqn|jrtjdn tjd|jj dr|jj d}|dk r|j d@krtjdt|_qn|jj dr|jj d}|dks|j dkrd|_q|j |_tjd|jn|jj dr|jj d}|dk r|j dAkrId|_n-|j dBkrgd |_n|j |_tjd|jqn|jj dr|jj d}|j dCkrt|_nt|_tjdtjd|jn|jjtj|j|j|j|jtjdy|jjjWn]tk r}|jj rtj!d|jjj"|qtjd|jjj"|nX|jj#tj|j|j$tj%d|j$tj&d|j$tj'd|j$tj(dt)|j*j+dkrGtj!dn|j$tj,d |j$tj-d |j$tj.d!|j$tj/d!t)|j0j1dkrtj!d"n|j$tj2d#|j$tj3d#t)|j4j5dkrtj6d$t7j8d%nt}xEd&d'd(gD]4}||j4j5kr2tj6d)|t}q2q2W|rt7j8d%n||j4j5krd*|j4j5krd*}n$d+|j4j5krd+}nd&}tj!d,|||}ntjd-|t9tj:} t;j<j=tj:rxtjd.tj:y| jWqxtk rt}tj!d/tj:|qxXn|j>j?| |jj@tj| |jAd0gt\} }| dkrtjd1|n|jd2krtBjC|jd kntBjD|_E|jFtjGdkr>tHjH} ntI|} |jJd3| |rf|s~|jKr|jLjMr| jNt| jOn|r|rtjd4|jPjQn|jRd3| | jNt| jO|jKr |jLjMr tjd5|jLjSntjd6|jTd3| tjd7|j4jUd3| |jV||_W|j4jXd|jWd3| | jNt| jO|j>jYr: tjd8|j>jZ| y| jNt| jOWq: tk r# } t| j[d9| j\r | j\nd:q: tk r6 q: Xn~ tjGd%krs tHjH}tj]d;|| ndS(DNs"Loading firewalld config file '%s's0Using fallback firewalld configuration settings.t DefaultZonet MinimalMarkt CleanupOnExittnotfalsesCleanupOnExit is set to '%s'tLockdowntyesttruesLockdown is enabledt IPv6_rpfiltersIPv6 rpfilter is enabledsIPV6 rpfilter is disabledtIndividualCallssIndividualCalls is enabledt LogDeniedtoffsLogDenied is set to '%s'tAutomaticHelperssAutomaticHelpers is set to '%s'tAllowZoneDriftingsAllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.s AllowZoneDrifting is set to '%s'sLoading lockdown whitelists*Failed to load lockdown whitelist '%s': %sRR/isNo icmptypes found.R4R0sNo services found.R1sNo zones found.itblocktdropttrustedsZone '%s' is not available.tpublictexternals+Default zone '%s' is not valid. Using '%s'.sUsing default zone '%s'sLoading direct rules file '%s's)Failed to load direct rules file '%s': %st nf_conntracks&Failed to load nf_conntrack module: %stsystemtuse_transactionsUnloading firewall modulessApplying ipsetssApplying default rule setsApplying used zoness2Applying direct chains rules and passthrough ruless Direct: %sRFs%Flushing and applying took %f seconds(RmRn(syesRq(RmRn(syesRq(syesRq(RmRn(syesRq(RmRn(^Rt FALLBACK_ZONERRhRRtreadt ExceptionR[tgettintR>tNonetlowerRGR?R3tenable_lockdownRR@R RARBRCRRtset_firewalld_conftcopytdeepcopyt_select_firewall_backendRORitlockdown_whitelisttquery_lockdownterrortfilenamet set_policiest_loadertFIREWALLD_IPSETStETC_FIREWALLD_IPSETStFIREWALLD_ICMPTYPEStETC_FIREWALLD_ICMPTYPEStlenR/t get_icmptypestFIREWALLD_HELPERStETC_FIREWALLD_HELPERStFIREWALLD_SERVICEStETC_FIREWALLD_SERVICESR0t get_servicestFIREWALLD_ZONEStETC_FIREWALLD_ZONESR1t get_zonesR\R]R^RtFIREWALLD_DIRECTtostpathtexistsR2tset_permanent_configt set_directthandle_modulesRtset_nf_conntrack_helper_settingtget_nf_conntrack_helper_settingRPR_tgetDebugLogLevelttimeRtflushR*Rt has_ipsetstexecutetclearR.tunload_firewall_modulestapply_default_tablest apply_ipsetstapply_default_rulest apply_zonest check_zoneR;tchange_default_zonethas_configurationt apply_directtcodetmsgtdebug2(R6treloadtcomplete_reloadt default_zoneRtvalueRtzR1tobjtstatusttm1t transactiontettm2((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt_startsR                                                      +   cCsUy|jWn*tk r:d|_|jdnXd|_|jddS(NtFAILEDtACCEPTtRUNNING(RRR9t set_policy(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytstarts    c Cstjj|sdS|r|jtjr}|dkr}t}tjj||_|j |j||_t |_ qt }nx[t tj |D]D}|jds|jtjr|dkrtjjd||fr|jd||f|dtqqnd||f}tjd||yP|dkrAt||}|j|jjkr|jj|j}tjd||j|j|j|jj|jn!|jjtjrt|_ ny|jj|Wn3tk r$} tjd|jt| fnX|jjtj|nE|d krt||}|j|j j!kr|j j"|j}tjd||j|j|j|j j#|jn!|jjtjrt|_ n|j j$||jj$tj|nx|dkrt%||d |}|rzdtjj|tjj|d d !f|_|j |jntj|} |j|j&j'kr#|j&j(|j}|j&j)|j|j*rtjd ||j|||j+|qMtjd||j|j|jn*|jjtjrMt|_ t| _ n|jj,| |rtjd ||j|||j+|q|j&j,|n|dkrt-||}|j|j.j/kr"|j.j0|j}tjd||j|j|j|j.j1|jn!|jjtjrCt|_ ny|j.j2|Wn3tk r} tj3d|jt| fnX|jj2tj|n|dkrvt4||}|j|j5j6kr)|j5j7|j}tjd||j|j|j|j5j8|jn!|jjtjrJt|_ n|j5j9||jj9tj|ntj:d|Wqtk r} tj;d||| qt<k rtj;d||tj=qXqW|r|j*r|j|j&j'kr|j&j(|j}tjd||j|j|jy|j&j)|jWnt<k rlnX|jj>|jn|j&j,|ndS(NR1s.xmls%s/%stcombinesLoading %s file '%s'R/s Overloads %s '%s' ('%s/%s')s%s: %s, ignoring for run-time.R0t no_check_nameiis Combining %s '%s' ('%s/%s')RR4sUnknown reader type %ssFailed to load %s file '%s': %ssFailed to load %s file '%s':s0 Overloading and deactivating %s '%s' ('%s/%s')(?RRtisdirt startswithRt ETC_FIREWALLDRtbasenametnamet check_nameRGtdefaulttsortedtlistdirtendswithRR RRhRR/Rt get_icmptypeRtremove_icmptypet add_icmptypeRtinfo1tstrRRRR0Rt get_servicetremove_servicet add_serviceRR1Rtget_zonet remove_zonetcombinedRtadd_zoneRRt get_ipsetst get_ipsett remove_ipsett add_ipsetR[RR4t get_helperst get_helpert remove_helpert add_helperR\RRt exceptiont forget_zone( R6Rt reader_typeRt combined_zoneRRRtorig_objRt config_objR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs                                                cCs|jj|jj|jj|jj|jj|jj|jj|jj|j j|j dS(N( R/tcleanupR0R1RR4RR2R3RR5(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRls         cCs>|jr0|j|jd|jjn|jdS(NR(R?RRR.RR(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytstopxs    cCs=|j}x||jkr(|d7}q W|jj||S(Ni(R>R=tappend(R6ti((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytnew_marks  cCs|jj|dS(N(R=tremove(R6tmark((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytdel_marksc Cs"d}d}x t|D]\}}|rF|jj|\}}n4|j|dkrbd}n|jj|\}}|dkr|d7}||7}qn|r|jj|d|j|cd7|j|jn|jrZ|j|jn|jrv|j|jn|S(N( R-RR,R!RR%R$R(R'(R6tbackends((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytenabled_backendss    cCszg}|jr"|j|jn|jr>|j|jn|jrZ|j|jn|jrv|j|jn|S(N( R!RRR%R$R(R'R-R,(R6R ((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs    cCsn|dkrt|}n|}x*|jD]}|j||jq.W|dkrj|jtndS(N(RRR t add_rulestbuild_default_tablesRR (R6RRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs  cCs3|dkrt|}n|}x6|jD](}|j|j}|j||q.W|jdr|jd}|jrd|j kr|j t |j |j |j}|j||y|j t Wn#tk r}tjd|nX|j qn|dkr/|j t ndS(NRWtraws+Applying rules for ipv6_rpfilter failed: %s(RRR tbuild_default_rulesRBRR RYR@RZRR Rtbuild_rpfilter_rulesRRR[(R6RRRtrulest ipv6_backendR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs*     cCs|dkrt|}n|}tjdx0|jD]"}|j}|j||q;W|dkr}|jtndS(NsFlushing rule set( RRRRhRtbuild_flush_rulesRRR (R6RRRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR+s    cCs|dkrt|}n|}tjd|x3|jD]%}|j|}|j||q>W|dkr|jtndS(NsSetting policy to '%s'( RRRRhR tbuild_set_policy_rulesRRR (R6tpolicyRRRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR:s  cCs^|s dS|j|}|s8ttjd|n|j|sKdS|j||jS(NRFs'%s' is not a valid backend(RRRRR tset_ruleRB(R6t backend_nametruleR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRKs c Cs\ttd|}|j|}|sCttjd|n|j|sVdS|js|j s|dkrE|j j rExt |D]\}}y|j ||jWqtk r<}tjtjtj|xLt|| D]:}y |j |j||jWqtk r.qXqW|qXqWtS|j||jSdS(Ns'%s' is not a valid backendRFR(tlistRURRRRRR RARdR'RgRRRBRRRht tracebackt format_excRtreversedt reverse_ruleR t set_rules(R6RRt_rulesRRRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRYs0      cCs|jrttjndS(N(R:RRt PANIC_MODE(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_paniczs cCsV|}| s|dkr(|j}n||jjkrRttj|n|S(NRF(tget_default_zoneR1RRRt INVALID_ZONE(R6R1t_zone((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR~s cCs(tj|s$ttj|ndS(N(RtcheckInterfaceRRtINVALID_INTERFACE(R6t interface((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytcheck_interfacescCs|jj|dS(N(R0t check_service(R6R0((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR+scCs(tj|s$ttj|ndS(N(Rt check_portRRt INVALID_PORT(R6tport((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR,scCsA|sttjn|dkr=ttjd|ndS(Nttcptudptsctptdccps''%s' not in {'tcp'|'udp'|'sctp'|'dccp'}(R/R0R1R2(RRtMISSING_PROTOCOLtINVALID_PROTOCOL(R6tprotocol((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_tcpudps   cCs(tj|s$ttj|ndS(N(RtcheckIPRRt INVALID_ADDR(R6tip((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytcheck_ipscCs||dkr3tj|sxttj|qxnE|dkrftj|sxttj|qxnttjddS(NRVRWs'%s' not in {'ipv4'|'ipv6'}(Rt checkIPnMaskRRR8t checkIP6nMaskR(R6Rtsource((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_addresss   cCs|jj|dS(N(R/tcheck_icmptype(R6ticmp((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR?scCs]t|ts.td|t|fnt|dkrYttjd|ndS(Ns%s is %s, expected intis#timeout '%d' is not positive number(t isinstanceRt TypeErrorttypeRRt INVALID_VALUE(R6ttimeout((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_timeouts  c Cs9|j}i}x1|jjD] }|jj|d||R?RFRRXRPR\R]R^RdReRgR$Rk(((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR>sd     7      $    !         K       (8t__all__tos.pathRR]RRRtfirewallRRt firewall.coreRRRRRtfirewall.core.fw_icmptypeRtfirewall.core.fw_serviceR tfirewall.core.fw_zoneR tfirewall.core.fw_directR tfirewall.core.fw_configR tfirewall.core.fw_policiesR tfirewall.core.fw_ipsetRtfirewall.core.fw_transactionRtfirewall.core.fw_helperRtfirewall.core.loggerRtfirewall.core.io.firewalld_confRtfirewall.core.io.directRtfirewall.core.io.serviceRtfirewall.core.io.icmptypeRtfirewall.core.io.zoneRRtfirewall.core.io.ipsetRtfirewall.core.io.helperRRtfirewall.errorsRtobjectR(((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyts@      PK!  icmp.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2017 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__ = [ "ICMP_TYPES", "ICMPV6_TYPES", "check_icmp_type", "check_icmpv6_type" ] ICMP_TYPES = { "echo-reply": "0/0", "pong": "0/0", "network-unreachable": "3/0", "host-unreachable": "3/1", "protocol-unreachable": "3/2", "port-unreachable": "3/3", "fragmentation-needed": "3/4", "source-route-failed": "3/5", "network-unknown": "3/6", "host-unknown": "3/7", "network-prohibited": "3/9", "host-prohibited": "3/10", "TOS-network-unreachable": "3/11", "TOS-host-unreachable": "3/12", "communication-prohibited": "3/13", "host-precedence-violation": "3/14", "precedence-cutoff": "3/15", "source-quench": "4/0", "network-redirect": "5/0", "host-redirect": "5/1", "TOS-network-redirect": "5/2", "TOS-host-redirect": "5/3", "echo-request": "8/0", "ping": "8/0", "router-advertisement": "9/0", "router-solicitation": "10/0", "ttl-zero-during-transit": "11/0", "ttl-zero-during-reassembly": "11/1", "ip-header-bad": "12/0", "required-option-missing": "12/1", "timestamp-request": "13/0", "timestamp-reply": "14/0", "address-mask-request": "17/0", "address-mask-reply": "18/0", } ICMPV6_TYPES = { "no-route": "1/0", "communication-prohibited": "1/1", "address-unreachable": "1/3", "port-unreachable": "1/4", "packet-too-big": "2/0", "ttl-zero-during-transit": "3/0", "ttl-zero-during-reassembly": "3/1", "bad-header": "4/0", "unknown-header-type": "4/1", "unknown-option": "4/2", "echo-request": "128/0", "ping": "128/0", "echo-reply": "129/0", "pong": "129/0", "router-solicitation": "133/0", "router-advertisement": "134/0", "neighbour-solicitation": "135/0", "neigbour-solicitation": "135/0", "neighbour-advertisement": "136/0", "neigbour-advertisement": "136/0", "redirect": "137/0", } def check_icmp_name(_name): if _name in ICMP_TYPES: return True return False def check_icmp_type(_type): if _type in ICMP_TYPES.values(): return True return False def check_icmpv6_name(_name): if _name in ICMP_TYPES: return True return False def check_icmpv6_type(_type): if _type in ICMPV6_TYPES.values(): return True return False PK!H modules.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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 . # """modules backend""" __all__ = [ "modules" ] from firewall.core.prog import runProg from firewall.core.logger import log from firewall.config import COMMANDS class modules(object): def __init__(self): self._load_command = COMMANDS["modprobe"] # Use rmmod instead of modprobe -r (RHBZ#1031102) self._unload_command = COMMANDS["rmmod"] def __repr__(self): return '%s' % (self.__class__) def loaded_modules(self): """ get all loaded kernel modules and their dependencies """ mods = [ ] deps = { } with open("/proc/modules", "r") as f: for line in f: if not line: break line = line.strip() splits = line.split() mods.append(splits[0]) if splits[3] != "-": deps[splits[0]] = splits[3].split(",")[:-1] else: deps[splits[0]] = [ ] return mods, deps # [loaded modules], {module:[dependants]} def load_module(self, module): log.debug2("%s: %s %s", self.__class__, self._load_command, module) return runProg(self._load_command, [ module ]) def unload_module(self, module): log.debug2("%s: %s %s", self.__class__, self._unload_command, module) return runProg(self._unload_command, [ module ]) def get_deps(self, module, deps, ret): """ get all dependants of a module """ if module not in deps: return for mod in deps[module]: self.get_deps(mod, deps, ret) if mod not in ret: ret.append(mod) if module not in ret: ret.append(module) def get_firewall_modules(self): """ get all loaded firewall-related modules """ mods = [ ] (mods2, deps) = self.loaded_modules() self.get_deps("nf_conntrack", deps, mods) # these modules don't have dependants listed in /proc/modules for bad_bad_module in ["nf_conntrack_ipv4", "nf_conntrack_ipv6"]: if bad_bad_module in mods: # move them to end of list, so we'll remove them later mods.remove(bad_bad_module) mods.insert(-1, bad_bad_module) for mod in mods2: if mod in [ "ip_tables", "ip6_tables", "ebtables" ] or \ mod.startswith("iptable_") or mod.startswith("ip6table_") or \ mod.startswith("nf_") or mod.startswith("xt_") or \ mod.startswith("ipt_") or mod.startswith("ip6t_") : self.get_deps(mod, deps, mods) return mods def unload_firewall_modules(self): """ unload all firewall-related modules """ for module in self.get_firewall_modules(): (status, ret) = self.unload_module(module) if status != 0: log.debug1("Failed to unload module '%s': %s" %(module, ret)) PK!xbase.pynu[# -*- 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 . # """Base firewall settings""" DEFAULT_ZONE_TARGET = "{chain}_{zone}" ZONE_TARGETS = [ "ACCEPT", "%%REJECT%%", "DROP", DEFAULT_ZONE_TARGET, "default" ] SHORTCUTS = { "PREROUTING": "PRE", "POSTROUTING": "POST", "INPUT": "IN", "FORWARD_IN": "FWDI", "FORWARD_OUT": "FWDO", "OUTPUT": "OUT", } REJECT_TYPES = { "ipv4": [ "icmp-host-prohibited", "host-prohib", "icmp-net-unreachable", "net-unreach", "icmp-host-unreachable", "host-unreach", "icmp-port-unreachable", "port-unreach", "icmp-proto-unreachable", "proto-unreach", "icmp-net-prohibited", "net-prohib", "tcp-reset", "tcp-rst", "icmp-admin-prohibited", "admin-prohib" ], "ipv6": [ "icmp6-adm-prohibited", "adm-prohibited", "icmp6-no-route", "no-route", "icmp6-addr-unreachable", "addr-unreach", "icmp6-port-unreachable", "port-unreach", "tcp-reset" ] } # ipset types that can be used as a source in zones # The match-set option will be src or src,src according to the # dimension of the ipset. ZONE_SOURCE_IPSET_TYPES = [ "hash:ip", "hash:ip,port", "hash:ip,mark", "hash:net", "hash:net,port", "hash:net,iface", "hash:mac" ] PK!\ }XuXurich.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2013-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__ = [ "Rich_Source", "Rich_Destination", "Rich_Service", "Rich_Port", "Rich_Protocol", "Rich_Masquerade", "Rich_IcmpBlock", "Rich_IcmpType", "Rich_SourcePort", "Rich_ForwardPort", "Rich_Log", "Rich_Audit", "Rich_Accept", "Rich_Reject", "Rich_Drop", "Rich_Mark", "Rich_Limit", "Rich_Rule" ] from firewall import functions from firewall.core.ipset import check_ipset_name from firewall.core.base import REJECT_TYPES from firewall import errors from firewall.errors import FirewallError class Rich_Source(object): def __init__(self, addr, mac, ipset, invert=False): self.addr = addr if self.addr == "": self.addr = None self.mac = mac if self.mac == "" or self.mac is None: self.mac = None elif self.mac is not None: self.mac = self.mac.upper() self.ipset = ipset if self.ipset == "": self.ipset = None self.invert = invert if self.addr is None and self.mac is None and self.ipset is None: raise FirewallError(errors.INVALID_RULE, "no address, mac and ipset") def __str__(self): ret = 'source%s ' % (" NOT" if self.invert else "") if self.addr is not None: return ret + 'address="%s"' % self.addr elif self.mac is not None: return ret + 'mac="%s"' % self.mac elif self.ipset is not None: return ret + 'ipset="%s"' % self.ipset else: raise FirewallError(errors.INVALID_RULE, "no address, mac and ipset") class Rich_Destination(object): def __init__(self, addr, invert=False): self.addr = addr self.invert = invert def __str__(self): return 'destination %saddress="%s"' % ("not " if self.invert else "", self.addr) class Rich_Service(object): def __init__(self, name): self.name = name def __str__(self): return 'service name="%s"' % (self.name) class Rich_Port(object): def __init__(self, port, protocol): self.port = port self.protocol = protocol def __str__(self): return 'port port="%s" protocol="%s"' % (self.port, self.protocol) class Rich_SourcePort(Rich_Port): def __str__(self): return 'source-port port="%s" protocol="%s"' % (self.port, self.protocol) class Rich_Protocol(object): def __init__(self, value): self.value = value def __str__(self): return 'protocol value="%s"' % (self.value) class Rich_Masquerade(object): def __init__(self): pass def __str__(self): return 'masquerade' class Rich_IcmpBlock(object): def __init__(self, name): self.name = name def __str__(self): return 'icmp-block name="%s"' % (self.name) class Rich_IcmpType(object): def __init__(self, name): self.name = name def __str__(self): return 'icmp-type name="%s"' % (self.name) class Rich_ForwardPort(object): def __init__(self, port, protocol, to_port, to_address): self.port = port self.protocol = protocol self.to_port = to_port self.to_address = to_address # replace None with "" in to_port and/or to_address if self.to_port is None: self.to_port = "" if self.to_address is None: self.to_address = "" def __str__(self): return 'forward-port port="%s" protocol="%s"%s%s' % \ (self.port, self.protocol, ' to-port="%s"' % self.to_port if self.to_port != "" else '', ' to-addr="%s"' % self.to_address if self.to_address != "" else '') class Rich_Log(object): def __init__(self, prefix=None, level=None, limit=None): #TODO check default level in iptables self.prefix = prefix self.level = level self.limit = limit def __str__(self): return 'log%s%s%s' % \ (' prefix="%s"' % (self.prefix) if self.prefix else "", ' level="%s"' % (self.level) if self.level else "", " %s" % self.limit if self.limit else "") class Rich_Audit(object): def __init__(self, limit=None): #TODO check default level in iptables self.limit = limit def __str__(self): return 'audit%s' % (" %s" % self.limit if self.limit else "") class Rich_Accept(object): def __init__(self, limit=None): self.limit = limit def __str__(self): return "accept%s" % (" %s" % self.limit if self.limit else "") class Rich_Reject(object): def __init__(self, _type=None, limit=None): self.type = _type self.limit = limit def __str__(self): return "reject%s%s" % (' type="%s"' % self.type if self.type else "", " %s" % self.limit if self.limit else "") def check(self, family): if self.type: if not family: raise FirewallError(errors.INVALID_RULE, "When using reject type you must specify also rule family.") if family in ['ipv4', 'ipv6'] and \ self.type not in REJECT_TYPES[family]: valid_types = ", ".join(REJECT_TYPES[family]) raise FirewallError(errors.INVALID_RULE, "Wrong reject type %s.\nUse one of: %s." % (self.type, valid_types)) class Rich_Drop(Rich_Accept): def __str__(self): return "drop%s" % (" %s" % self.limit if self.limit else "") class Rich_Mark(object): def __init__(self, _set, limit=None): self.set = _set self.limit = limit def __str__(self): return "mark set=%s%s" % (self.set, " %s" % self.limit if self.limit else "") def check(self): if self.set is not None: x = self.set else: raise FirewallError(errors.INVALID_MARK, "no value set") if "/" in x: splits = x.split("/") if len(splits) != 2: raise FirewallError(errors.INVALID_MARK, x) if not functions.checkUINT32(splits[0]) or \ not functions.checkUINT32(splits[1]): # value and mask are uint32 raise FirewallError(errors.INVALID_MARK, x) else: if not functions.checkUINT32(x): # value is uint32 raise FirewallError(errors.INVALID_MARK, x) class Rich_Limit(object): def __init__(self, value): self.value = value if "/" in self.value: splits = self.value.split("/") if len(splits) == 2 and \ splits[1] in [ "second", "minute", "hour", "day" ]: self.value = "%s/%s" % (splits[0], splits[1][:1]) def check(self): splits = None if "/" in self.value: splits = self.value.split("/") if not splits or len(splits) != 2: raise FirewallError(errors.INVALID_LIMIT, self.value) (rate, duration) = splits try: rate = int(rate) except: raise FirewallError(errors.INVALID_LIMIT, self.value) if rate < 1 or duration not in [ "s", "m", "h", "d" ]: raise FirewallError(errors.INVALID_LIMIT, self.value) mult = 1 if duration == "s": mult = 1 elif duration == "m": mult = 60 elif duration == "h": mult = 60*60 elif duration == "d": mult = 24*60*60 if 10000 * mult / rate == 0: raise FirewallError(errors.INVALID_LIMIT, "%s too fast" % self.value) if rate == 1 and duration == "d": # iptables (v1.4.21) doesn't accept 1/d raise FirewallError(errors.INVALID_LIMIT, "%s too slow" % self.value) def __str__(self): return 'limit value="%s"' % (self.value) def command(self): return '' class Rich_Rule(object): def __init__(self, family=None, rule_str=None): if family is not None: self.family = str(family) else: self.family = None self.source = None self.destination = None self.element = None self.log = None self.audit = None self.action = None if rule_str: self._import_from_string(rule_str) def _lexer(self, rule_str): """ Lexical analysis """ tokens = [] for r in functions.splitArgs(rule_str): if "=" in r: attr = r.split('=') if len(attr) != 2 or not attr[0] or not attr[1]: raise FirewallError(errors.INVALID_RULE, 'internal error in _lexer(): %s' % r) tokens.append({'attr_name':attr[0], 'attr_value':attr[1]}) else: tokens.append({'element':r}) tokens.append({'element':'EOL'}) return tokens def _import_from_string(self, rule_str): if not rule_str: raise FirewallError(errors.INVALID_RULE, 'empty rule') self.family = None self.source = None self.destination = None self.element = None self.log = None self.audit = None self.action = None tokens = self._lexer(rule_str) if tokens and tokens[0].get('element') == 'EOL': raise FirewallError(errors.INVALID_RULE, 'empty rule') attrs = {} # attributes of elements in_elements = [] # stack with elements we are in index = 0 # index into tokens while not (tokens[index].get('element') == 'EOL' and in_elements == ['rule']): element = tokens[index].get('element') attr_name = tokens[index].get('attr_name') attr_value = tokens[index].get('attr_value') #print ("in_elements: ", in_elements) #print ("index: %s, element: %s, attribute: %s=%s" % (index, element, attr_name, attr_value)) if attr_name: # attribute if attr_name not in ['family', 'address', 'mac', 'ipset', 'invert', 'value', 'port', 'protocol', 'to-port', 'to-addr', 'name', 'prefix', 'level', 'type', 'set']: raise FirewallError(errors.INVALID_RULE, "bad attribute '%s'" % attr_name) else: # element if element in ['rule', 'source', 'destination', 'protocol', 'service', 'port', 'icmp-block', 'icmp-type', 'masquerade', 'forward-port', 'source-port', 'log', 'audit', 'accept', 'drop', 'reject', 'mark', 'limit', 'not', 'NOT', 'EOL']: if element == 'source' and self.source: raise FirewallError(errors.INVALID_RULE, "more than one 'source' element") elif element == 'destination' and self.destination: raise FirewallError(errors.INVALID_RULE, "more than one 'destination' element") elif element in ['protocol', 'service', 'port', 'icmp-block', 'icmp-type', 'masquerade', 'forward-port', 'source-port'] and self.element: raise FirewallError(errors.INVALID_RULE, "more than one element. There cannot be both '%s' and '%s' in one rule." % (element, self.element)) elif element == 'log' and self.log: raise FirewallError(errors.INVALID_RULE, "more than one 'log' element") elif element == 'audit' and self.audit: raise FirewallError(errors.INVALID_RULE, "more than one 'audit' element") elif element in ['accept', 'drop', 'reject', 'mark'] and self.action: raise FirewallError(errors.INVALID_RULE, "more than one 'action' element. There cannot be both '%s' and '%s' in one rule." % (element, self.action)) else: raise FirewallError(errors.INVALID_RULE, "unknown element %s" % element) in_element = in_elements[len(in_elements)-1] if len(in_elements) > 0 else '' if in_element == '': if not element and attr_name: if attr_name == 'family': raise FirewallError(errors.INVALID_RULE, "'family' outside of rule. Use 'rule family=...'.") else: raise FirewallError(errors.INVALID_RULE, "'%s' outside of any element. Use 'rule %s= ...'." % (attr_name, attr_name)) elif 'rule' not in element: raise FirewallError(errors.INVALID_RULE, "'%s' outside of rule. Use 'rule ... %s ...'." % (element, element)) else: in_elements.append('rule') # push into stack elif in_element == 'rule': if attr_name == 'family': if attr_value not in ['ipv4', 'ipv6']: raise FirewallError(errors.INVALID_RULE, "'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead." % attr_value) self.family = attr_value elif attr_name: if attr_name == 'protocol': err_msg = "wrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'." else: err_msg = "attribute '%s' outside of any element. Use 'rule %s= ...'." % (attr_name, attr_name) raise FirewallError(errors.INVALID_RULE, err_msg) else: in_elements.append(element) # push into stack elif in_element == 'source': if attr_name in ['address', 'mac', 'ipset', 'invert']: attrs[attr_name] = attr_value elif element in ['not', 'NOT']: attrs['invert'] = True else: self.source = Rich_Source(attrs.get('address'), attrs.get('mac'), attrs.get('ipset'), attrs.get('invert', False)) in_elements.pop() # source attrs.clear() index = index -1 # return token to input elif in_element == 'destination': if attr_name in ['address', 'invert']: attrs[attr_name] = attr_value elif element in ['not', 'NOT']: attrs['invert'] = True else: self.destination = Rich_Destination(attrs.get('address'), attrs.get('invert')) in_elements.pop() # destination attrs.clear() index = index -1 # return token to input elif in_element == 'protocol': if attr_name == 'value': self.element = Rich_Protocol(attr_value) in_elements.pop() # protocol else: raise FirewallError(errors.INVALID_RULE, "invalid 'protocol' element") elif in_element == 'service': if attr_name == 'name': self.element = Rich_Service(attr_value) in_elements.pop() # service else: raise FirewallError(errors.INVALID_RULE, "invalid 'service' element") elif in_element == 'port': if attr_name in ['port', 'protocol']: attrs[attr_name] = attr_value else: self.element = Rich_Port(attrs.get('port'), attrs.get('protocol')) in_elements.pop() # port attrs.clear() index = index -1 # return token to input elif in_element == 'icmp-block': if attr_name == 'name': self.element = Rich_IcmpBlock(attr_value) in_elements.pop() # icmp-block else: raise FirewallError(errors.INVALID_RULE, "invalid 'icmp-block' element") elif in_element == 'icmp-type': if attr_name == 'name': self.element = Rich_IcmpType(attr_value) in_elements.pop() # icmp-type else: raise FirewallError(errors.INVALID_RULE, "invalid 'icmp-type' element") elif in_element == 'masquerade': self.element = Rich_Masquerade() in_elements.pop() attrs.clear() index = index -1 # return token to input elif in_element == 'forward-port': if attr_name in ['port', 'protocol', 'to-port', 'to-addr']: attrs[attr_name] = attr_value else: self.element = Rich_ForwardPort(attrs.get('port'), attrs.get('protocol'), attrs.get('to-port'), attrs.get('to-addr')) in_elements.pop() # forward-port attrs.clear() index = index -1 # return token to input elif in_element == 'source-port': if attr_name in ['port', 'protocol']: attrs[attr_name] = attr_value else: self.element = Rich_SourcePort(attrs.get('port'), attrs.get('protocol')) in_elements.pop() # source-port attrs.clear() index = index -1 # return token to input elif in_element == 'log': if attr_name in ['prefix', 'level']: attrs[attr_name] = attr_value elif element == 'limit': in_elements.append('limit') else: self.log = Rich_Log(attrs.get('prefix'), attrs.get('level'), attrs.get('limit')) in_elements.pop() # log attrs.clear() index = index -1 # return token to input elif in_element == 'audit': if element == 'limit': in_elements.append('limit') else: self.audit = Rich_Audit(attrs.get('limit')) in_elements.pop() # audit attrs.clear() index = index -1 # return token to input elif in_element == 'accept': if element == 'limit': in_elements.append('limit') else: self.action = Rich_Accept(attrs.get('limit')) in_elements.pop() # accept attrs.clear() index = index -1 # return token to input elif in_element == 'drop': if element == 'limit': in_elements.append('limit') else: self.action = Rich_Drop(attrs.get('limit')) in_elements.pop() # drop attrs.clear() index = index -1 # return token to input elif in_element == 'reject': if attr_name == 'type': attrs[attr_name] = attr_value elif element == 'limit': in_elements.append('limit') else: self.action = Rich_Reject(attrs.get('type'), attrs.get('limit')) in_elements.pop() # accept attrs.clear() index = index -1 # return token to input elif in_element == 'mark': if attr_name == 'set': attrs[attr_name] = attr_value elif element == 'limit': in_elements.append('limit') else: self.action = Rich_Mark(attrs.get('set'), attrs.get('limit')) in_elements.pop() # accept attrs.clear() index = index -1 # return token to input elif in_element == 'limit': if attr_name == 'value': attrs['limit'] = Rich_Limit(attr_value) in_elements.pop() # limit else: raise FirewallError(errors.INVALID_RULE, "invalid 'limit' element") index = index + 1 self.check() def check(self): if self.family is not None and self.family not in [ "ipv4", "ipv6" ]: raise FirewallError(errors.INVALID_FAMILY, self.family) if self.family is None: if (self.source is not None and self.source.addr is not None) or \ self.destination is not None: raise FirewallError(errors.MISSING_FAMILY) if type(self.element) == Rich_ForwardPort: raise FirewallError(errors.MISSING_FAMILY) if self.element is None: if self.action is None: raise FirewallError(errors.INVALID_RULE, "no element, no action") if self.source is None and self.destination is None: raise FirewallError(errors.INVALID_RULE, "no element, no source, no destination") if type(self.element) not in [ Rich_IcmpBlock, Rich_ForwardPort, Rich_Masquerade ]: if self.log is None and self.audit is None and \ self.action is None: raise FirewallError(errors.INVALID_RULE, "no action, no log, no audit") # source if self.source is not None: if self.source.addr is not None: if self.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.source.mac is not None: raise FirewallError(errors.INVALID_RULE, "address and mac") if self.source.ipset is not None: raise FirewallError(errors.INVALID_RULE, "address and ipset") if not functions.check_address(self.family, self.source.addr): raise FirewallError(errors.INVALID_ADDR, str(self.source.addr)) elif self.source.mac is not None: if self.source.ipset is not None: raise FirewallError(errors.INVALID_RULE, "mac and ipset") if not functions.check_mac(self.source.mac): raise FirewallError(errors.INVALID_MAC, str(self.source.mac)) elif self.source.ipset is not None: if not check_ipset_name(self.source.ipset): raise FirewallError(errors.INVALID_IPSET, str(self.source.ipset)) else: raise FirewallError(errors.INVALID_RULE, "invalid source") # destination if self.destination is not None: if self.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.destination.addr is None or \ not functions.check_address(self.family, self.destination.addr): raise FirewallError(errors.INVALID_ADDR, str(self.destination.addr)) # service if type(self.element) == Rich_Service: # service availability needs to be checked in Firewall, here is no # knowledge about this, therefore only simple check if self.element.name is None or len(self.element.name) < 1: raise FirewallError(errors.INVALID_SERVICE, str(self.element.name)) # port elif type(self.element) == Rich_Port: if not functions.check_port(self.element.port): raise FirewallError(errors.INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol) # protocol elif type(self.element) == Rich_Protocol: if not functions.checkProtocol(self.element.value): raise FirewallError(errors.INVALID_PROTOCOL, self.element.value) # masquerade elif type(self.element) == Rich_Masquerade: if self.action is not None: raise FirewallError(errors.INVALID_RULE, "masquerade and action") if self.source is not None and self.source.mac is not None: raise FirewallError(errors.INVALID_RULE, "masquerade and mac source") # icmp-block elif type(self.element) == Rich_IcmpBlock: # icmp type availability needs to be checked in Firewall, here is no # knowledge about this, therefore only simple check if self.element.name is None or len(self.element.name) < 1: raise FirewallError(errors.INVALID_ICMPTYPE, str(self.element.name)) if self.action: raise FirewallError(errors.INVALID_RULE, "icmp-block and action") # icmp-type elif type(self.element) == Rich_IcmpType: # icmp type availability needs to be checked in Firewall, here is no # knowledge about this, therefore only simple check if self.element.name is None or len(self.element.name) < 1: raise FirewallError(errors.INVALID_ICMPTYPE, str(self.element.name)) # forward-port elif type(self.element) == Rich_ForwardPort: if not functions.check_port(self.element.port): raise FirewallError(errors.INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol) if self.element.to_port == "" and self.element.to_address == "": raise FirewallError(errors.INVALID_PORT, self.element.to_port) if self.element.to_port != "" and \ not functions.check_port(self.element.to_port): raise FirewallError(errors.INVALID_PORT, self.element.to_port) if self.element.to_address != "" and \ not functions.check_single_address(self.family, self.element.to_address): raise FirewallError(errors.INVALID_ADDR, self.element.to_address) if self.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.action is not None: raise FirewallError(errors.INVALID_RULE, "forward-port and action") # source-port elif type(self.element) == Rich_SourcePort: if not functions.check_port(self.element.port): raise FirewallError(errors.INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol) # other element and not empty? elif self.element is not None: raise FirewallError(errors.INVALID_RULE, "Unknown element %s" % type(self.element)) # log if self.log is not None: if self.log.level and \ self.log.level not in [ "emerg", "alert", "crit", "error", "warning", "notice", "info", "debug" ]: raise FirewallError(errors.INVALID_LOG_LEVEL, self.log.level) if self.log.limit is not None: self.log.limit.check() # audit if self.audit is not None: if type(self.action) not in [ Rich_Accept, Rich_Reject, Rich_Drop ]: raise FirewallError(errors.INVALID_AUDIT_TYPE, type(self.action)) if self.audit.limit is not None: self.audit.limit.check() # action if self.action is not None: if type(self.action) == Rich_Reject: self.action.check(self.family) elif type(self.action) == Rich_Mark: self.action.check() if self.action.limit is not None: self.action.limit.check() def __str__(self): ret = 'rule' if self.family: ret += ' family="%s"' % self.family if self.source: ret += " %s" % self.source if self.destination: ret += " %s" % self.destination if self.element: ret += " %s" % self.element if self.log: ret += " %s" % self.log if self.audit: ret += " %s" % self.audit if self.action: ret += " %s" % self.action return (functions.u2b(ret)) if functions.PY2 else ret #class Rich_RawRule(object): #class Rich_RuleSet(object): #class Rich_AddressList(object): PK!1 fw_policies.pynu[# -*- 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__ = [ "FirewallPolicies" ] from firewall import config from firewall.core.logger import log from firewall.core.io.lockdown_whitelist import LockdownWhitelist from firewall import errors from firewall.errors import FirewallError class FirewallPolicies(object): def __init__(self): self._lockdown = False self.lockdown_whitelist = LockdownWhitelist(config.LOCKDOWN_WHITELIST) def __repr__(self): return '%s(%r, %r)' % (self.__class__, self._lockdown, self.lockdown_whitelist) def cleanup(self): self._lockdown = False self.lockdown_whitelist.cleanup() # lockdown def access_check(self, key, value): if key == "context": log.debug2('Doing access check for context "%s"' % value) if self.lockdown_whitelist.match_context(value): log.debug3('context matches.') return True elif key == "uid": log.debug2('Doing access check for uid %d' % value) if self.lockdown_whitelist.match_uid(value): log.debug3('uid matches.') return True elif key == "user": log.debug2('Doing access check for user "%s"' % value) if self.lockdown_whitelist.match_user(value): log.debug3('user matches.') return True elif key == "command": log.debug2('Doing access check for command "%s"' % value) if self.lockdown_whitelist.match_command(value): log.debug3('command matches.') return True return False def enable_lockdown(self): if self._lockdown: raise FirewallError(errors.ALREADY_ENABLED, "enable_lockdown()") self._lockdown = True def disable_lockdown(self): if not self._lockdown: raise FirewallError(errors.NOT_ENABLED, "disable_lockdown()") self._lockdown = False def query_lockdown(self): return self._lockdown PK!Uu))base.pycnu[ c`c@sdZdZdddedgZidd6dd 6d d 6d d 6dd6dd6Ziddddddddddddddd d!gd"6d#d$d%d&d'd(d)ddg d*6Zd+d,d-d.d/d0d1gZd2S(3sBase firewall settingss{chain}_{zone}tACCEPTs %%REJECT%%tDROPtdefaulttPREt PREROUTINGtPOSTt POSTROUTINGtINtINPUTtFWDIt FORWARD_INtFWDOt FORWARD_OUTtOUTtOUTPUTsicmp-host-prohibiteds host-prohibsicmp-net-unreachables net-unreachsicmp-host-unreachables host-unreachsicmp-port-unreachables port-unreachsicmp-proto-unreachables proto-unreachsicmp-net-prohibiteds net-prohibs tcp-resetstcp-rstsicmp-admin-prohibiteds admin-prohibtipv4sicmp6-adm-prohibitedsadm-prohibitedsicmp6-no-routesno-routesicmp6-addr-unreachables addr-unreachsicmp6-port-unreachabletipv6shash:ips hash:ip,ports hash:ip,markshash:nets hash:net,portshash:net,ifaceshash:macN(t__doc__tDEFAULT_ZONE_TARGETt ZONE_TARGETSt SHORTCUTSt REJECT_TYPEStZONE_SOURCE_IPSET_TYPES(((s6/usr/lib/python2.7/site-packages/firewall/core/base.pyts,           PK!|QӮӮfw.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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__ = [ "Firewall" ] import os.path import sys import copy import time import traceback from firewall import config from firewall import functions from firewall.core import ipXtables from firewall.core import ebtables from firewall.core import nftables from firewall.core import ipset from firewall.core import modules from firewall.core.fw_icmptype import FirewallIcmpType from firewall.core.fw_service import FirewallService from firewall.core.fw_zone import FirewallZone from firewall.core.fw_direct import FirewallDirect from firewall.core.fw_config import FirewallConfig from firewall.core.fw_policies import FirewallPolicies from firewall.core.fw_ipset import FirewallIPSet from firewall.core.fw_transaction import FirewallTransaction from firewall.core.fw_helper import FirewallHelper from firewall.core.logger import log from firewall.core.io.firewalld_conf import firewalld_conf from firewall.core.io.direct import Direct from firewall.core.io.service import service_reader from firewall.core.io.icmptype import icmptype_reader from firewall.core.io.zone import zone_reader, Zone from firewall.core.io.ipset import ipset_reader from firewall.core.io.helper import helper_reader from firewall import errors from firewall.errors import FirewallError ############################################################################ # # class Firewall # ############################################################################ class Firewall(object): def __init__(self): self._firewalld_conf = firewalld_conf(config.FIREWALLD_CONF) self.ip4tables_backend = ipXtables.ip4tables(self) self.ip4tables_enabled = True self.ip4tables_supported_icmp_types = [ ] self.ip6tables_backend = ipXtables.ip6tables(self) self.ip6tables_enabled = True self.ip6tables_supported_icmp_types = [ ] self.ebtables_backend = ebtables.ebtables() self.ebtables_enabled = True self.ipset_backend = ipset.ipset() self.ipset_enabled = True self.ipset_supported_types = [ ] self.nftables_backend = nftables.nftables(self) self.nftables_enabled = True self.modules_backend = modules.modules() self.icmptype = FirewallIcmpType(self) self.service = FirewallService(self) self.zone = FirewallZone(self) self.direct = FirewallDirect(self) self.config = FirewallConfig(self) self.policies = FirewallPolicies() self.ipset = FirewallIPSet(self) self.helper = FirewallHelper(self) self.__init_vars() def __repr__(self): return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \ (self.__class__, self.ip4tables_enabled, self.ip6tables_enabled, self.ebtables_enabled, self._state, self._panic, self._default_zone, self._module_refcount, self._marks, self._min_mark, self.cleanup_on_exit, self.ipv6_rpfilter_enabled, self.ipset_enabled, self._individual_calls, self._log_denied, self._automatic_helpers) def __init_vars(self): self._state = "INIT" self._panic = False self._default_zone = "" self._module_refcount = { } self._marks = [ ] # fallback settings will be overloaded by firewalld.conf self._min_mark = config.FALLBACK_MINIMAL_MARK self.cleanup_on_exit = config.FALLBACK_CLEANUP_ON_EXIT self.ipv6_rpfilter_enabled = config.FALLBACK_IPV6_RPFILTER self._individual_calls = config.FALLBACK_INDIVIDUAL_CALLS self._log_denied = config.FALLBACK_LOG_DENIED self._automatic_helpers = config.FALLBACK_AUTOMATIC_HELPERS self._firewall_backend = config.FALLBACK_FIREWALL_BACKEND self.nf_conntrack_helper_setting = 0 self._allow_zone_drifting = config.FALLBACK_ALLOW_ZONE_DRIFTING def individual_calls(self): return self._individual_calls def _check_tables(self): # check if iptables, ip6tables and ebtables are usable, else disable if self.ip4tables_enabled and \ "filter" not in self.get_backend_by_ipv("ipv4").get_available_tables(): log.warning("iptables not usable, disabling IPv4 firewall.") self.ip4tables_enabled = False if self.ip6tables_enabled and \ "filter" not in self.get_backend_by_ipv("ipv6").get_available_tables(): log.warning("ip6tables not usable, disabling IPv6 firewall.") self.ip6tables_enabled = False if self.ebtables_enabled and \ "filter" not in self.get_backend_by_ipv("eb").get_available_tables(): log.warning("ebtables not usable, disabling ethernet bridge firewall.") self.ebtables_enabled = False # is there at least support for ipv4 or ipv6 if not self.ip4tables_enabled and not self.ip6tables_enabled \ and not self.nftables_enabled: log.fatal("No IPv4 and IPv6 firewall.") sys.exit(1) def _start_check(self): try: self.ipset_backend.set_list() except ValueError: log.warning("ipset not usable, disabling ipset usage in firewall.") # ipset is not usable, no supported types self.ipset_enabled = False self.ipset_supported_types = [ ] else: # ipset is usable, get all supported types self.ipset_supported_types = self.ipset_backend.set_supported_types() self.ip4tables_backend.fill_exists() if not self.ip4tables_backend.restore_command_exists: if self.ip4tables_backend.command_exists: log.warning("iptables-restore is missing, using " "individual calls for IPv4 firewall.") else: log.warning("iptables-restore and iptables are missing, " "disabling IPv4 firewall.") self.ip4tables_enabled = False if self.ip4tables_enabled: self.ip4tables_supported_icmp_types = \ self.ip4tables_backend.supported_icmp_types() else: self.ip4tables_supported_icmp_types = [ ] self.ip6tables_backend.fill_exists() if not self.ip6tables_backend.restore_command_exists: if self.ip6tables_backend.command_exists: log.warning("ip6tables-restore is missing, using " "individual calls for IPv6 firewall.") else: log.warning("ip6tables-restore and ip6tables are missing, " "disabling IPv6 firewall.") self.ip6tables_enabled = False if self.ip6tables_enabled: self.ip6tables_supported_icmp_types = \ self.ip6tables_backend.supported_icmp_types() else: self.ip6tables_supported_icmp_types = [ ] self.ebtables_backend.fill_exists() if not self.ebtables_backend.restore_command_exists: if self.ebtables_backend.command_exists: log.warning("ebtables-restore is missing, using " "individual calls for bridge firewall.") else: log.warning("ebtables-restore and ebtables are missing, " "disabling bridge firewall.") self.ebtables_enabled = False if self.ebtables_enabled and not self._individual_calls and \ not self.ebtables_backend.restore_noflush_option: log.debug1("ebtables-restore is not supporting the --noflush " "option, will therefore not be used") def _start(self, reload=False, complete_reload=False): # initialize firewall default_zone = config.FALLBACK_ZONE # load firewalld config log.debug1("Loading firewalld config file '%s'", config.FIREWALLD_CONF) try: self._firewalld_conf.read() except Exception as msg: log.warning(msg) log.warning("Using fallback firewalld configuration settings.") else: if self._firewalld_conf.get("DefaultZone"): default_zone = self._firewalld_conf.get("DefaultZone") if self._firewalld_conf.get("MinimalMark"): self._min_mark = int(self._firewalld_conf.get("MinimalMark")) if self._firewalld_conf.get("CleanupOnExit"): value = self._firewalld_conf.get("CleanupOnExit") if value is not None and value.lower() in [ "no", "false" ]: self.cleanup_on_exit = False log.debug1("CleanupOnExit is set to '%s'", self.cleanup_on_exit) if self._firewalld_conf.get("Lockdown"): value = self._firewalld_conf.get("Lockdown") if value is not None and value.lower() in [ "yes", "true" ]: log.debug1("Lockdown is enabled") try: self.policies.enable_lockdown() except FirewallError: # already enabled, this is probably reload pass if self._firewalld_conf.get("IPv6_rpfilter"): value = self._firewalld_conf.get("IPv6_rpfilter") if value is not None: if value.lower() in [ "no", "false" ]: self.ipv6_rpfilter_enabled = False if value.lower() in [ "yes", "true" ]: self.ipv6_rpfilter_enabled = True if self.ipv6_rpfilter_enabled: log.debug1("IPv6 rpfilter is enabled") else: log.debug1("IPV6 rpfilter is disabled") if self._firewalld_conf.get("IndividualCalls"): value = self._firewalld_conf.get("IndividualCalls") if value is not None and value.lower() in [ "yes", "true" ]: log.debug1("IndividualCalls is enabled") self._individual_calls = True if self._firewalld_conf.get("LogDenied"): value = self._firewalld_conf.get("LogDenied") if value is None or value.lower() == "no": self._log_denied = "off" else: self._log_denied = value.lower() log.debug1("LogDenied is set to '%s'", self._log_denied) if self._firewalld_conf.get("AutomaticHelpers"): value = self._firewalld_conf.get("AutomaticHelpers") if value is not None: if value.lower() in [ "no", "false" ]: self._automatic_helpers = "no" elif value.lower() in [ "yes", "true" ]: self._automatic_helpers = "yes" else: self._automatic_helpers = value.lower() log.debug1("AutomaticHelpers is set to '%s'", self._automatic_helpers) if self._firewalld_conf.get("AllowZoneDrifting"): value = self._firewalld_conf.get("AllowZoneDrifting") if value.lower() in [ "no", "false" ]: self._allow_zone_drifting = False else: self._allow_zone_drifting = True log.warning("AllowZoneDrifting is enabled. This is considered " "an insecure configuration option. It will be " "removed in a future release. Please consider " "disabling it now.") log.debug1("AllowZoneDrifting is set to '%s'", self._allow_zone_drifting) self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf)) self._select_firewall_backend(self._firewall_backend) self._start_check() # load lockdown whitelist log.debug1("Loading lockdown whitelist") try: self.policies.lockdown_whitelist.read() except Exception as msg: if self.policies.query_lockdown(): log.error("Failed to load lockdown whitelist '%s': %s", self.policies.lockdown_whitelist.filename, msg) else: log.debug1("Failed to load lockdown whitelist '%s': %s", self.policies.lockdown_whitelist.filename, msg) # copy policies to config interface self.config.set_policies(copy.deepcopy(self.policies)) # load ipset files self._loader(config.FIREWALLD_IPSETS, "ipset") self._loader(config.ETC_FIREWALLD_IPSETS, "ipset") # load icmptype files self._loader(config.FIREWALLD_ICMPTYPES, "icmptype") self._loader(config.ETC_FIREWALLD_ICMPTYPES, "icmptype") if len(self.icmptype.get_icmptypes()) == 0: log.error("No icmptypes found.") # load helper files self._loader(config.FIREWALLD_HELPERS, "helper") self._loader(config.ETC_FIREWALLD_HELPERS, "helper") # load service files self._loader(config.FIREWALLD_SERVICES, "service") self._loader(config.ETC_FIREWALLD_SERVICES, "service") if len(self.service.get_services()) == 0: log.error("No services found.") # load zone files self._loader(config.FIREWALLD_ZONES, "zone") self._loader(config.ETC_FIREWALLD_ZONES, "zone") if len(self.zone.get_zones()) == 0: log.fatal("No zones found.") sys.exit(1) # check minimum required zones error = False for z in [ "block", "drop", "trusted" ]: if z not in self.zone.get_zones(): log.fatal("Zone '%s' is not available.", z) error = True if error: sys.exit(1) # check if default_zone is a valid zone if default_zone not in self.zone.get_zones(): if "public" in self.zone.get_zones(): zone = "public" elif "external" in self.zone.get_zones(): zone = "external" else: zone = "block" # block is a base zone, therefore it has to exist log.error("Default zone '%s' is not valid. Using '%s'.", default_zone, zone) default_zone = zone else: log.debug1("Using default zone '%s'", default_zone) # load direct rules obj = Direct(config.FIREWALLD_DIRECT) if os.path.exists(config.FIREWALLD_DIRECT): log.debug1("Loading direct rules file '%s'" % \ config.FIREWALLD_DIRECT) try: obj.read() except Exception as msg: log.error("Failed to load direct rules file '%s': %s", config.FIREWALLD_DIRECT, msg) self.direct.set_permanent_config(obj) self.config.set_direct(copy.deepcopy(obj)) # automatic helpers # # NOTE: must force loading of nf_conntrack to make sure the values are # available in /proc (status, msg) = self.handle_modules(["nf_conntrack"], True) if status != 0: log.warning("Failed to load nf_conntrack module: %s" % msg) if self._automatic_helpers != "system": functions.set_nf_conntrack_helper_setting(self._automatic_helpers == "yes") self.nf_conntrack_helper_setting = \ functions.get_nf_conntrack_helper_setting() # check if needed tables are there self._check_tables() if log.getDebugLogLevel() > 0: # get time before flushing and applying tm1 = time.time() # Start transaction transaction = FirewallTransaction(self) # flush rules self.flush(use_transaction=transaction) # If modules need to be unloaded in complete reload or if there are # ipsets to get applied, limit the transaction to flush. # # Future optimization for the ipset case in reload: The transaction # only needs to be split here if there are conflicting ipset types in # exsting ipsets and the configuration in firewalld. if (reload and complete_reload) or \ (self.ipset_enabled and self.ipset.has_ipsets()): transaction.execute(True) transaction.clear() # complete reload: unload modules also if reload and complete_reload: log.debug1("Unloading firewall modules") self.modules_backend.unload_firewall_modules() self.apply_default_tables(use_transaction=transaction) transaction.execute(True) transaction.clear() # apply settings for loaded ipsets while reloading here if self.ipset_enabled and self.ipset.has_ipsets(): log.debug1("Applying ipsets") self.ipset.apply_ipsets() # Start or continue with transaction # apply default rules log.debug1("Applying default rule set") self.apply_default_rules(use_transaction=transaction) # apply settings for loaded zones log.debug1("Applying used zones") self.zone.apply_zones(use_transaction=transaction) self._default_zone = self.check_zone(default_zone) self.zone.change_default_zone(None, self._default_zone, use_transaction=transaction) # Execute transaction transaction.execute(True) # Start new transaction for direct rules transaction.clear() # apply direct chains, rules and passthrough rules if self.direct.has_configuration(): log.debug1("Applying direct chains rules and passthrough rules") self.direct.apply_direct(transaction) # since direct rules are easy to make syntax errors lets highlight # the cause if the transaction fails. try: transaction.execute(True) transaction.clear() except FirewallError as e: raise FirewallError(e.code, "Direct: %s" % (e.msg if e.msg else "")) except Exception: raise del transaction if log.getDebugLogLevel() > 1: # get time after flushing and applying tm2 = time.time() log.debug2("Flushing and applying took %f seconds" % (tm2 - tm1)) def start(self): try: self._start() except Exception: self._state = "FAILED" self.set_policy("ACCEPT") raise else: self._state = "RUNNING" self.set_policy("ACCEPT") def _loader(self, path, reader_type, combine=False): # combine: several zone files are getting combined into one obj if not os.path.isdir(path): return if combine: if path.startswith(config.ETC_FIREWALLD) and reader_type == "zone": combined_zone = Zone() combined_zone.name = os.path.basename(path) combined_zone.check_name(combined_zone.name) combined_zone.path = path combined_zone.default = False else: combine = False for filename in sorted(os.listdir(path)): if not filename.endswith(".xml"): if path.startswith(config.ETC_FIREWALLD) and \ reader_type == "zone" and \ os.path.isdir("%s/%s" % (path, filename)): self._loader("%s/%s" % (path, filename), reader_type, combine=True) continue name = "%s/%s" % (path, filename) log.debug1("Loading %s file '%s'", reader_type, name) try: if reader_type == "icmptype": obj = icmptype_reader(filename, path) if obj.name in self.icmptype.get_icmptypes(): orig_obj = self.icmptype.get_icmptype(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.icmptype.remove_icmptype(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True try: self.icmptype.add_icmptype(obj) except FirewallError as error: log.info1("%s: %s, ignoring for run-time." % \ (obj.name, str(error))) # add a deep copy to the configuration interface self.config.add_icmptype(copy.deepcopy(obj)) elif reader_type == "service": obj = service_reader(filename, path) if obj.name in self.service.get_services(): orig_obj = self.service.get_service(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.service.remove_service(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.service.add_service(obj) # add a deep copy to the configuration interface self.config.add_service(copy.deepcopy(obj)) elif reader_type == "zone": obj = zone_reader(filename, path, no_check_name=combine) if combine: # Change name for permanent configuration obj.name = "%s/%s" % ( os.path.basename(path), os.path.basename(filename)[0:-4]) obj.check_name(obj.name) # Copy object before combine config_obj = copy.deepcopy(obj) if obj.name in self.zone.get_zones(): orig_obj = self.zone.get_zone(obj.name) self.zone.remove_zone(orig_obj.name) if orig_obj.combined: log.debug1(" Combining %s '%s' ('%s/%s')", reader_type, obj.name, path, filename) obj.combine(orig_obj) else: log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True config_obj.default = True self.config.add_zone(config_obj) if combine: log.debug1(" Combining %s '%s' ('%s/%s')", reader_type, combined_zone.name, path, filename) combined_zone.combine(obj) else: self.zone.add_zone(obj) elif reader_type == "ipset": obj = ipset_reader(filename, path) if obj.name in self.ipset.get_ipsets(): orig_obj = self.ipset.get_ipset(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.ipset.remove_ipset(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True try: self.ipset.add_ipset(obj) except FirewallError as error: log.warning("%s: %s, ignoring for run-time." % \ (obj.name, str(error))) # add a deep copy to the configuration interface self.config.add_ipset(copy.deepcopy(obj)) elif reader_type == "helper": obj = helper_reader(filename, path) if obj.name in self.helper.get_helpers(): orig_obj = self.helper.get_helper(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.helper.remove_helper(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.helper.add_helper(obj) # add a deep copy to the configuration interface self.config.add_helper(copy.deepcopy(obj)) else: log.fatal("Unknown reader type %s", reader_type) except FirewallError as msg: log.error("Failed to load %s file '%s': %s", reader_type, name, msg) except Exception: log.error("Failed to load %s file '%s':", reader_type, name) log.exception() if combine and combined_zone.combined: if combined_zone.name in self.zone.get_zones(): orig_obj = self.zone.get_zone(combined_zone.name) log.debug1(" Overloading and deactivating %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) try: self.zone.remove_zone(combined_zone.name) except Exception: pass self.config.forget_zone(combined_zone.name) self.zone.add_zone(combined_zone) def cleanup(self): self.icmptype.cleanup() self.service.cleanup() self.zone.cleanup() self.ipset.cleanup() self.helper.cleanup() self.config.cleanup() self.direct.cleanup() self.policies.cleanup() self._firewalld_conf.cleanup() self.__init_vars() def stop(self): if self.cleanup_on_exit: self.flush() self.set_policy("ACCEPT") self.modules_backend.unload_firewall_modules() self.cleanup() # marks def new_mark(self): # return first unused mark i = self._min_mark while i in self._marks: i += 1 self._marks.append(i) return i def del_mark(self, mark): self._marks.remove(mark) # handle modules def handle_modules(self, _modules, enable): num_failed = 0 error_msgs = "" for i,module in enumerate(_modules): if enable: (status, msg) = self.modules_backend.load_module(module) else: if self._module_refcount[module] > 1: status = 0 # module referenced more then one, do not unload else: (status, msg) = self.modules_backend.unload_module(module) if status != 0: num_failed += 1 error_msgs += msg continue if enable: self._module_refcount.setdefault(module, 0) self._module_refcount[module] += 1 else: if module in self._module_refcount: self._module_refcount[module] -= 1 if self._module_refcount[module] == 0: del self._module_refcount[module] return (num_failed, error_msgs) def _select_firewall_backend(self, backend): if backend != "nftables": self.nftables_enabled = False # even if using nftables, the other backends are enabled for use with # the direct interface. nftables is used for the firewalld primitives. def get_backend_by_name(self, name): for backend in self.all_backends(): if backend.name == name: return backend raise FirewallError(errors.UNKNOWN_ERROR, "'%s' backend does not exist" % name) def get_backend_by_ipv(self, ipv): if self.nftables_enabled: return self.nftables_backend if ipv == "ipv4" and self.ip4tables_enabled: return self.ip4tables_backend elif ipv == "ipv6" and self.ip6tables_enabled: return self.ip6tables_backend elif ipv == "eb" and self.ebtables_enabled: return self.ebtables_backend raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend or is unavailable" % ipv) def get_direct_backend_by_ipv(self, ipv): if ipv == "ipv4" and self.ip4tables_enabled: return self.ip4tables_backend elif ipv == "ipv6" and self.ip6tables_enabled: return self.ip6tables_backend elif ipv == "eb" and self.ebtables_enabled: return self.ebtables_backend raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend or is unavailable" % ipv) def is_backend_enabled(self, name): if name == "ip4tables": return self.ip4tables_enabled elif name == "ip6tables": return self.ip6tables_enabled elif name == "ebtables": return self.ebtables_enabled elif name == "nftables": return self.nftables_enabled return False def is_ipv_enabled(self, ipv): if self.nftables_enabled: return True if ipv == "ipv4": return self.ip4tables_enabled elif ipv == "ipv6": return self.ip6tables_enabled elif ipv == "eb": return self.ebtables_enabled return False def enabled_backends(self): backends = [] if self.nftables_enabled: backends.append(self.nftables_backend) else: if self.ip4tables_enabled: backends.append(self.ip4tables_backend) if self.ip6tables_enabled: backends.append(self.ip6tables_backend) if self.ebtables_enabled: backends.append(self.ebtables_backend) return backends def all_backends(self): backends = [] if self.ip4tables_enabled: backends.append(self.ip4tables_backend) if self.ip6tables_enabled: backends.append(self.ip6tables_backend) if self.ebtables_enabled: backends.append(self.ebtables_backend) if self.nftables_enabled: backends.append(self.nftables_backend) return backends def apply_default_tables(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction for backend in self.enabled_backends(): transaction.add_rules(backend, backend.build_default_tables()) if use_transaction is None: transaction.execute(True) def apply_default_rules(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction for backend in self.enabled_backends(): rules = backend.build_default_rules(self._log_denied) transaction.add_rules(backend, rules) if self.is_ipv_enabled("ipv6"): ipv6_backend = self.get_backend_by_ipv("ipv6") if self.ipv6_rpfilter_enabled and \ "raw" in ipv6_backend.get_available_tables(): # Execute existing transaction transaction.execute(True) # Start new transaction transaction.clear() rules = ipv6_backend.build_rpfilter_rules(self._log_denied) transaction.add_rules(ipv6_backend, rules) # Execute ipv6_rpfilter transaction, it might fail try: transaction.execute(True) except FirewallError as msg: log.warning("Applying rules for ipv6_rpfilter failed: %s", msg) # Start new transaction transaction.clear() if use_transaction is None: transaction.execute(True) # flush and policy def flush(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction log.debug1("Flushing rule set") for backend in self.all_backends(): rules = backend.build_flush_rules() transaction.add_rules(backend, rules) if use_transaction is None: transaction.execute(True) def set_policy(self, policy, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction log.debug1("Setting policy to '%s'", policy) for backend in self.enabled_backends(): rules = backend.build_set_policy_rules(policy) transaction.add_rules(backend, rules) if use_transaction is None: transaction.execute(True) # rule function used in handle_ functions def rule(self, backend_name, rule): if not rule: return "" backend = self.get_backend_by_name(backend_name) if not backend: raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend" % backend_name) if not self.is_backend_enabled(backend_name): return "" return backend.set_rule(rule, self._log_denied) def rules(self, backend_name, rules): _rules = list(filter(None, rules)) backend = self.get_backend_by_name(backend_name) if not backend: raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend" % backend_name) if not self.is_backend_enabled(backend_name): return "" if self._individual_calls or \ not backend.restore_command_exists or \ (backend_name == "ebtables" and not self.ebtables_backend.restore_noflush_option): for i,rule in enumerate(_rules): try: backend.set_rule(rule, self._log_denied) except Exception as msg: log.debug1(traceback.format_exc()) log.error(msg) for rule in reversed(_rules[:i]): try: backend.set_rule(backend.reverse_rule(rule), self._log_denied) except Exception: # ignore errors here pass raise msg return True else: return backend.set_rules(_rules, self._log_denied) # check functions def check_panic(self): if self._panic: raise FirewallError(errors.PANIC_MODE) def check_zone(self, zone): _zone = zone if not _zone or _zone == "": _zone = self.get_default_zone() if _zone not in self.zone.get_zones(): raise FirewallError(errors.INVALID_ZONE, _zone) return _zone def check_interface(self, interface): if not functions.checkInterface(interface): raise FirewallError(errors.INVALID_INTERFACE, interface) def check_service(self, service): self.service.check_service(service) def check_port(self, port): if not functions.check_port(port): raise FirewallError(errors.INVALID_PORT, port) def check_tcpudp(self, protocol): if not protocol: raise FirewallError(errors.MISSING_PROTOCOL) if protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, "'%s' not in {'tcp'|'udp'|'sctp'|'dccp'}" % \ protocol) def check_ip(self, ip): if not functions.checkIP(ip): raise FirewallError(errors.INVALID_ADDR, ip) def check_address(self, ipv, source): if ipv == "ipv4": if not functions.checkIPnMask(source): raise FirewallError(errors.INVALID_ADDR, source) elif ipv == "ipv6": if not functions.checkIP6nMask(source): raise FirewallError(errors.INVALID_ADDR, source) else: raise FirewallError(errors.INVALID_IPV, "'%s' not in {'ipv4'|'ipv6'}") def check_icmptype(self, icmp): self.icmptype.check_icmptype(icmp) def check_timeout(self, timeout): if not isinstance(timeout, int): raise TypeError("%s is %s, expected int" % (timeout, type(timeout))) if int(timeout) < 0: raise FirewallError(errors.INVALID_VALUE, "timeout '%d' is not positive number" % timeout) # RELOAD def reload(self, stop=False): _panic = self._panic # save zone interfaces _zone_interfaces = { } for zone in self.zone.get_zones(): _zone_interfaces[zone] = self.zone.get_settings(zone)["interfaces"] # save direct config _direct_config = self.direct.get_runtime_config() _old_dz = self.get_default_zone() self.set_policy("DROP") # stop self.cleanup() start_exception = None try: self._start(reload=True, complete_reload=stop) except Exception as e: # save the exception for later, but continue restoring interfaces, # etc. We'll re-raise it at the end. start_exception = e # handle interfaces in the default zone and move them to the new # default zone if it changed _new_dz = self.get_default_zone() if _new_dz != _old_dz: # if_new_dz has been introduced with the reload, we need to add it # https://github.com/firewalld/firewalld/issues/53 if _new_dz not in _zone_interfaces: _zone_interfaces[_new_dz] = { } # default zone changed. Move interfaces from old default zone to # the new one. for iface, settings in list(_zone_interfaces[_old_dz].items()): if settings["__default__"]: # move only those that were added to default zone # (not those that were added to specific zone same as # default) _zone_interfaces[_new_dz][iface] = \ _zone_interfaces[_old_dz][iface] del _zone_interfaces[_old_dz][iface] # add interfaces to zones again for zone in self.zone.get_zones(): if zone in _zone_interfaces: self.zone.set_settings(zone, { "interfaces": _zone_interfaces[zone] }) del _zone_interfaces[zone] else: log.info1("New zone '%s'.", zone) if len(_zone_interfaces) > 0: for zone in list(_zone_interfaces.keys()): log.info1("Lost zone '%s', zone interfaces dropped.", zone) del _zone_interfaces[zone] del _zone_interfaces # restore direct config self.direct.set_config(_direct_config) # enable panic mode again if it has been enabled before or set policy # to ACCEPT if _panic: self.enable_panic_mode() else: self.set_policy("ACCEPT") if start_exception: self._state = "FAILED" raise start_exception else: self._state = "RUNNING" # STATE def get_state(self): return self._state # PANIC MODE def enable_panic_mode(self): if self._panic: raise FirewallError(errors.ALREADY_ENABLED, "panic mode already enabled") # TODO: use rule in raw table not default chain policy try: self.set_policy("DROP") except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) self._panic = True def disable_panic_mode(self): if not self._panic: raise FirewallError(errors.NOT_ENABLED, "panic mode is not enabled") # TODO: use rule in raw table not default chain policy try: self.set_policy("ACCEPT") except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) self._panic = False def query_panic_mode(self): return self._panic # LOG DENIED def get_log_denied(self): return self._log_denied def set_log_denied(self, value): if value not in config.LOG_DENIED_VALUES: raise FirewallError(errors.INVALID_VALUE, "'%s', choose from '%s'" % \ (value, "','".join(config.LOG_DENIED_VALUES))) if value != self.get_log_denied(): self._log_denied = value self._firewalld_conf.set("LogDenied", value) self._firewalld_conf.write() else: raise FirewallError(errors.ALREADY_SET, value) # AUTOMATIC HELPERS def get_automatic_helpers(self): return self._automatic_helpers def set_automatic_helpers(self, value): if value not in config.AUTOMATIC_HELPERS_VALUES: raise FirewallError(errors.INVALID_VALUE, "'%s', choose from '%s'" % \ (value, "','".join(config.AUTOMATIC_HELPERS_VALUES))) if value != self.get_automatic_helpers(): self._automatic_helpers = value self._firewalld_conf.set("AutomaticHelpers", value) self._firewalld_conf.write() else: raise FirewallError(errors.ALREADY_SET, value) # DEFAULT ZONE def get_default_zone(self): return self._default_zone def set_default_zone(self, zone): _zone = self.check_zone(zone) if _zone != self._default_zone: _old_dz = self._default_zone self._default_zone = _zone self._firewalld_conf.set("DefaultZone", _zone) self._firewalld_conf.write() # remove old default zone from ZONES and add new default zone self.zone.change_default_zone(_old_dz, _zone) # Move interfaces from old default zone to the new one. _old_dz_settings = self.zone.get_settings(_old_dz) for iface, settings in list(_old_dz_settings["interfaces"].items()): if settings["__default__"]: # move only those that were added to default zone # (not those that were added to specific zone same as default) self.zone.change_zone_of_interface("", iface) else: raise FirewallError(errors.ZONE_ALREADY_SET, _zone) PK! prog.pyonu[ c`c@s(ddlZdgZdddZdS(iNtrunProgc Cs|dkrg}n|g|}d}|r[t|d}|jj}WdQXnidd6}y:tj|dtjdtjdtjdtd|}Wnt k rd SX|j |\}} |j d d }|j |fS(NtrtCtLANGtstdintstderrtstdoutt close_fdstenvitsutf-8treplace(iR ( tNonetopentreadtencodet subprocesstPopentPIPEtSTDOUTtTruetOSErrort communicatetdecodet returncode( tprogtargvRtargst input_stringthandleRtprocesstoutputt err_output((s6/usr/lib/python2.7/site-packages/firewall/core/prog.pyRs$       (Rt__all__R R(((s6/usr/lib/python2.7/site-packages/firewall/core/prog.pyts  PK!Uu))base.pyonu[ c`c@sdZdZdddedgZidd6dd 6d d 6d d 6dd6dd6Ziddddddddddddddd d!gd"6d#d$d%d&d'd(d)ddg d*6Zd+d,d-d.d/d0d1gZd2S(3sBase firewall settingss{chain}_{zone}tACCEPTs %%REJECT%%tDROPtdefaulttPREt PREROUTINGtPOSTt POSTROUTINGtINtINPUTtFWDIt FORWARD_INtFWDOt FORWARD_OUTtOUTtOUTPUTsicmp-host-prohibiteds host-prohibsicmp-net-unreachables net-unreachsicmp-host-unreachables host-unreachsicmp-port-unreachables port-unreachsicmp-proto-unreachables proto-unreachsicmp-net-prohibiteds net-prohibs tcp-resetstcp-rstsicmp-admin-prohibiteds admin-prohibtipv4sicmp6-adm-prohibitedsadm-prohibitedsicmp6-no-routesno-routesicmp6-addr-unreachables addr-unreachsicmp6-port-unreachabletipv6shash:ips hash:ip,ports hash:ip,markshash:nets hash:net,portshash:net,ifaceshash:macN(t__doc__tDEFAULT_ZONE_TARGETt ZONE_TARGETSt SHORTCUTSt REJECT_TYPEStZONE_SOURCE_IPSET_TYPES(((s6/usr/lib/python2.7/site-packages/firewall/core/base.pyts,           PK!~N fw_policies.pyonu[ c`c@ssdgZddlmZddlmZddlmZddlmZddlm Z de fdYZ dS( tFirewallPoliciesi(tconfig(tlog(tLockdownWhitelist(terrors(t FirewallErrorcBsGeZdZdZdZdZdZdZdZRS(cCst|_ttj|_dS(N(tFalset _lockdownRRtLOCKDOWN_WHITELISTtlockdown_whitelist(tself((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyt__init__s cCsd|j|j|jfS(Ns %s(%r, %r)(t __class__RR (R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyt__repr__#scCst|_|jjdS(N(RRR tcleanup(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyR's cCs|dkrCtjd||jj|r tjdtSn|dkrtjd||jj|r tjdtSn|dkrtjd||jj|r tjd tSnC|d kr tjd ||jj|r tjd tSnt S( Ntcontexts#Doing access check for context "%s"scontext matches.tuidsDoing access check for uid %ds uid matches.tusers Doing access check for user "%s"s user matches.tcommands#Doing access check for command "%s"scommand matches.( Rtdebug2R t match_contexttdebug3tTruet match_uidt match_usert match_commandR(R tkeytvalue((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyt access_check-s*        cCs+|jrttjdnt|_dS(Nsenable_lockdown()(RRRtALREADY_ENABLEDR(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pytenable_lockdownDs cCs+|jsttjdnt|_dS(Nsdisable_lockdown()(RRRt NOT_ENABLEDR(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pytdisable_lockdownIs cCs|jS(N(R(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pytquery_lockdownNs( t__name__t __module__R R RRRR R!(((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyRs      N( t__all__tfirewallRtfirewall.core.loggerRt#firewall.core.io.lockdown_whitelistRRtfirewall.errorsRtobjectR(((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyts PK!ө= __init__.pyonu[ c`c@sdS(N((((s:/usr/lib/python2.7/site-packages/firewall/core/__init__.pytsPK!f$f$ipset.pynu[# -*- 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 . # """The ipset command wrapper""" __all__ = [ "ipset", "check_ipset_name", "remove_default_create_options" ] import os.path from firewall import errors from firewall.errors import FirewallError from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import tempFile, readfile from firewall.config import COMMANDS IPSET_MAXNAMELEN = 32 IPSET_TYPES = [ # bitmap and set types are currently not supported # "bitmap:ip", # "bitmap:ip,mac", # "bitmap:port", # "list:set", "hash:ip", "hash:ip,port", "hash:ip,port,ip", "hash:ip,port,net", "hash:ip,mark", "hash:net", "hash:net,net", "hash:net,port", "hash:net,port,net", "hash:net,iface", "hash:mac", ] IPSET_CREATE_OPTIONS = { "family": "inet|inet6", "hashsize": "value", "maxelem": "value", "timeout": "value in secs", #"counters": None, #"comment": None, } IPSET_DEFAULT_CREATE_OPTIONS = { "family": "inet", "hashsize": "1024", "maxelem": "65536", } class ipset(object): """ipset command wrapper class""" def __init__(self): self._command = COMMANDS["ipset"] self.name = "ipset" def __run(self, args): """Call ipset with args""" # convert to string list _args = ["%s" % item for item in args] log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args)) (status, ret) = runProg(self._command, _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(_args), ret)) return ret def check_name(self, name): """Check ipset name""" if len(name) > IPSET_MAXNAMELEN: raise FirewallError(errors.INVALID_NAME, "ipset name '%s' is not valid" % name) def set_supported_types(self): """Return types that are supported by the ipset command and kernel""" ret = [ ] output = "" try: output = self.__run(["--help"]) except ValueError as ex: log.debug1("ipset error: %s" % ex) lines = output.splitlines() in_types = False for line in lines: #print(line) if in_types: splits = line.strip().split(None, 2) if splits[0] not in ret and splits[0] in IPSET_TYPES: ret.append(splits[0]) if line.startswith("Supported set types:"): in_types = True return ret def check_type(self, type_name): """Check ipset type""" if len(type_name) > IPSET_MAXNAMELEN or type_name not in IPSET_TYPES: raise FirewallError(errors.INVALID_TYPE, "ipset type name '%s' is not valid" % type_name) def set_create(self, set_name, type_name, options=None): """Create an ipset with name, type and options""" self.check_name(set_name) self.check_type(type_name) args = [ "create", set_name, type_name ] if isinstance(options, dict): for key, val in options.items(): args.append(key) if val != "": args.append(val) return self.__run(args) def set_destroy(self, set_name): self.check_name(set_name) return self.__run([ "destroy", set_name ]) def set_add(self, set_name, entry): args = [ "add", set_name, entry ] return self.__run(args) def set_delete(self, set_name, entry): args = [ "del", set_name, entry ] return self.__run(args) def test(self, set_name, entry, options=None): args = [ "test", set_name, entry ] if options: args.append("%s" % " ".join(options)) return self.__run(args) def set_list(self, set_name=None, options=None): args = [ "list" ] if set_name: args.append(set_name) if options: args.extend(options) return self.__run(args).split("\n") def set_get_active_terse(self): """ Get active ipsets (only headers) """ lines = self.set_list(options=["-terse"]) ret = { } _name = _type = None _options = { } for line in lines: if len(line) < 1: continue pair = [ x.strip() for x in line.split(":", 1) ] if len(pair) != 2: continue elif pair[0] == "Name": _name = pair[1] elif pair[0] == "Type": _type = pair[1] elif pair[0] == "Header": splits = pair[1].split() i = 0 while i < len(splits): opt = splits[i] if opt in [ "family", "hashsize", "maxelem", "timeout", "netmask" ]: if len(splits) > i: i += 1 _options[opt] = splits[i] else: log.error("Malformed ipset list -terse output: %s", line) return { } i += 1 if _name and _type: ret[_name] = (_type, remove_default_create_options(_options)) _name = _type = None _options.clear() return ret def save(self, set_name=None): args = [ "save" ] if set_name: args.append(set_name) return self.__run(args) def set_restore(self, set_name, type_name, entries, create_options=None, entry_options=None): self.check_name(set_name) self.check_type(type_name) temp_file = tempFile() if ' ' in set_name: set_name = "'%s'" % set_name args = [ "create", set_name, type_name, "-exist" ] if create_options: for key, val in create_options.items(): args.append(key) if val != "": args.append(val) temp_file.write("%s\n" % " ".join(args)) temp_file.write("flush %s\n" % set_name) for entry in entries: if ' ' in entry: entry = "'%s'" % entry if entry_options: temp_file.write("add %s %s %s\n" % \ (set_name, entry, " ".join(entry_options))) else: temp_file.write("add %s %s\n" % (set_name, entry)) temp_file.close() stat = os.stat(temp_file.name) log.debug2("%s: %s restore %s", self.__class__, self._command, "%s: %d" % (temp_file.name, stat.st_size)) args = [ "restore" ] (status, ret) = runProg(self._command, args, stdin=temp_file.name) if log.getDebugLogLevel() > 2: try: readfile(temp_file.name) except Exception: pass else: i = 1 for line in readfile(temp_file.name): log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0) if not line.endswith("\n"): log.debug3("", nofmt=1) i += 1 os.unlink(temp_file.name) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(args), ret)) return ret def set_flush(self, set_name): args = [ "flush" ] if set_name: args.append(set_name) return self.__run(args) def rename(self, old_set_name, new_set_name): return self.__run([ "rename", old_set_name, new_set_name ]) def swap(self, set_name_1, set_name_2): return self.__run([ "swap", set_name_1, set_name_2 ]) def version(self): return self.__run([ "version" ]) def check_ipset_name(name): """Return true if ipset name is valid""" if len(name) > IPSET_MAXNAMELEN: return False return True def remove_default_create_options(options): """ Return only non default create options """ _options = options.copy() for opt in IPSET_DEFAULT_CREATE_OPTIONS: if opt in _options and \ IPSET_DEFAULT_CREATE_OPTIONS[opt] == _options[opt]: del _options[opt] return _options PK!4Hzz fw_config.pyonu[ c`c@sdgZddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZmZmZddlmZmZmZdd lmZmZmZdd lmZdd lmZde fd YZ!dS( tFirewallConfigiN(tconfig(tlog(tIcmpTypeticmptype_readerticmptype_writer(tServicetservice_readertservice_writer(tZonet zone_readert zone_writer(tIPSett ipset_readert ipset_writer(tHelpert helper_readert helper_writer(terrors(t FirewallErrorcBseZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!d Z"d!Z#d"Z$d#Z%d$Z&d%Z'd&Z(d'Z)d(Z*d)Z+d*Z,d+Z-d,Z.d-Z/d.Z0d/Z1d0Z2d1Z3d2Z4d3Z5d4Z6d5Z7d6Z8d7Z9d8Z:d9Z;d:Z<d;Z=d<Z>d=Z?d>Z@d?ZAd@ZBdAZCdBZDdCZEdDZFdEZGdFZHdGZIdHZJdIZKdJZLdKZMdLZNdMZOdNZPdOZQdPZRRS(QcCs||_|jdS(N(t_fwt_FirewallConfig__init_vars(tselftfw((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt__init__'s cCs\d|j|j|j|j|j|j|j|j|j|j |j |j |j |j fS(Ns6%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)(t __class__t_ipsetst _icmptypest _servicest_zonest_helperst_builtin_ipsetst_builtin_icmptypest_builtin_servicest_builtin_zonest_builtin_helperst_firewalld_conft _policiest_direct(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt__repr__+s cCsyi|_i|_i|_i|_i|_i|_i|_i|_i|_i|_ d|_ d|_ d|_ dS(N(RRRRRRR R!R"R#tNoneR$R%R&(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt __init_vars4s            cCsx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=qQWx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=qWx8t|jjD]!}|j|j|j|=q=Wx8t|j jD]!}|j |j|j |=qxWx8t|j jD]!}|j |j|j |=qWx8t|j jD]!}|j |j|j |=qWx8t|j jD]!}|j |j|j |=q)W|j rv|j j|` d|_ n|jr|jj|`d|_n|jr|jj|`d|_n|jdS(N(tlistRtkeystcleanupRR RR!RR"RR#RR$R(R%R&R(Rtx((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyR,CsV         cCs|jjjS(N(Rtpoliciestquery_lockdown(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytlockdown_enabledzscCs|jjj||S(N(RR.t access_check(Rtkeytvalue((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyR1}scCs ||_dS(N(R$(Rtconf((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytset_firewalld_confscCs|jS(N(R$(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytget_firewalld_confscCs6tjjtjs%|jjn |jjdS(N(tostpathtexistsRtFIREWALLD_CONFR$tcleartread(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytupdate_firewalld_confscCs ||_dS(N(R%(RR.((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt set_policiesscCs|jS(N(R%(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt get_policiesscCs<tjjtjs(|jjjn|jjjdS(N( R7R8R9RtLOCKDOWN_WHITELISTR%tlockdown_whitelistR,R<(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pytupdate_lockdown_whitelistscCs ||_dS(N(R&(Rtdirect((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt set_directscCs|jS(N(R&(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt get_directscCs6tjjtjs%|jjn |jjdS(N(R7R8R9RtFIREWALLD_DIRECTR&R,R<(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt update_directscCs2ttt|jjt|jjS(N(tsortedtsetR*RR+R(R((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyt get_ipsetsscCs0|jr||j|jR?RBRDRERGRJRNRPRSRUR[R`RjRRRoRpRrRqRsRtRvRxRyR{R|R}RwRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyR&s   7                  E            E            E             M            E    ("t__all__RVR7tos.pathRltfirewallRtfirewall.core.loggerRtfirewall.core.io.icmptypeRRRtfirewall.core.io.serviceRRRtfirewall.core.io.zoneR R R tfirewall.core.io.ipsetR R Rtfirewall.core.io.helperRRRRtfirewall.errorsRtobjectR(((s;/usr/lib/python2.7/site-packages/firewall/core/fw_config.pyts     PK!}w@ helper.pyonu[ c`c@sdZdZdS(sThe helper maxnameleni N(t__doc__tHELPER_MAXNAMELEN(((s8/usr/lib/python2.7/site-packages/firewall/core/helper.pytsPK!i֑ fw_icmptype.pyonu[ c`c@s_dgZddlZddlmZddlmZddlmZdefdYZ dS(tFirewallIcmpTypeiN(tlog(terrors(t FirewallErrorcBsPeZdZdZdZdZdZdZdZdZ RS(cCs||_i|_dS(N(t_fwt _icmptypes(tselftfw((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt__init__s cCsd|j|jfS(Ns%s(%r)(t __class__R(R((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt__repr__"scCs|jjdS(N(Rtclear(R((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pytcleanup%scCst|jjS(N(tsortedRtkeys(R((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt get_icmptypes*scCs(||jkr$ttj|ndS(N(RRRtINVALID_ICMPTYPE(Rticmptype((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pytcheck_icmptype-scCs|j||j|S(N(RR(RR((s=/usr/lib/python2.7/site-packages/firewall/core/fw_icmptype.pyt get_icmptype1s cCs_|j}t|dkr*ddg}n|}x|D]}|dkrk|jjs\q8n|jj}n3|dkr|jjsq8n|jj}ng}|jj|kr8t j d|j|f|j |q8q8Wt|t|krKt|dkr t t jdntj|}||_||j|js  PK!ZZ fw_ifcfg.pyonu[ c`c@spdZddgZddlZddlZddlmZddlmZddlm Z dZ d Z dS( s.Functions to search for and change ifcfg filestsearch_ifcfg_of_interfacetifcfg_set_zone_of_interfaceiN(tconfig(tlog(tifcfgcCstjjtjsd SxttjtjD]}|jdsMq2nx5ddddddgD]}|j |rfqfqfqfWd|krq2nt d tj|f}|j |j d |kr2|Sq2Wd tj|f}tjj|rt |}|j |Sd S( s6search ifcfg file for the interface in config.IFCFGDIRsifcfg-s.baks.origs.rpmnews.rpmorigs.rpmsaves-ranget.s%s/%stDEVICEs %s/ifcfg-%sN( tostpathtexistsRtIFCFGDIRtNonetsortedtlistdirt startswithtendswithRtreadtget(t interfacetfilenametignoredt ifcfg_file((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ifcfg.pyR!s*      cCs|dkrd}nt|}|dk r|jd|kr|jddko`|dk rtjd||jf|jd||jndS(sYSet zone (ZONE=) in the ifcfg file that uses the interface (DEVICE=)ttZONEsSetting ZONE=%s in '%s'N(R RRRtdebug1Rtsettwrite(tzoneRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ifcfg.pyR?s   !"( t__doc__t__all__Rtos.pathtfirewallRtfirewall.core.loggerRtfirewall.core.io.ifcfgRRR(((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ifcfg.pyts    PK!Ы99 nftables.pycnu[ c`c@s~ddlZddlZddlmZmZddlmZddlm Z ddl m Z m Z m Z mZmZddlmZddlmZmZmZmZmZmZddlmZmZmZmZd Zd Ziid d efd 6d6id defd 6d6id defd 6ddefd6d6iddefd6ddefd6d6Z iid6id6id6Z!ii"dd d!dd"d#gd$6dd d!gd!6dd d%gd%6dd d&gd&6dd d!dd"d'gd(6dd d!dd"d)gd*6dd d!dd"d+gd,6dd d-dd"d.gd/6dd d!dd"d0gd16dd d!dd"d.gd26dd d3dd"d.gd46dd d!dd"d5gd66dd d-dd"d7gd86dd d!dd"d9gd:6dd d!dd"d7gd;6dd d3gd36dd d!dd"d<gd=6dd d!dd"d>gd?6dd d!dd"d@gdA6dd d-gd-6dd d3dd"d.gdB6dd dCgdC6dd dDgdD6dd dEgdE6dd d!dd"dFgdG6dd dHgdH6dd dIgdI6dd dJgdJ6dd d-dd"d<gdK6dd d!dd"dLgdM6dd d-dd"d@gdN6dd d!dd"dOgdP6dd dHdd"d.gdQ6dd dHdd"d7gdR6dS6idTd d!dTd"d<gdU6dTd d3dTd"d7gdV6dTd d!dTd"d@gdW6dTd d!dTd"d.gd$6dTd d!gd!6dTd d%gd%6dTd d&gd&6dTd d!dTd"dFgdX6dTd dYgdZ6dTd d[gd\6dTd d!dTd"d7gd]6dTd d^gd^6dTd d3gd36dTd d!dTd"d'gd=6dTd d_gd-6dTd d!dTd"d9gd`6dTd dagdC6dTd dbgdD6dTd dHgdH6dTd dHdTd"d.gdQ6dTd dHdTd"d7gdR6dTd d3dTd"d.gdc6dTd d3dTd"d@gdd6de6Z"dfe#fdgYZ$dS(hiN(t SHORTCUTStDEFAULT_ZONE_TARGET(trunProg(tlog(t splitArgst check_mactportStrtcheck_single_addresst check_address(tconfig(t FirewallErrort UNKNOWN_ERRORt INVALID_RULEtINVALID_ICMPTYPEt INVALID_TYPEt INVALID_ENTRY(t Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_Markt firewalldi t preroutingit PREROUTINGtrawijtmangleit postroutingidt POSTROUTINGtnattinputitINPUTtforwardtFORWARDtfiltertinettiptip6ticmpttypesdestination-unreachabletcodet13scommunication-prohibiteds echo-replys echo-requestt4sfragmentation-neededt14shost-precedence-violationt10shost-prohibitedtredirectt1s host-redirectt7s host-unknownshost-unreachablesparameter-problems ip-header-badt8snetwork-prohibitedt0snetwork-redirectt6snetwork-unknownsnetwork-unreachablet3sport-unreachablet15sprecedence-cutofft2sprotocol-unreachablesrequired-option-missingsrouter-advertisementsrouter-solicitations source-quencht5ssource-route-faileds time-exceededstimestamp-replystimestamp-requeststos-host-redirectt12stos-host-unreachablestos-network-redirectt11stos-network-unreachablesttl-zero-during-reassemblysttl-zero-during-transittipv4ticmpv6saddress-unreachables bad-headers beyond-scopes failed-policysnd-neighbor-advertsneighbour-advertisementsnd-neighbor-solicitsneighbour-solicitationsno-routespacket-too-bigs nd-redirects reject-routesnd-router-advertsnd-router-solicitsunknown-header-typesunknown-optiontipv6tnftablescBseZdZeZdZdZdZdZdZ dZ dZ dZ d3d Zd Zd Zd Zd ZddZdZeddZddZddZdZdZdZdZdZdZdZdZ d3d3dZ!d3d3dZ"d3d3dZ#d Z$d3d!Z%d3d"Z&d#Z'd3d$Z(d%Z)d3d&Z*d'Z+ed(Z,d)Z-d*Z.d+Z/d3d,Z0d-Z1d.Z2d/Z3d0Z4d1Z5d2Z6RS(4R:cCsK||_tjd|_|jg|_i|_i|_i|_dS(Ntnft( t_fwR tCOMMANDSt_commandt fill_existstavailable_tablestrule_to_handletrule_ref_counttzone_source_index_cache(tselftfw((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt__init__s     cCs%tjj|j|_t|_dS(N(tostpathtexistsR>tcommand_existstFalsetrestore_command_exists(RD((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR?sc Csy?|jd}|j||j|}||df}WnLtk ry&|jd}|j|d}Wqtk rdSXnX|d}|r| r||kr|||kr||j|qn|r||krg||sitinsertitaddtindexs%d( RRtpopt ValueErrortNonetremovetappendtsortR<t_allow_zone_driftingtlenRP( RDtrule_addtruleRCtitzonet zone_sourcetfamilyRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_run_replace_zone_sourcesD                 c Csddg}|}|ddkrs|ddkrs|}d|dRUtTruetintt ExceptionR R RStjoinRKRBR Rtdebug2t __class__tcopytdeepcopyRCRaRARTRRRZtstrip( RDtargstnft_optst_argst _args_testtstatustoutputtrule_keyR[RCt _args_strtstrtoffset((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt__runs|           #!     cCsAy|j|}Wntk r'tSX||||d+tSdS(Ni(RRRTRKRi(RDR\tpatternt replacementR]((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt _rule_replace,s  cCs|}d|d<|S(NRbi((RDRrtret_args((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt reverse_rule5s cCsttddS(Nsnot implemented(R R (RDtrulest log_denied((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_rules:sc Csd}d|ks*d|ks*d|kr3d}n-d|ksWd|ksWd|kr`d}n|j|dd d |d d g|j|d dddgy|jd}Wntk rnDX|dkrdS|dkrd|g|||d+n |j||j|S(NticmpxR7R"R$R9R#R8s %%REJECT%%trejecttwithR%sadmin-prohibiteds%%ICMP%%tmetatl4protos{icmp, icmpv6}s %%LOGTYPE%%toffRetunicastt broadcastt multicasttpkttypei(RRR(RRRRTRSt_nftables__run(RDR\Rt icmp_keywordR]((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytset_ruleCs$$ $      cCs|r |gStjS(N(tIPTABLES_TO_NFT_HOOKtkeys(RDRc((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytget_available_tablesbscCsYi|_i|_i|_g}x1tjD]#}|jdd|dtgq.W|S(NRbRcs%s(RARBRCt OUR_CHAINSRRWt TABLE_NAME(RDRR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_flush_rulesfs   !cCstdd}g}|dkr|jddd|gxddgD]:}d |d ||d td f}|jt|qFWn5|d kr|jddd|gn ttd|S(Nt_t policy_droptDROPRQRcR!RRwsMadd chain inet %s %s_%s '{ type filter hook %s priority %d ; policy drop ; }'RiitACCEPTRbsnot implemented(RRWtNFT_HOOK_OFFSETRR R (RDtpolicyt table_nameRthookt _add_chain((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_set_policy_rulesps   cCsAt}x+tjD]}|jt|jqWt|S(N(tsettICMP_TYPES_FRAGMENTRtupdateRd(RDt supportedtipv((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytsupported_icmp_typess cCsAg}x+tjD]}|jd|tfqWtt|S(Nsadd table %s %s(RRRWRtmapR(RDtdefault_tablesR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_default_tablessRc Csg}ttddadd rule inet %s filter_%s ct state established,related acceptRs,add rule inet %s filter_%s iifname lo acceptsadd chain inet %s filter_%s_%ss,add rule inet %s filter_%s jump filter_%s_%sRs_add rule inet %s filter_%s ct state invalid %%%%LOGTYPE%%%% log prefix '"STATE_INVALID_DROP: "'s0add rule inet %s filter_%s ct state invalid dropsHadd rule inet %s filter_%s %%%%LOGTYPE%%%% log prefix '"FINAL_REJECT: "'sBadd rule inet %s filter_%s reject with icmpx type admin-prohibiteds$add chain inet %s filter_%s_IN_ZONESRtINtOUTs!add chain inet %s filter_%s_%s_%ss/add rule inet %s filter_%s jump filter_%s_%s_%stINPUT_ZONES_SOURCEt INPUT_ZONEStFORWARD_IN_ZONES_SOURCEtFORWARD_IN_ZONEStFORWARD_OUT_ZONES_SOURCEtFORWARD_OUT_ZONES( RRRRRWRR<RYRRR(RDRt default_rulestchaintdispatch_suffixR`t direction((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_default_ruless (0 (0  ( 4 (!  ((  cCsY|dkrdddgS|dkr,dgS|dkrBddgS|d krUdgSiS( NR Rt FORWARD_INt FORWARD_OUTRRRRR((RDRc((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytget_zone_table_chainss      R!c Cs|dkrr|dkrrg}|j|j||||||d|j|j||||||d|Sidd6dd6dd 6dd 6dd 6dd 6|} |t|d dkr|t|d  d}ntjdt|d|} d} |r3| r3dd|dtd||fdg} ne|r_dd|dtd||fg} n9dd|dtd||fg} |s| dg7} n|dkr| | d|| fg7} n(| | d|d| d|| fg7} | gS(NRR!R"R#tiifnameRtoifnameRRRRtOUTPUTit+t*RR^tgotoRPR\s%ss %s_%s_ZONESs%%ZONE_INTERFACE%%RQRbs%s_%ss"(textendt!build_zone_source_interface_rulesRZRtformatRR( RDtenableR^t interfaceRcRRWR`RtoptttargettactionR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyRs>  &# (cCsK|dkr|dkrg}|jdrI|j|td}nd}td|svt|sv|dkr|j|j|||||dntd|st|s|dkr|j|j|||||dn|Sidt6d t 6|} id d 6d d 6d d6d d6d d6d d6|} |j j r\d||f} nd||f} t j dt|d|} d} |jdr|td}|j|}d|}nCt|r| d krdSd}ntd|rd}nd}| d|dt| d||| || d|| fg }|gS(NRR!sipset:R7R"R9R#RPRbtsaddrRtdaddrRRRRRs%s_%s_ZONES_SOURCEs %s_%s_ZONESRR^Rt@RetetherR\s%ss%%ZONE_SOURCE%%s%s_%s(t startswitht_set_get_familyRZRURRRtbuild_zone_source_address_rulesRiRKR<RYRRRR(RDRR^taddressRcRR`Rt ipset_familytadd_delRtzone_dispatch_chainRRtipsett rule_familyR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR$sT''      c Cs.|dkr`|dkr`g}|j|j|||d|j|j|||d|Stjdt|d|}t||jt|d|d|d |gg}|jd d|d t d ||fg|jd d|d t d ||fg|jd d|d t d||fg|jd d|d t d||fg|jd d|d t d ||fdd ||fg|jd d|d t d ||fdd||fg|jd d|d t d ||fdd||fg|j j j |j }|j jdkr|dkr|d kr|d!kr|}|dkrud}n|jd d|d t d ||fdddd||fg qqn|dkr*|d"kr*|d#kr*|jd d|d t d ||f|dkr|jndgn|S($NRR!R"R#RR^s%s_logs%s_denys%s_allowRQs%ss%s_%ss %s_%s_logs %s_%s_denys %s_%s_allowR\tjumpRR RRRRtREJECTs %%REJECT%%Rs %%LOGTYPE%%Rtprefixs"filter_%s_%s: "R(sINPUTs FORWARD_INs FORWARD_OUTsOUTPUT(Rs %%REJECT%%sDROP(sACCEPTRs %%REJECT%%sDROP(sINPUTs FORWARD_INs FORWARD_OUTsOUTPUT(Rtbuild_zone_chain_rulesRRRRRRRWRR<R^t_zonesRtget_log_deniedtlower( RDR^RcRR`Rt_zoneRt log_suffix((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR^s^            %cCsiddddgd6ddddgd6ddddgd6ddddgd 6dddd gd 6dddd gd 6dd dd gd6dd dd gd6ddddgd6ddddgd6ddddgd6ddddgd6ddddgd6dd ddgd6ddddgd6ddddgd6ddddgd6dd ddgd6dd ddgd 6dd dd!gd"6dd dd!gd!6dd#d$gd%6dd#d$gd&6}||S('NRR$R%shost-prohibitedsicmp-host-prohibiteds host-prohibsnet-prohibitedsicmp-net-prohibiteds net-prohibsadmin-prohibitedsicmp-admin-prohibiteds admin-prohibR8sicmp6-adm-prohibitedsadm-prohibitedsnet-unreachablesicmp-net-unreachables net-unreachshost-unreachablesicmp-host-unreachables host-unreachsport-unreachablesicmp-port-unreachablesicmp6-port-unreachableRs port-unreachsprot-unreachablesicmp-proto-unreachables proto-unreachsaddr-unreachablesicmp6-addr-unreachables addr-unreachsno-routesicmp6-no-routettcptresets tcp-resetstcp-rst((RDt reject_typetfrags((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_reject_types_fragments2cCs|s gSidd6dd6dd6dd6}y|jjd }Wn tk rdttd nXd d |jd |!d ||j|dgS(Ntsecondtstminutetmthourthtdaytdt/sExpected '/' in limittlimittrateii(tvalueRRRTR R (RDRt rich_to_nftR]((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_limit_fragments  cCs|js gSidt6dt6|}|dddtd||fg}||dg7}|jjr|dd |jjg7}n|jjr|d d |jjg7}n||j|jj7}|S( NRQRbR\R!s%ss %s_%s_logRRs"%s"tlevel(RRiRKRRRRR(RDt rich_ruleRRcRt rule_fragmentRR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_logs   cCs||js gSidt6dt6|}|dddtd||fg}||ddd g7}||j|jj7}|S( NRQRbR\R!s%ss %s_%s_logRRtaudit(RRiRKRRR(RDRRRcRRRR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_audits c Cs|js gSidt6dt6|}t|jtkrVd||f}dg} nt|jtkrd||f}dg} |jjr^| |j|jj7} q^nt|jtkrd||f}dg} n~t|jtkrBt j dt d d |}d }d||f}d d d|jj g} nt tdt|j|dddt|g} | |7} | |j|jj7} | | 7} | S(NRQRbs %s_%s_allowtaccepts %s_%s_denyRtdropRRR^RRtmarkRsUnknown action %sR\R!s%s(RRiRKR%RRRRRRRRRR R RRR( RDR^RRRcRRRRt rule_actionR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_actions6        cCsS|s gS|dkr#dddgS|dkr<dddgSttd|dS(NR7RtnfprotoR9sInvalid family(R R (RDt rich_family((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_family_fragments    cCsx|s gSg}td|jr2|dg7}n |dg7}|jra|dd|jg7}n|d|jg7}|S(NR7R"R#Rs!=(Rtaddrtinvert(RDt rich_destR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_destination_fragments  cCsJ|s gSg}|jrtd|jr;|dg7}n |dg7}|jrj|dd|jg7}qF|d|jg7}nt|dr|jr|jr|ddd|jg7}qF|dd|jg7}npt|drF|jrF|j|j}|jr)||ddd |jg7}qF||dd |jg7}n|S( NR7R"R#Rs!=tmacRRR(RRRthasattrRRR(RDt rich_sourceRR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_rich_rule_source_fragment,s(      c Csidt6dt6|}d}tjdtdd|} g} |r_| |j|j7} n|rtd|r| dg7} n | d g7} | d |g7} n|r| |j|j 7} | |j |j 7} n| |d d t |d g7} | st |jtkr+| dddg7} ng} |r| j|j|||| | | j|j|||| | | j|j||||| | n5| j|ddd td|| fg| dg| S(NRQRbR RRR^R7R"R#Rtdports%st-tcttstates new,untrackedR\R!s %s_%s_allowR(RiRKRRRRR`RRt destinationR tsourceRR%RRRWRRRR( RDRR^tprototportRRRRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_ports_rulesIs2  ""(/c Csidt6dt6|}d}tjdtdd|}g} |r_| |j|j7} n|rtd|r| dg7} n | d g7} | d |g7} n|r| |j|j7} | |j|j 7} | |j |j 7} nd d |g} | st |j tkr0| d ddg7} ng} |r| j|j||||| | j|j||||| | j|j|||||| n/| j|dddtd|g| dg| S(NRQRbR RRR^R7R"R#RRRR R s new,untrackedR\R!s%ssfilter_%s_allowR(RiRKRRRRR`RRRR RR%RRRWRRRR( RDRR^tprotocolRRRRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_protocol_rulesjs4 ""()c Csidt6dt6|}d}tjdtdd|} g} |r_| |j|j7} n|rtd|r| dg7} n | d g7} | d |g7} n|r| |j|j 7} | |j |j 7} n| |d d t |d g7} | st |jtkr+| dddg7} ng} |r| j|j|||| | | j|j|||| | | j|j||||| | n5| j|ddd td|| fg| dg| S(NRQRbR RRR^R7R"R#Rtsports%sR R R s new,untrackedR\R!s %s_%s_allowR(RiRKRRRRR`RRRR RRR%RRRWRRRR( RDRR^RRRRRRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_source_ports_ruless2  ""(/c Csidt6dt6|}tjdtdd|} |dddtd | g} |rtd |rv| d g7} n | d g7} | d |g7} n| |ddt|dg7} | dddd||fg7} dddtd||fddd|d|ddg } | | gS(NRQRbRRR^R\R!s%ssfilter_%s_allowR7R"R#RR R R thelperRs"helper-%s-%s"s helper-%s-%st{R%s"%s"Rt;t}(RiRKRRRRRR( RDRR^RRRt helper_nametmodule_short_nameRRR\t helper_object((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_helper_ports_ruless"       cCsidt6dt6|}tjdtdd|}g}|ro||j|j7}||j|j7}n|d|dt d|g|d d d d ggS( NRQRbRRR^R\s%ss nat_%s_allowRs!=tlot masquerade( RiRKRRRRRR RR(RDRR^R`RRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt _build_zone_masquerade_nat_ruless cCsg}|rd|jr$|jdksB|jrdtd|jjrd|j|j||d|n}|r|jr|jdks|jrtd|jjr|j|j||d|n|j|j||d|idt6dt6|}tj dt dd |}g}|rP||j |j 7}||j |j7}n|j|d d d td |g|ddddg|S(NR9R#R7R"RQRbRRR^R\R!s%ssfilter_%s_allowR R s new,untrackedR(R`RRRRR!RiRKRRRRRR RWR(RDRR^RRRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_masquerade_ruless$"" 2c Csidt6dt6|}tjdtdd|} g} |rV| dd|g7} n| ddg7} |r|d kr| d t|d g7} n|d |d td| dd|g|| gS(NRQRbRRR^tdnatttoR+Res:%sR R\s%ss nat_%s_allowRR(RiRKRRRRR( RDRR^Rt mark_fragmentttoaddrttoportR`RRt dnat_fragment((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt"_build_zone_forward_port_nat_ruless c Csaidt6dt6|} d|} dd| g} tjdtdd|} g}| r||j| j7}||j| j7}||j | j 7}ng}|j | d d d t d | g||d |ddd| g| rC| jr| jdks|rCt d|rC|j|j|||| ||dn| r| jra| jdksv|rt d|r|j|j|||| ||dnh|rt d|r|j|j|||| ||dn(|j|j|||| ||dtjdt|d|} |j | d d d t d| dddg| dg|S(NRQRbs0x%xRRRRR^R\R!s%ssmangle_%s_allowR RR9R#R7R"sfilter_%s_allowR R s new,untrackedR(RiRKRRRRR`RRR RRWRRRR)(RDRR^t filter_chainRRR'R&tmark_idRRtmark_strR%RRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_forward_port_ruless@   2cCs<|t|krt||Sttd||jfdS(Ns"ICMP type '%s' not supported by %s(RR R tname(RDRt icmp_type((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_icmp_types_to_nft_fragment/s c Csd}idt6dt6|}|r9|jr9|j}n\|jrg}d|jkrg|jdnd|jkr|jdqn ddg}g}x/|D]'} xddgD]} tjdt| d |} |jj j |rd || f} d } nd || f} d } g}|rl||j |j 7}||j |j7}||j|j7}n||j| |j7}|r8|j|j|||| ||j|j|||| ||jr|j|j||||| |q|j|dddtd || fg|d gq|jjdkr| d kr|j|dddt| g|dddd||fgn|j|dddt| g|| gqWqW|S(NR RQRbR7R9RRRR^s %s_%s_allowRs %s_%s_denys %%REJECT%%R\R!s%sRs %%LOGTYPE%%RRs"%s_%s_ICMP_BLOCK: "(RiRKtipvsRRWRRRR<R^tquery_icmp_block_inversionRR`RR RR0R.RRRRRR(RDRR^tictRRcRR1RRRRt final_chaint final_targetR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_zone_icmp_block_rules6sT      "" (2! -c Csd}g}xddgD]}tjdt|d|}djddtd ||fd d ||fg}|j|}|jjj|rd } nd } |rddddtd ||fd|g} n#ddddtd ||fg} | d| g7} |j | |jjj|r|jj dkr|rpddddtd ||fd|g} n#ddddtd ||fg} | ddddd||fg7} |j | qqqW|S(NR RRRR^RgR!s%ss%s_%sRs %s_%s_allows %%REJECT%%RRQR\RfRbs%%ICMP%%Rs %%LOGTYPE%%RRs"%s_%s_ICMP_BLOCK: "( RRRRlRRAR<R^R2RWR( RDRR^RcRRRRxt rule_handlet ibi_targetR\((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt%build_zone_icmp_block_inversion_rulesls<     cCsg}|jddddtdddd d d d d dddg|dkr|jddddtdddd d d d d dddddgn|jddddtdddddg |S(NRPR\R!s%ssraw_%sRRRR9tfibRt.tiiftoiftmissingRRRRs"rpfilter_DROP: "R8R%s){ nd-router-advert, nd-neighbor-solicit }Rtraw_PREROUTINGR?R?(RWR(RDRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytbuild_rpfilter_ruless   cCsd}tjdtdd|}g}||j|j7}||j|j7}||j|j7}g}|j |j ||||||j |j ||||||j |j |||||||S(NR RRR^( RRRRR`RRR RRWRRR(RDRR^RRcRRR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt(build_zone_rich_source_destination_ruless ""%cCs|dkrtStS(NR7R9teb(sipv4sipv6RB(RiRK(RDR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytis_ipv_supporteds cCs;idd6dd6}i ||gd6||ddgd6||dd ||gd 6||dd ||gd 6||d gd 6||gd6||ddgd6||dd ||gd6||dd ||gd6||dgd6dgd6}ydg||dgSWn$tk r6ttd|nXdS(Nt ipv4_addrR7t ipv6_addrR9shash:ips . inet_protos. inet_services hash:ip,ports. inet_service .shash:ip,port,ipshash:ip,port,nets. marks hash:ip,markshash:nets hash:net,portshash:net,port,ipshash:net,port,nets. ifnameshash:net,ifacet ether_addrshash:macR%Rs!ipset type name '%s' is not valid(tKeyErrorR R(RDRR%tipv_addrttypes((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_set_type_fragments(   c Cs)|r+d|kr+|ddkr+d}nd}|dg}||j||7}|rd|kr|d|dddg7}nd |kr|d |d dg7}qn| sd|krd |kr|d d dg7}n|dg7}x4dddgD]#}|jdd|tg|qWdS(NR`tinet6R9R7RttimeoutRRtmaxelemtsizet,tflagstintervalRR!R"R#RQR(RJRR(RDR.R%toptionsRtcmdR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_creates "      cCs:x3dddgD]"}|jdd|t|gqWdS(NR!R"R#RbR(RR(RDR.R`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_destroyscCs)|jjj|jddjd}|jd}t|t|krdttdng}xtt|D]}||dkry||jd}Wn(t k r|dd||g7}qX|||| d|||dg7}n|j |||j dq}W|d S( Nt:iROs+Number of values does not match ipset type.RRR;i( R<Rtget_typetsplitRZR RtrangeRRRTRW(RDR.tentryt type_formatt entry_tokenstfragmentR]RR((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt_set_entry_fragments +  *cCsTxMdddgD]<}|jdd|t|dg|j||dgqWdS(NR!R"R#RQtelementRR(RRR^(RDR.RZR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pytset_addscCsTxMdddgD]<}|jdd|t|dg|j||dgqWdS(NR!R"R#RbR_RR(RRR^(RDR.RZR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_deletescCs:x3dddgD]"}|jdd|t|gqWdS(NR!R"R#tflushR(RR(RDR.R`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyt set_flushscCsk|jjj|}|jdkr-d}n:|jrad|jkra|jddkrad}nd}|S(Nshash:macRR`RKR#R"(R<Rt get_ipsetR%RR(RDR.RR`((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR!s  N(7t__name__t __module__R.Ritzones_supportedRFR?RaRRRRRRURRRRRRRRKRRRRRRRRRRR RRRRR!R"R)R-R0R6R9R@RARCRJRTRUR^R`RaRcR(((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyR:sf  - U      T  + 9 @   "  !#!     ,  6 2          (%tos.pathRGRotfirewall.core.baseRRtfirewall.core.progRtfirewall.core.loggerRtfirewall.functionsRRRRRtfirewallR tfirewall.errorsR R R R RRtfirewall.core.richRRRRRRRRRtobjectR:(((s:/usr/lib/python2.7/site-packages/firewall/core/nftables.pyts  (."   PK!~N fw_policies.pycnu[ c`c@ssdgZddlmZddlmZddlmZddlmZddlm Z de fdYZ dS( tFirewallPoliciesi(tconfig(tlog(tLockdownWhitelist(terrors(t FirewallErrorcBsGeZdZdZdZdZdZdZdZRS(cCst|_ttj|_dS(N(tFalset _lockdownRRtLOCKDOWN_WHITELISTtlockdown_whitelist(tself((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyt__init__s cCsd|j|j|jfS(Ns %s(%r, %r)(t __class__RR (R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyt__repr__#scCst|_|jjdS(N(RRR tcleanup(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyR's cCs|dkrCtjd||jj|r tjdtSn|dkrtjd||jj|r tjdtSn|dkrtjd||jj|r tjd tSnC|d kr tjd ||jj|r tjd tSnt S( Ntcontexts#Doing access check for context "%s"scontext matches.tuidsDoing access check for uid %ds uid matches.tusers Doing access check for user "%s"s user matches.tcommands#Doing access check for command "%s"scommand matches.( Rtdebug2R t match_contexttdebug3tTruet match_uidt match_usert match_commandR(R tkeytvalue((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyt access_check-s*        cCs+|jrttjdnt|_dS(Nsenable_lockdown()(RRRtALREADY_ENABLEDR(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pytenable_lockdownDs cCs+|jsttjdnt|_dS(Nsdisable_lockdown()(RRRt NOT_ENABLEDR(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pytdisable_lockdownIs cCs|jS(N(R(R ((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pytquery_lockdownNs( t__name__t __module__R R RRRR R!(((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyRs      N( t__all__tfirewallRtfirewall.core.loggerRt#firewall.core.io.lockdown_whitelistRRtfirewall.errorsRtobjectR(((s=/usr/lib/python2.7/site-packages/firewall/core/fw_policies.pyts PK!CIR%$%$ ebtables.pyonu[ c`c@sdgZddlZddlmZddlmZddlmZm Z m Z ddl m Z ddl mZddlmZmZddlZid gd 6d d d gd6dd dgd6ZiZiZiZxejD]Zgees0      PK!ZZ fw_ifcfg.pycnu[ c`c@spdZddgZddlZddlZddlmZddlmZddlm Z dZ d Z dS( s.Functions to search for and change ifcfg filestsearch_ifcfg_of_interfacetifcfg_set_zone_of_interfaceiN(tconfig(tlog(tifcfgcCstjjtjsd SxttjtjD]}|jdsMq2nx5ddddddgD]}|j |rfqfqfqfWd|krq2nt d tj|f}|j |j d |kr2|Sq2Wd tj|f}tjj|rt |}|j |Sd S( s6search ifcfg file for the interface in config.IFCFGDIRsifcfg-s.baks.origs.rpmnews.rpmorigs.rpmsaves-ranget.s%s/%stDEVICEs %s/ifcfg-%sN( tostpathtexistsRtIFCFGDIRtNonetsortedtlistdirt startswithtendswithRtreadtget(t interfacetfilenametignoredt ifcfg_file((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ifcfg.pyR!s*      cCs|dkrd}nt|}|dk r|jd|kr|jddko`|dk rtjd||jf|jd||jndS(sYSet zone (ZONE=) in the ifcfg file that uses the interface (DEVICE=)ttZONEsSetting ZONE=%s in '%s'N(R RRRtdebug1Rtsettwrite(tzoneRR((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ifcfg.pyR?s   !"( t__doc__t__all__Rtos.pathtfirewallRtfirewall.core.loggerRtfirewall.core.io.ifcfgRRR(((s:/usr/lib/python2.7/site-packages/firewall/core/fw_ifcfg.pyts    PK!8^^rich.pyonu[ c`c@sdddddddddd d d d d ddddgZddlmZddlmZddlmZddlmZddlm Z de fdYZ de fdYZ de fdYZ de fdYZdefdYZde fdYZde fdYZde fdYZde fd YZd e fd!YZd e fd"YZd e fd#YZd e fd$YZd e fd%YZdefd&YZde fd'YZde fd(YZde fd)YZd*S(+t Rich_SourcetRich_Destinationt Rich_Servicet Rich_Portt Rich_ProtocoltRich_MasqueradetRich_IcmpBlockt Rich_IcmpTypetRich_SourcePorttRich_ForwardPorttRich_Logt Rich_Auditt Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_Markt Rich_Limitt Rich_Rulei(t functions(tcheck_ipset_name(t REJECT_TYPES(terrors(t FirewallErrorcBseZedZdZRS(cCs||_|jdkr$d|_n||_|jdksK|jdkrWd|_n$|jdk r{|jj|_n||_|jdkrd|_n||_|jdkr|jdkr|jdkrttjdndS(Ntsno address, mac and ipset( taddrtNonetmactuppertipsettinvertRRt INVALID_RULE(tselfRRRR((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyt__init__$s       - cCsd|jrdnd}|jdk r7|d|jS|jdk rU|d|jS|jdk rs|d|jSttjddS(Ns source%s s NOTRs address="%s"smac="%s"s ipset="%s"sno address, mac and ipset(RRRRRRRR(Rtret((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyt__str__5s (t__name__t __module__tFalseR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR#s cBseZedZdZRS(cCs||_||_dS(N(RR(RRR((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR Bs cCs d|jrdnd|jfS(Nsdestination %saddress="%s"snot R(RR(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Fs(R#R$R%R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRAs cBseZdZdZRS(cCs ||_dS(N(tname(RR&((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR KscCs d|jS(Nsservice name="%s"(R&(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Ns(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRJs cBseZdZdZRS(cCs||_||_dS(N(tporttprotocol(RR'R(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR Rs cCsd|j|jfS(Nsport port="%s" protocol="%s"(R'R((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Vs(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRQs cBseZdZRS(cCsd|j|jfS(Ns#source-port port="%s" protocol="%s"(R'R((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"Zs (R#R$R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRYscBseZdZdZRS(cCs ||_dS(N(tvalue(RR)((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR _scCs d|jS(Nsprotocol value="%s"(R)(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"bs(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR^s cBseZdZdZRS(cCsdS(N((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR fscCsdS(Nt masquerade((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"is(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRes cBseZdZdZRS(cCs ||_dS(N(R&(RR&((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR mscCs d|jS(Nsicmp-block name="%s"(R&(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"ps(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRls cBseZdZdZRS(cCs ||_dS(N(R&(RR&((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR tscCs d|jS(Nsicmp-type name="%s"(R&(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"ws(R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRss cBseZdZdZRS(cCs^||_||_||_||_|jdkr?d|_n|jdkrZd|_ndS(NR(R'R(tto_portt to_addressR(RR'R(R+R,((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR {s     cCsRd|j|j|jdkr+d|jnd|jdkrJd|jndfS(Ns(forward-port port="%s" protocol="%s"%s%sRs to-port="%s"s to-addr="%s"(R'R(R+R,(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s (R#R$R R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR zs cBs#eZddddZdZRS(cCs||_||_||_dS(N(tprefixtleveltlimit(RR-R.R/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s  cCsSd|jrd|jnd|jr2d|jnd|jrKd|jndfS(Ns log%s%s%ss prefix="%s"Rs level="%s"s %s(R-R.R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"sN(R#R$RR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR scBseZddZdZRS(cCs ||_dS(N(R/(RR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR scCsd|jrd|jndS(Nsaudit%ss %sR(R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"sN(R#R$RR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cBseZddZdZRS(cCs ||_dS(N(R/(RR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR scCsd|jrd|jndS(Nsaccept%ss %sR(R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"sN(R#R$RR R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cBs)eZdddZdZdZRS(cCs||_||_dS(N(ttypeR/(Rt_typeR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cCs:d|jrd|jnd|jr2d|jndfS(Ns reject%s%ss type="%s"Rs %s(R0R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"scCs|jr{|s$ttjdn|dkr{|jt|kr{djt|}ttjd|j|fq{ndS(Ns9When using reject type you must specify also rule family.tipv4tipv6s, s%Wrong reject type %s. Use one of: %s.(R2R3(R0RRRRtjoin(Rtfamilyt valid_types((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pytchecks  N(R#R$RR R"R7(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cBseZdZRS(cCsd|jrd|jndS(Nsdrop%ss %sR(R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s(R#R$R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRscBs&eZddZdZdZRS(cCs||_||_dS(N(tsetR/(Rt_setR/((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s cCs'd|j|jrd|jndfS(Ns mark set=%s%ss %sR(R8R/(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s cCs|jdk r|j}nttjdd|kr|jd}t|dkrottj|ntj|d stj|d rttj|qn$tj|sttj|ndS(Ns no value sett/iii( R8RRRt INVALID_MARKtsplittlenRt checkUINT32(Rtxtsplits((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR7s  N(R#R$RR R"R7(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRs  cBs,eZdZdZdZdZRS(cCsu||_d|jkrq|jjd}t|dkrq|dd krqd|d |dd f|_qqndS( NR:iitsecondtminutethourtdays%s/%si(RARBRCRD(R)R<R=(RR)R@((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s  cCsd}d|jkr*|jjd}n| sCt|dkr[ttj|jn|\}}yt|}Wnttj|jnX|dks|dkrttj|jnd}|dkrd}n?|dkrd}n*|dkr d}n|dkr d}nd ||d krPttjd |jn|dkr|dkrttjd |jndS(NR:iitstmthtdi<ii'is %s too fasts %s too slow(RERFRGRHiiiQ(RR)R<R=RRt INVALID_LIMITtint(RR@tratetdurationtmult((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR7s6           cCs d|jS(Nslimit value="%s"(R)(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"scCsdS(NR((R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pytcommand s(R#R$R R7R"RN(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRs  " cBs;eZdddZdZdZdZdZRS(cCsw|dk rt||_n d|_d|_d|_d|_d|_d|_d|_|rs|j |ndS(N( RtstrR5tsourcet destinationtelementtlogtaudittactiont_import_from_string(RR5trule_str((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s        cCsg}xtj|D]}d|kr|jd}t|dks_|d s_|d rxttjd|n|ji|dd6|dd6q|ji|d6qW|jid d6|S( s Lexical analysis t=iiisinternal error in _lexer(): %st attr_namet attr_valueRRtEOL(Rt splitArgsR<R=RRRtappend(RRWttokenstrtattr((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyt_lexers ( &c Cs |sttjdnd|_d|_d|_d|_d|_d|_ d|_ |j |}|r|dj ddkrttjdni}g}d}x ||j ddko|dgks ||j d}||j d}||j d}|rA|d?kr|ttjd|q|n;|d@krf|dkrw|jrwttjd)q||dkr|jrttjd*q||dAkr|jrttjd+||jfq||d kr|jrttjd,q||d!kr,|j r,ttjd-q||dBkr||j r|ttjd.||j fq|nttjd/|t |dkr|t |d0nd1} | d1kr<| r|r|dkrttjd2q9ttjd3||fq d|kr,ttjd4||fq |jdnx| dkr|dkr|dCkryttjd7|n||_q |r|dkrd8} nd9||f} ttj| q |j|n| dkrs|dDkr|||n|d0}qW|j$dS(LNs empty ruleiRRR[truleRYRZR5taddressRRRR)R'R(sto-portsto-addrR&R-R.R0R8sbad attribute '%s'RPRQtservices icmp-blocks icmp-typeR*s forward-ports source-portRSRTtaccepttdroptrejecttmarkR/tnottNOTsmore than one 'source' elements#more than one 'destination' elementsFmore than one element. There cannot be both '%s' and '%s' in one rule.smore than one 'log' elementsmore than one 'audit' elementsOmore than one 'action' element. There cannot be both '%s' and '%s' in one rule.sunknown element %siRs0'family' outside of rule. Use 'rule family=...'.s:'%s' outside of any element. Use 'rule %s= ...'.s,'%s' outside of rule. Use 'rule ... %s ...'.R2R3sH'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead.sdwrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'.sDattribute '%s' outside of any element. Use 'rule %s= ...'.sinvalid 'protocol' elementsinvalid 'service' elementsinvalid 'icmp-block' elementsinvalid 'icmp-type' elementsinvalid 'limit' element(sfamilyRcsmacsipsetsinvertsvaluesportsprotocolsto-portsto-addrsnamesprefixslevelstypesset(Rbssources destinationsprotocolRdsports icmp-blocks icmp-types masquerades forward-ports source-portslogsauditReRfRgsmarkslimitRiRjsEOL(sprotocolRdsports icmp-blocks icmp-types masquerades forward-ports source-port(ReRfRgsmark(sipv4sipv6(Rcsmacsipsetsinvert(RiRj(Rcsinvert(RiRj(sportsprotocol(sportsprotocolsto-portsto-addr(sportsprotocol(sprefixslevel(%RRRRR5RPRQRRRSRTRURatgetR=R]tTrueRR%tpoptclearRRRRRRRR RR R R RR RRR7( RRWR^tattrst in_elementstindexRRRYRZt in_elementterr_msg((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyRV.st       +  "%,               ?        $            $                 <      $       0                      $             cCs |jdk r6|jdkr6ttj|jn|jdkr|jdk rf|jjdk su|jdk rttjnt |j t krttjqn|j dkr|j dkrttj dn|jdkr|jdkrttj dqnt |j tt tgkr}|jdkr}|jdkr}|j dkr}ttj dq}n|jdk r|jjdk rL|jdkrttjn|jjdk rttj dn|jjdk r ttj dntj|j|jjsttjt|jjqq|jjdk r|jjdk rttj dntj|jjsttjt|jjqq|jjdk rt|jjsttjt|jjqqttj d n|jdk r|jdkrKttjn|jjdksytj|j|jj rttjt|jjqnt |j tkr|j jdkst|j jd kr>ttjt|j jq>n>t |j t krutj!|j j"sEttj#|j j"n|j j$dkr>ttj%|j j$q>nt |j t&krtj'|j j(s>ttj%|j j(q>nt |j tkr/|j dk rttj dn|jdk r>|jjdk r>ttj dq>nt |j tkr|j jdksnt|j jd krttj)t|j jn|j r>ttj dq>nt |j t*kr|j jdkst|j jd kr>ttj)t|j jq>n+t |j t krtj!|j j"sXttj#|j j"n|j j$dkrttj%|j j$n|j j+dkr|j j,dkrttj#|j j+n|j j+dkrtj!|j j+ rttj#|j j+n|j j,dkrPtj-|j|j j, rPttj|j j,n|jdkrqttjn|j dk r>ttj dq>nt |j t.kr tj!|j j"sttj#|j j"n|j j$d kr>ttj%|j j$q>n1|j dk r>ttj dt |j n|jdk r|jj/r|jj/d!krttj0|jj/n|jj1dk r|jj1j2qn|jdk r! t |j t3t4t5gkrttj6t |j n|jj1dk r! |jj1j2q! n|j dk r t |j t4kr[ |j j2|jn%t |j t7kr |j j2n|j j1dk r |j j1j2q ndS("NR2R3sno element, no actions%no element, no source, no destinationsno action, no log, no auditsaddress and macsaddress and ipsets mac and ipsetsinvalid sourceittcptudptsctptdccpsmasquerade and actionsmasquerade and mac sourcesicmp-block and actionRsforward-port and actionsUnknown element %stemergtalerttcritterrortwarningtnoticetinfotdebug(sipv4sipv6(RtRuRvRw(RtRuRvRw(RtRuRvRw(RxRyRzserrorR|R}sinfosdebug(8R5RRRtINVALID_FAMILYRPRRQtMISSING_FAMILYR0RRR RURRRRSRTRRRt check_addresst INVALID_ADDRROt check_mact INVALID_MACRt INVALID_IPSETRR&R=tINVALID_SERVICERt check_portR't INVALID_PORTR(tINVALID_PROTOCOLRt checkProtocolR)tINVALID_ICMPTYPERR+R,tcheck_single_addressRR.tINVALID_LOG_LEVELR/R7R R RtINVALID_AUDIT_TYPER(R((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR7 s! $$$ $*$!*! *$$     cCsd}|jr#|d|j7}n|jr@|d|j7}n|jr]|d|j7}n|jrz|d|j7}n|jr|d|j7}n|jr|d|j7}n|jr|d|j7}ntjrtj |S|S(NRbs family="%s"s %s( R5RPRQRRRSRTRURtPY2tu2b(RR!((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR"s        N(R#R$RR RaRVR7R"(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyR s   N(t__all__tfirewallRtfirewall.core.ipsetRtfirewall.core.baseRRtfirewall.errorsRtobjectRRRRRRRRRR R R R R RRRR(((s6/usr/lib/python2.7/site-packages/firewall/core/rich.pyts8       1PK!~ watcher.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2012-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__ = [ "Watcher" ] from gi.repository import Gio, GLib class Watcher(object): def __init__(self, callback, timeout): self._callback = callback self._timeout = timeout self._monitors = { } self._timeouts = { } self._blocked = [ ] def add_watch_dir(self, directory): gfile = Gio.File.new_for_path(directory) self._monitors[directory] = gfile.monitor_directory(\ Gio.FileMonitorFlags.NONE, None) self._monitors[directory].connect("changed", self._file_changed_cb) def add_watch_file(self, filename): gfile = Gio.File.new_for_path(filename) self._monitors[filename] = gfile.monitor_file(\ Gio.FileMonitorFlags.NONE, None) self._monitors[filename].connect("changed", self._file_changed_cb) def get_watches(self): return self._monitors.keys() def has_watch(self, filename): return filename in self._monitors def remove_watch(self, filename): del self._monitors[filename] def block_source(self, filename): if filename not in self._blocked: self._blocked.append(filename) def unblock_source(self, filename): if filename in self._blocked: self._blocked.remove(filename) def clear_timeouts(self): for filename in list(self._timeouts.keys()): GLib.source_remove(self._timeouts[filename]) del self._timeouts[filename] def _call_callback(self, filename): if filename not in self._blocked: self._callback(filename) del self._timeouts[filename] def _file_changed_cb(self, monitor, gio_file, gio_other_file, event): filename = gio_file.get_parse_name() if filename in self._blocked: if filename in self._timeouts: GLib.source_remove(self._timeouts[filename]) del self._timeouts[filename] return if event == Gio.FileMonitorEvent.CHANGED or \ event == Gio.FileMonitorEvent.CREATED or \ event == Gio.FileMonitorEvent.DELETED or \ event == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED: if filename in self._timeouts: GLib.source_remove(self._timeouts[filename]) del self._timeouts[filename] self._timeouts[filename] = GLib.timeout_add_seconds(\ self._timeout, self._call_callback, filename) PK!َ:  fw_ifcfg.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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 . # """Functions to search for and change ifcfg files""" __all__ = [ "search_ifcfg_of_interface", "ifcfg_set_zone_of_interface" ] import os import os.path from firewall import config from firewall.core.logger import log from firewall.core.io.ifcfg import ifcfg def search_ifcfg_of_interface(interface): """search ifcfg file for the interface in config.IFCFGDIR""" # Return quickly if config.IFCFGDIR does not exist if not os.path.exists(config.IFCFGDIR): return None for filename in sorted(os.listdir(config.IFCFGDIR)): if not filename.startswith("ifcfg-"): continue for ignored in [ ".bak", ".orig", ".rpmnew", ".rpmorig", ".rpmsave", "-range" ]: if filename.endswith(ignored): continue if "." in filename: continue ifcfg_file = ifcfg("%s/%s" % (config.IFCFGDIR, filename)) ifcfg_file.read() if ifcfg_file.get("DEVICE") == interface: return ifcfg_file # Wasn't found above, so assume filename matches the device we want filename = "%s/ifcfg-%s" % (config.IFCFGDIR, interface) if os.path.exists(filename): ifcfg_file = ifcfg(filename) ifcfg_file.read() return ifcfg_file return None def ifcfg_set_zone_of_interface(zone, interface): """Set zone (ZONE=) in the ifcfg file that uses the interface (DEVICE=)""" if zone is None: zone = "" ifcfg_file = search_ifcfg_of_interface(interface) if ifcfg_file is not None and ifcfg_file.get("ZONE") != zone and not \ (ifcfg_file.get("ZONE") is None and zone == ""): log.debug1("Setting ZONE=%s in '%s'" % (zone, ifcfg_file.filename)) ifcfg_file.set("ZONE", zone) ifcfg_file.write() PK!zzfw.pycnu[ c`c@sdgZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddl m Z ddl mZdd l mZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl$m%Z%ddl&m'Z'ddl(m)Z)ddl*m+Z+ddl,m-Z-m.Z.ddl/m0Z0ddl1m2Z2ddlm3Z3ddl4m5Z5de6fdYZ7dS(tFirewalliN(tconfig(t functions(t ipXtables(tebtables(tnftables(tipset(tmodules(tFirewallIcmpType(tFirewallService(t FirewallZone(tFirewallDirect(tFirewallConfig(tFirewallPolicies(t FirewallIPSet(tFirewallTransaction(tFirewallHelper(tlog(tfirewalld_conf(tDirect(tservice_reader(ticmptype_reader(t zone_readertZone(t ipset_reader(t helper_reader(terrors(t FirewallErrorcBseZdZdZdZdZdZdZeedZ dZ edZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZedZedZedZedZdZdZdZ dZ!dZ"dZ#d Z$d!Z%d"Z&d#Z'd$Z(d%Z)ed&Z*d'Z+d(Z,d)Z-d*Z.d+Z/d,Z0d-Z1d.Z2d/Z3d0Z4RS(1cCs@ttj|_tj||_t|_g|_ tj ||_ t|_ g|_ tj|_t|_tj|_t|_g|_tj||_t|_tj|_t||_t||_t||_t ||_!t"||_t#|_$t%||_t&||_'|j(dS(N()RRtFIREWALLD_CONFt_firewalld_confRt ip4tablestip4tables_backendtTruetip4tables_enabledtip4tables_supported_icmp_typest ip6tablestip6tables_backendtip6tables_enabledtip6tables_supported_icmp_typesRtebtables_backendtebtables_enabledRt ipset_backendt ipset_enabledtipset_supported_typesRtnftables_backendtnftables_enabledRtmodules_backendRticmptypeR tserviceR tzoneR tdirectR R tpoliciesRRthelpert_Firewall__init_vars(tself((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt__init__?s0         cCshd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |j|jfS(Ns>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)(t __class__R!R%R(t_statet_panict _default_zonet_module_refcountt_markst _min_marktcleanup_on_exittipv6_rpfilter_enabledR*t_individual_callst _log_deniedt_automatic_helpers(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt__repr__]scCsd|_t|_d|_i|_g|_tj|_tj |_ tj |_ tj |_tj|_tj|_tj|_d|_tj|_dS(NtINITti(R9tFalseR:R;R<R=RtFALLBACK_MINIMAL_MARKR>tFALLBACK_CLEANUP_ON_EXITR?tFALLBACK_IPV6_RPFILTERR@tFALLBACK_INDIVIDUAL_CALLSRAtFALLBACK_LOG_DENIEDRBtFALLBACK_AUTOMATIC_HELPERSRCtFALLBACK_FIREWALL_BACKENDt_firewall_backendtnf_conntrack_helper_settingtFALLBACK_ALLOW_ZONE_DRIFTINGt_allow_zone_drifting(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt __init_varsfs             cCs|jS(N(RA(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytindividual_callswscCs|jr=d|jdjkr=tjdt|_n|jrzd|jdjkrztjdt|_n|jrd|jdjkrtjdt|_n|j r|j r|j rtj dt j d ndS( Ntfiltertipv4s-iptables not usable, disabling IPv4 firewall.tipv6s.ip6tables not usable, disabling IPv6 firewall.tebs8ebtables not usable, disabling ethernet bridge firewall.sNo IPv4 and IPv6 firewall.i( R!tget_backend_by_ipvtget_available_tablesRtwarningRGR%R(R-tfataltsystexit(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt _check_tableszs            cCsy|jjWn0tk rCtjdt|_g|_nX|jj|_|j j |j j s|j j rtjdqtjdt|_ n|j r|j j|_n g|_|jj |jj s|jj rtjdqtjdt|_n|jr7|jj|_n g|_|jj |jj s|jj rutjdqtjdt|_n|jr|j r|jj rtjdndS( Ns4ipset not usable, disabling ipset usage in firewall.sFiptables-restore is missing, using individual calls for IPv4 firewall.sCiptables-restore and iptables are missing, disabling IPv4 firewall.sGip6tables-restore is missing, using individual calls for IPv6 firewall.sEip6tables-restore and ip6tables are missing, disabling IPv6 firewall.sHebtables-restore is missing, using individual calls for bridge firewall.sEebtables-restore and ebtables are missing, disabling bridge firewall.sSebtables-restore is not supporting the --noflush option, will therefore not be used(R)tset_listt ValueErrorRR[RGR*R+tset_supported_typesRt fill_existstrestore_command_existstcommand_existsR!tsupported_icmp_typesR"R$R%R&R'R(RAtrestore_noflush_optiontdebug1(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt _start_checksD                        cCsw tj}tjdtjy|jjWn-tk r\}tj|tjdnX|jj dr|jj d}n|jj drt |jj d|_ n|jj dr|jj d}|dk r|j d<krt|_ntjd|jn|jj d r|jj d }|dk r|j d=krtjd y|jjWqtk rqXqn|jj d r|jj d }|dk r|j d>krt|_n|j d?krt|_qqn|jrtjdn tjd|jj dr|jj d}|dk r|j d@krtjdt|_qn|jj dr|jj d}|dks|j dkrd|_q|j |_tjd|jn|jj dr|jj d}|dk r|j dAkrId|_n-|j dBkrgd |_n|j |_tjd|jqn|jj dr|jj d}|j dCkrt|_nt|_tjdtjd|jn|jjtj|j|j|j|jtjdy|jjjWn]tk r}|jj rtj!d|jjj"|qtjd|jjj"|nX|jj#tj|j|j$tj%d|j$tj&d|j$tj'd|j$tj(dt)|j*j+dkrGtj!dn|j$tj,d |j$tj-d |j$tj.d!|j$tj/d!t)|j0j1dkrtj!d"n|j$tj2d#|j$tj3d#t)|j4j5dkrtj6d$t7j8d%nt}xEd&d'd(gD]4}||j4j5kr2tj6d)|t}q2q2W|rt7j8d%n||j4j5krd*|j4j5krd*}n$d+|j4j5krd+}nd&}tj!d,|||}ntjd-|t9tj:} t;j<j=tj:rxtjd.tj:y| jWqxtk rt}tj!d/tj:|qxXn|j>j?| |jj@tj| |jAd0gt\} }| dkrtjd1|n|jd2krtBjC|jd kntBjD|_E|jFtjGdkr>tHjH} ntI|} |jJd3| |rf|s~|jKr|jLjMr| jNt| jOn|r|rtjd4|jPjQn|jRd3| | jNt| jO|jKr |jLjMr tjd5|jLjSntjd6|jTd3| tjd7|j4jUd3| |jV||_W|j4jXd|jWd3| | jNt| jO|j>jYr: tjd8|j>jZ| y| jNt| jOWq: tk r# } t| j[d9| j\r | j\nd:q: tk r6 q: Xn~ tjGd%krs tHjH}tj]d;|| ndS(DNs"Loading firewalld config file '%s's0Using fallback firewalld configuration settings.t DefaultZonet MinimalMarkt CleanupOnExittnotfalsesCleanupOnExit is set to '%s'tLockdowntyesttruesLockdown is enabledt IPv6_rpfiltersIPv6 rpfilter is enabledsIPV6 rpfilter is disabledtIndividualCallssIndividualCalls is enabledt LogDeniedtoffsLogDenied is set to '%s'tAutomaticHelperssAutomaticHelpers is set to '%s'tAllowZoneDriftingsAllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.s AllowZoneDrifting is set to '%s'sLoading lockdown whitelists*Failed to load lockdown whitelist '%s': %sRR/isNo icmptypes found.R4R0sNo services found.R1sNo zones found.itblocktdropttrustedsZone '%s' is not available.tpublictexternals+Default zone '%s' is not valid. Using '%s'.sUsing default zone '%s'sLoading direct rules file '%s's)Failed to load direct rules file '%s': %st nf_conntracks&Failed to load nf_conntrack module: %stsystemtuse_transactionsUnloading firewall modulessApplying ipsetssApplying default rule setsApplying used zoness2Applying direct chains rules and passthrough ruless Direct: %sRFs%Flushing and applying took %f seconds(RmRn(syesRq(RmRn(syesRq(syesRq(RmRn(syesRq(RmRn(^Rt FALLBACK_ZONERRhRRtreadt ExceptionR[tgettintR>tNonetlowerRGR?R3tenable_lockdownRR@R RARBRCRRtset_firewalld_conftcopytdeepcopyt_select_firewall_backendRORitlockdown_whitelisttquery_lockdownterrortfilenamet set_policiest_loadertFIREWALLD_IPSETStETC_FIREWALLD_IPSETStFIREWALLD_ICMPTYPEStETC_FIREWALLD_ICMPTYPEStlenR/t get_icmptypestFIREWALLD_HELPERStETC_FIREWALLD_HELPERStFIREWALLD_SERVICEStETC_FIREWALLD_SERVICESR0t get_servicestFIREWALLD_ZONEStETC_FIREWALLD_ZONESR1t get_zonesR\R]R^RtFIREWALLD_DIRECTtostpathtexistsR2tset_permanent_configt set_directthandle_modulesRtset_nf_conntrack_helper_settingtget_nf_conntrack_helper_settingRPR_tgetDebugLogLevelttimeRtflushR*Rt has_ipsetstexecutetclearR.tunload_firewall_modulestapply_default_tablest apply_ipsetstapply_default_rulest apply_zonest check_zoneR;tchange_default_zonethas_configurationt apply_directtcodetmsgtdebug2(R6treloadtcomplete_reloadt default_zoneRtvalueRtzR1tobjtstatusttm1t transactiontettm2((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt_startsR                                                      +   cCsUy|jWn*tk r:d|_|jdnXd|_|jddS(NtFAILEDtACCEPTtRUNNING(RRR9t set_policy(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytstarts    c Cstjj|sdS|r|jtjr}|dkr}t}tjj||_|j |j||_t |_ qt }nx[t tj |D]D}|jds|jtjr|dkrtjjd||fr|jd||f|dtqqnd||f}tjd||yP|dkrAt||}|j|jjkr|jj|j}tjd||j|j|j|jj|jn!|jjtjrt|_ ny|jj|Wn3tk r$} tjd|jt| fnX|jjtj|nE|d krt||}|j|j j!kr|j j"|j}tjd||j|j|j|j j#|jn!|jjtjrt|_ n|j j$||jj$tj|nx|dkrt%||d |}|rzdtjj|tjj|d d !f|_|j |jntj|} |j|j&j'kr#|j&j(|j}|j&j)|j|j*rtjd ||j|||j+|qMtjd||j|j|jn*|jjtjrMt|_ t| _ n|jj,| |rtjd ||j|||j+|q|j&j,|n|dkrt-||}|j|j.j/kr"|j.j0|j}tjd||j|j|j|j.j1|jn!|jjtjrCt|_ ny|j.j2|Wn3tk r} tj3d|jt| fnX|jj2tj|n|dkrvt4||}|j|j5j6kr)|j5j7|j}tjd||j|j|j|j5j8|jn!|jjtjrJt|_ n|j5j9||jj9tj|ntj:d|Wqtk r} tj;d||| qt<k rtj;d||tj=qXqW|r|j*r|j|j&j'kr|j&j(|j}tjd||j|j|jy|j&j)|jWnt<k rlnX|jj>|jn|j&j,|ndS(NR1s.xmls%s/%stcombinesLoading %s file '%s'R/s Overloads %s '%s' ('%s/%s')s%s: %s, ignoring for run-time.R0t no_check_nameiis Combining %s '%s' ('%s/%s')RR4sUnknown reader type %ssFailed to load %s file '%s': %ssFailed to load %s file '%s':s0 Overloading and deactivating %s '%s' ('%s/%s')(?RRtisdirt startswithRt ETC_FIREWALLDRtbasenametnamet check_nameRGtdefaulttsortedtlistdirtendswithRR RRhRR/Rt get_icmptypeRtremove_icmptypet add_icmptypeRtinfo1tstrRRRR0Rt get_servicetremove_servicet add_serviceRR1Rtget_zonet remove_zonetcombinedRtadd_zoneRRt get_ipsetst get_ipsett remove_ipsett add_ipsetR[RR4t get_helperst get_helpert remove_helpert add_helperR\RRt exceptiont forget_zone( R6Rt reader_typeRt combined_zoneRRRtorig_objRt config_objR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs                                                cCs|jj|jj|jj|jj|jj|jj|jj|jj|j j|j dS(N( R/tcleanupR0R1RR4RR2R3RR5(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRls         cCs>|jr0|j|jd|jjn|jdS(NR(R?RRR.RR(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytstopxs    cCs=|j}x||jkr(|d7}q W|jj||S(Ni(R>R=tappend(R6ti((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytnew_marks  cCs|jj|dS(N(R=tremove(R6tmark((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytdel_marksc Cs"d}d}x t|D]\}}|rF|jj|\}}n4|j|dkrbd}n|jj|\}}|dkr|d7}||7}qn|r|jj|d|j|cd7|j|jn|jrZ|j|jn|jrv|j|jn|S(N( R-RR,R!RR%R$R(R'(R6tbackends((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytenabled_backendss    cCszg}|jr"|j|jn|jr>|j|jn|jrZ|j|jn|jrv|j|jn|S(N( R!RRR%R$R(R'R-R,(R6R ((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs    cCsn|dkrt|}n|}x*|jD]}|j||jq.W|dkrj|jtndS(N(RRR t add_rulestbuild_default_tablesRR (R6RRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs  cCs3|dkrt|}n|}x6|jD](}|j|j}|j||q.W|jdr|jd}|jrd|j kr|j t |j |j |j}|j||y|j t Wn#tk r}tjd|nX|j qn|dkr/|j t ndS(NRWtraws+Applying rules for ipv6_rpfilter failed: %s(RRR tbuild_default_rulesRBRR RYR@RZRR Rtbuild_rpfilter_rulesRRR[(R6RRRtrulest ipv6_backendR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRs*     cCs|dkrt|}n|}tjdx0|jD]"}|j}|j||q;W|dkr}|jtndS(NsFlushing rule set( RRRRhRtbuild_flush_rulesRRR (R6RRRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR+s    cCs|dkrt|}n|}tjd|x3|jD]%}|j|}|j||q>W|dkr|jtndS(NsSetting policy to '%s'( RRRRhR tbuild_set_policy_rulesRRR (R6tpolicyRRRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR:s  cCs^|s dS|j|}|s8ttjd|n|j|sKdS|j||jS(NRFs'%s' is not a valid backend(RRRRR tset_ruleRB(R6t backend_nametruleR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRKs c Cs\ttd|}|j|}|sCttjd|n|j|sVdS|js|j s|dkrE|j j rExt |D]\}}y|j ||jWqtk r<}tjtjtj|xLt|| D]:}y |j |j||jWqtk r.qXqW|qXqWtS|j||jSdS(Ns'%s' is not a valid backendRFR(tlistRURRRRRR RARdR'RgRRRBRRRht tracebackt format_excRtreversedt reverse_ruleR t set_rules(R6RRt_rulesRRRR((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyRYs0      cCs|jrttjndS(N(R:RRt PANIC_MODE(R6((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_paniczs cCsV|}| s|dkr(|j}n||jjkrRttj|n|S(NRF(tget_default_zoneR1RRRt INVALID_ZONE(R6R1t_zone((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR~s cCs(tj|s$ttj|ndS(N(RtcheckInterfaceRRtINVALID_INTERFACE(R6t interface((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytcheck_interfacescCs|jj|dS(N(R0t check_service(R6R0((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR+scCs(tj|s$ttj|ndS(N(Rt check_portRRt INVALID_PORT(R6tport((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR,scCsA|sttjn|dkr=ttjd|ndS(Nttcptudptsctptdccps''%s' not in {'tcp'|'udp'|'sctp'|'dccp'}(R/R0R1R2(RRtMISSING_PROTOCOLtINVALID_PROTOCOL(R6tprotocol((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_tcpudps   cCs(tj|s$ttj|ndS(N(RtcheckIPRRt INVALID_ADDR(R6tip((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pytcheck_ipscCs||dkr3tj|sxttj|qxnE|dkrftj|sxttj|qxnttjddS(NRVRWs'%s' not in {'ipv4'|'ipv6'}(Rt checkIPnMaskRRR8t checkIP6nMaskR(R6Rtsource((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_addresss   cCs|jj|dS(N(R/tcheck_icmptype(R6ticmp((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR?scCs]t|ts.td|t|fnt|dkrYttjd|ndS(Ns%s is %s, expected intis#timeout '%d' is not positive number(t isinstanceRt TypeErrorttypeRRt INVALID_VALUE(R6ttimeout((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyt check_timeouts  c Cs9|j}i}x1|jjD] }|jj|d||R?RFRRXRPR\R]R^RdReRgR$Rk(((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyR>sd     7      $    !         K       (8t__all__tos.pathRR]RRRtfirewallRRt firewall.coreRRRRRtfirewall.core.fw_icmptypeRtfirewall.core.fw_serviceR tfirewall.core.fw_zoneR tfirewall.core.fw_directR tfirewall.core.fw_configR tfirewall.core.fw_policiesR tfirewall.core.fw_ipsetRtfirewall.core.fw_transactionRtfirewall.core.fw_helperRtfirewall.core.loggerRtfirewall.core.io.firewalld_confRtfirewall.core.io.directRtfirewall.core.io.serviceRtfirewall.core.io.icmptypeRtfirewall.core.io.zoneRRtfirewall.core.io.ipsetRtfirewall.core.io.helperRRtfirewall.errorsRtobjectR(((s4/usr/lib/python2.7/site-packages/firewall/core/fw.pyts@      PK! ipXtables.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-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 os.path import copy from firewall.core.base import SHORTCUTS, DEFAULT_ZONE_TARGET from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import tempFile, readfile, splitArgs, check_mac, portStr, \ check_single_address, check_address, normalizeIP6 from firewall import config from firewall.errors import FirewallError, INVALID_PASSTHROUGH, INVALID_RULE from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark import string BUILT_IN_CHAINS = { "security": [ "INPUT", "OUTPUT", "FORWARD" ], "raw": [ "PREROUTING", "OUTPUT" ], "mangle": [ "PREROUTING", "POSTROUTING", "INPUT", "OUTPUT", "FORWARD" ], "nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ], "filter": [ "INPUT", "OUTPUT", "FORWARD" ], } DEFAULT_REJECT_TYPE = { "ipv4": "icmp-host-prohibited", "ipv6": "icmp6-adm-prohibited", } ICMP = { "ipv4": "icmp", "ipv6": "ipv6-icmp", } # ipv ebtables also uses this # def common_reverse_rule(args): """ Inverse valid rule """ replace_args = { # Append "-A": "-D", "--append": "--delete", # Insert "-I": "-D", "--insert": "--delete", # New chain "-N": "-X", "--new-chain": "--delete-chain", } ret_args = args[:] for arg in replace_args: try: idx = ret_args.index(arg) except Exception: continue if arg in [ "-I", "--insert" ]: # With insert rulenum, then remove it if it is a number # Opt at position idx, chain at position idx+1, [rulenum] at # position idx+2 try: int(ret_args[idx+2]) except Exception: pass else: ret_args.pop(idx+2) ret_args[idx] = replace_args[arg] return ret_args def common_reverse_passthrough(args): """ Reverse valid passthough rule """ replace_args = { # Append "-A": "-D", "--append": "--delete", # Insert "-I": "-D", "--insert": "--delete", # New chain "-N": "-X", "--new-chain": "--delete-chain", } ret_args = args[:] for x in replace_args: try: idx = ret_args.index(x) except ValueError: continue if x in [ "-I", "--insert" ]: # With insert rulenum, then remove it if it is a number # Opt at position idx, chain at position idx+1, [rulenum] at # position idx+2 try: int(ret_args[idx+2]) except ValueError: pass else: ret_args.pop(idx+2) ret_args[idx] = replace_args[x] return ret_args raise FirewallError(INVALID_PASSTHROUGH, "no '-A', '-I' or '-N' arg") # ipv ebtables also uses this # def common_check_passthrough(args): """ Check if passthough rule is valid (only add, insert and new chain rules are allowed) """ args = set(args) not_allowed = set(["-C", "--check", # check rule "-D", "--delete", # delete rule "-R", "--replace", # replace rule "-L", "--list", # list rule "-S", "--list-rules", # print rules "-F", "--flush", # flush rules "-Z", "--zero", # zero rules "-X", "--delete-chain", # delete chain "-P", "--policy", # policy "-E", "--rename-chain"]) # rename chain) # intersection of args and not_allowed is not empty, i.e. # something from args is not allowed if len(args & not_allowed) > 0: raise FirewallError(INVALID_PASSTHROUGH, "arg '%s' is not allowed" % list(args & not_allowed)[0]) # args need to contain one of -A, -I, -N needed = set(["-A", "--append", "-I", "--insert", "-N", "--new-chain"]) # empty intersection of args and needed, i.e. # none from args contains any needed command if len(args & needed) == 0: raise FirewallError(INVALID_PASSTHROUGH, "no '-A', '-I' or '-N' arg") class ip4tables(object): ipv = "ipv4" name = "ip4tables" zones_supported = True def __init__(self, fw): self._fw = fw self._command = config.COMMANDS[self.ipv] self._restore_command = config.COMMANDS["%s-restore" % self.ipv] self.wait_option = self._detect_wait_option() self.restore_wait_option = self._detect_restore_wait_option() self.fill_exists() self.available_tables = [] self.zone_source_index_cache = [] self.our_chains = {} # chains created by firewalld def fill_exists(self): self.command_exists = os.path.exists(self._command) self.restore_command_exists = os.path.exists(self._restore_command) def __run(self, args): # convert to string list if self.wait_option and self.wait_option not in args: _args = [self.wait_option] + ["%s" % item for item in args] else: _args = ["%s" % item for item in args] log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args)) (status, ret) = runProg(self._command, _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(_args), ret)) return ret def split_value(self, rules, opts=None): """Split values combined with commas for options in opts""" if opts is None: return rules out_rules = [ ] for rule in rules: processed = False for opt in opts: try: i = rule.index(opt) except ValueError: pass else: if len(rule) > i and "," in rule[i+1]: # For all items in the comma separated list in index # i of the rule, a new rule is created with a single # item from this list processed = True items = rule[i+1].split(",") for item in items: _rule = rule[:] _rule[i+1] = item out_rules.append(_rule) if not processed: out_rules.append(rule) return out_rules def _rule_replace(self, rule, pattern, replacement): try: i = rule.index(pattern) except ValueError: return False else: rule[i:i+1] = replacement return True def is_chain_builtin(self, ipv, table, chain): return table in BUILT_IN_CHAINS and \ chain in BUILT_IN_CHAINS[table] def build_chain_rules(self, add, table, chain): rule = [ "-t", table ] if add: rule.append("-N") else: rule.append("-X") rule.append(chain) return [rule] def build_rule(self, add, table, chain, index, args): rule = [ "-t", table ] if add: rule += [ "-I", chain, str(index) ] else: rule += [ "-D", chain ] rule += args return rule def reverse_rule(self, args): return common_reverse_rule(args) def check_passthrough(self, args): common_check_passthrough(args) def reverse_passthrough(self, args): return common_reverse_passthrough(args) def passthrough_parse_table_chain(self, args): table = "filter" try: i = args.index("-t") except ValueError: pass else: if len(args) >= i+1: table = args[i+1] chain = None for opt in [ "-A", "--append", "-I", "--insert", "-N", "--new-chain" ]: try: i = args.index(opt) except ValueError: pass else: if len(args) >= i+1: chain = args[i+1] return (table, chain) def _run_replace_zone_source(self, rule, zone_source_index_cache): try: i = rule.index("%%ZONE_SOURCE%%") rule.pop(i) zone = rule.pop(i) if "-m" == rule[4]: # ipset/mac zone_source = (zone, rule[7]) # (zone, address) else: zone_source = (zone, rule[5]) # (zone, address) except ValueError: try: i = rule.index("%%ZONE_INTERFACE%%") rule.pop(i) zone_source = None except ValueError: return rule_add = True if rule[0] in ["-D", "--delete"]: rule_add = False if zone_source and not rule_add: if zone_source in zone_source_index_cache: zone_source_index_cache.remove(zone_source) elif rule_add: if zone_source: # order source based dispatch by zone name if zone_source not in zone_source_index_cache: zone_source_index_cache.append(zone_source) zone_source_index_cache.sort(key=lambda x: x[0]) index = zone_source_index_cache.index(zone_source) else: if self._fw._allow_zone_drifting: index = 0 else: index = len(zone_source_index_cache) rule[0] = "-I" rule.insert(2, "%d" % (index + 1)) def set_rules(self, rules, log_denied): temp_file = tempFile() table_rules = { } zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache) for _rule in rules: rule = _rule[:] # replace %%REJECT%% self._rule_replace(rule, "%%REJECT%%", \ ["REJECT", "--reject-with", DEFAULT_REJECT_TYPE[self.ipv]]) # replace %%ICMP%% self._rule_replace(rule, "%%ICMP%%", [ICMP[self.ipv]]) # replace %%LOGTYPE%% try: i = rule.index("%%LOGTYPE%%") except ValueError: pass else: if log_denied == "off": continue if log_denied in [ "unicast", "broadcast", "multicast" ]: rule[i:i+1] = [ "-m", "pkttype", "--pkt-type", log_denied ] else: rule.pop(i) self._run_replace_zone_source(rule, zone_source_index_cache) table = "filter" # get table form rule for opt in [ "-t", "--table" ]: try: i = rule.index(opt) except ValueError: pass else: if len(rule) >= i+1: rule.pop(i) table = rule.pop(i) # we can not use joinArgs here, because it would use "'" instead # of '"' for the start and end of the string, this breaks # iptables-restore for i in range(len(rule)): for c in string.whitespace: if c in rule[i] and not (rule[i].startswith('"') and rule[i].endswith('"')): rule[i] = '"%s"' % rule[i] table_rules.setdefault(table, []).append(rule) for table in table_rules: rules = table_rules[table] rules = self.split_value(rules, [ "-s", "--source" ]) rules = self.split_value(rules, [ "-d", "--destination" ]) temp_file.write("*%s\n" % table) for rule in rules: temp_file.write(" ".join(rule) + "\n") temp_file.write("COMMIT\n") temp_file.close() stat = os.stat(temp_file.name) log.debug2("%s: %s %s", self.__class__, self._restore_command, "%s: %d" % (temp_file.name, stat.st_size)) args = [ ] if self.restore_wait_option: args.append(self.restore_wait_option) args.append("-n") (status, ret) = runProg(self._restore_command, args, stdin=temp_file.name) if log.getDebugLogLevel() > 2: lines = readfile(temp_file.name) if lines is not None: i = 1 for line in lines: log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0) if not line.endswith("\n"): log.debug3("", nofmt=1) i += 1 os.unlink(temp_file.name) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._restore_command, " ".join(args), ret)) self.zone_source_index_cache = zone_source_index_cache return ret def set_rule(self, rule, log_denied): # replace %%REJECT%% self._rule_replace(rule, "%%REJECT%%", \ ["REJECT", "--reject-with", DEFAULT_REJECT_TYPE[self.ipv]]) # replace %%ICMP%% self._rule_replace(rule, "%%ICMP%%", [ICMP[self.ipv]]) # replace %%LOGTYPE%% try: i = rule.index("%%LOGTYPE%%") except ValueError: pass else: if log_denied == "off": return "" if log_denied in [ "unicast", "broadcast", "multicast" ]: rule[i:i+1] = [ "-m", "pkttype", "--pkt-type", log_denied ] else: rule.pop(i) zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache) self._run_replace_zone_source(rule, zone_source_index_cache) output = self.__run(rule) self.zone_source_index_cache = zone_source_index_cache return output def get_available_tables(self, table=None): ret = [] tables = [ table ] if table else BUILT_IN_CHAINS.keys() for table in tables: if table in self.available_tables: ret.append(table) else: try: self.__run(["-t", table, "-L", "-n"]) self.available_tables.append(table) ret.append(table) except ValueError: log.debug1("%s table '%s' does not exist (or not enough permission to check)." % (self.ipv, table)) return ret def _detect_wait_option(self): wait_option = "" ret = runProg(self._command, ["-w", "-L", "-n"]) # since iptables-1.4.20 if ret[0] == 0: wait_option = "-w" # wait for xtables lock ret = runProg(self._command, ["-w10", "-L", "-n"]) # since iptables > 1.4.21 if ret[0] == 0: wait_option = "-w10" # wait max 10 seconds log.debug2("%s: %s will be using %s option.", self.__class__, self._command, wait_option) return wait_option def _detect_restore_wait_option(self): temp_file = tempFile() temp_file.write("#foo") temp_file.close() wait_option = "" for test_option in ["-w", "--wait=2"]: ret = runProg(self._restore_command, [test_option], stdin=temp_file.name) if ret[0] == 0 and "invalid option" not in ret[1] \ and "unrecognized option" not in ret[1]: wait_option = test_option break log.debug2("%s: %s will be using %s option.", self.__class__, self._restore_command, wait_option) os.unlink(temp_file.name) return wait_option def build_flush_rules(self): self.zone_source_index_cache = [] rules = [] for table in BUILT_IN_CHAINS.keys(): if not self.get_available_tables(table): continue # Flush firewall rules: -F # Delete firewall chains: -X # Set counter to zero: -Z for flag in [ "-F", "-X", "-Z" ]: rules.append(["-t", table, flag]) return rules def build_set_policy_rules(self, policy): rules = [] for table in BUILT_IN_CHAINS.keys(): if not self.get_available_tables(table): continue if table == "nat": continue for chain in BUILT_IN_CHAINS[table]: rules.append(["-t", table, "-P", chain, policy]) return rules def supported_icmp_types(self): """Return ICMP types that are supported by the iptables/ip6tables command and kernel""" ret = [ ] output = "" try: output = self.__run(["-p", "icmp" if self.ipv == "ipv4" else "ipv6-icmp", "--help"]) except ValueError as ex: if self.ipv == "ipv4": log.debug1("iptables error: %s" % ex) else: log.debug1("ip6tables error: %s" % ex) lines = output.splitlines() in_types = False for line in lines: #print(line) if in_types: line = line.strip().lower() splits = line.split() for split in splits: if split.startswith("(") and split.endswith(")"): x = split[1:-1] else: x = split if x not in ret: ret.append(x) if self.ipv == "ipv4" and line.startswith("Valid ICMP Types:") or \ self.ipv == "ipv6" and line.startswith("Valid ICMPv6 Types:"): in_types = True return ret def build_default_tables(self): # nothing to do, they always exist return [] def build_default_rules(self, log_denied="off"): default_rules = {} if self.get_available_tables("security"): default_rules["security"] = [ ] self.our_chains["security"] = set() for chain in BUILT_IN_CHAINS["security"]: default_rules["security"].append("-N %s_direct" % chain) default_rules["security"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["security"].add("%s_direct" % chain) if self.get_available_tables("raw"): default_rules["raw"] = [ ] self.our_chains["raw"] = set() for chain in BUILT_IN_CHAINS["raw"]: default_rules["raw"].append("-N %s_direct" % chain) default_rules["raw"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["raw"].add("%s_direct" % chain) if chain == "PREROUTING": for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules["raw"].append("-N %s_%s" % (chain, dispatch_suffix)) default_rules["raw"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix)) self.our_chains["raw"].update(set(["%s_%s" % (chain, dispatch_suffix)])) if self.get_available_tables("mangle"): default_rules["mangle"] = [ ] self.our_chains["mangle"] = set() for chain in BUILT_IN_CHAINS["mangle"]: default_rules["mangle"].append("-N %s_direct" % chain) default_rules["mangle"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["mangle"].add("%s_direct" % chain) if chain == "PREROUTING": for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules["mangle"].append("-N %s_%s" % (chain, dispatch_suffix)) default_rules["mangle"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix)) self.our_chains["mangle"].update(set(["%s_%s" % (chain, dispatch_suffix)])) if self.get_available_tables("nat"): default_rules["nat"] = [ ] self.our_chains["nat"] = set() for chain in BUILT_IN_CHAINS["nat"]: default_rules["nat"].append("-N %s_direct" % chain) default_rules["nat"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["nat"].add("%s_direct" % chain) if chain in [ "PREROUTING", "POSTROUTING" ]: for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules["nat"].append("-N %s_%s" % (chain, dispatch_suffix)) default_rules["nat"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix)) self.our_chains["nat"].update(set(["%s_%s" % (chain, dispatch_suffix)])) default_rules["filter"] = [] self.our_chains["filter"] = set() default_rules["filter"].append("-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT") default_rules["filter"].append("-A INPUT -i lo -j ACCEPT") default_rules["filter"].append("-N INPUT_direct") default_rules["filter"].append("-A INPUT -j INPUT_direct") self.our_chains["filter"].update(set("INPUT_direct")) for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules["filter"].append("-N INPUT_%s" % (dispatch_suffix)) default_rules["filter"].append("-A INPUT -j INPUT_%s" % (dispatch_suffix)) self.our_chains["filter"].update(set("INPUT_%s" % (dispatch_suffix))) if log_denied != "off": default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '") default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID -j DROP") if log_denied != "off": default_rules["filter"].append("-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '") default_rules["filter"].append("-A INPUT -j %%REJECT%%") default_rules["filter"].append("-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT") default_rules["filter"].append("-A FORWARD -i lo -j ACCEPT") default_rules["filter"].append("-N FORWARD_direct") default_rules["filter"].append("-A FORWARD -j FORWARD_direct") self.our_chains["filter"].update(set("FORWARD_direct")) for direction in ["IN", "OUT"]: for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules["filter"].append("-N FORWARD_%s_%s" % (direction, dispatch_suffix)) default_rules["filter"].append("-A FORWARD -j FORWARD_%s_%s" % (direction, dispatch_suffix)) self.our_chains["filter"].update(set("FORWARD_%s_%s" % (direction, dispatch_suffix))) if log_denied != "off": default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '") default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID -j DROP") if log_denied != "off": default_rules["filter"].append("-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '") default_rules["filter"].append("-A FORWARD -j %%REJECT%%") default_rules["filter"] += [ "-N OUTPUT_direct", "-A OUTPUT -o lo -j ACCEPT", "-A OUTPUT -j OUTPUT_direct", ] self.our_chains["filter"].update(set("OUTPUT_direct")) final_default_rules = [] for table in default_rules: if table not in self.get_available_tables(): continue for rule in default_rules[table]: final_default_rules.append(["-t", table] + splitArgs(rule)) return final_default_rules def get_zone_table_chains(self, table): if table == "filter": return { "INPUT", "FORWARD_IN", "FORWARD_OUT" } if table == "mangle": if "mangle" in self.get_available_tables() and \ "nat" in self.get_available_tables(): return { "PREROUTING" } if table == "nat": if "nat" in self.get_available_tables(): return { "PREROUTING", "POSTROUTING" } if table == "raw": if "raw" in self.get_available_tables(): return { "PREROUTING" } return {} def build_zone_source_interface_rules(self, enable, zone, interface, table, chain, append=False): # handle all zones in the same way here, now # trust and block zone targets are handled now in __chain opt = { "PREROUTING": "-i", "POSTROUTING": "-o", "INPUT": "-i", "FORWARD_IN": "-i", "FORWARD_OUT": "-o", "OUTPUT": "-o", }[chain] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) action = "-g" if enable and not append: rule = [ "-I", "%s_ZONES" % chain, "%%ZONE_INTERFACE%%" ] elif enable: rule = [ "-A", "%s_ZONES" % chain ] else: rule = [ "-D", "%s_ZONES" % chain ] if not append: rule += ["%%ZONE_INTERFACE%%"] rule += [ "-t", table, opt, interface, action, target ] return [rule] def build_zone_source_address_rules(self, enable, zone, address, table, chain): add_del = { True: "-I", False: "-D" }[enable] opt = { "PREROUTING": "-s", "POSTROUTING": "-d", "INPUT": "-s", "FORWARD_IN": "-s", "FORWARD_OUT": "-d", "OUTPUT": "-d", }[chain] if self._fw._allow_zone_drifting: zone_dispatch_chain = "%s_ZONES_SOURCE" % (chain) else: zone_dispatch_chain = "%s_ZONES" % (chain) target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) action = "-g" if address.startswith("ipset:"): name = address[6:] if opt == "-d": opt = "dst" else: opt = "src" flags = ",".join([opt] * self._fw.ipset.get_dimension(name)) rule = [ add_del, zone_dispatch_chain, "%%ZONE_SOURCE%%", zone, "-t", table, "-m", "set", "--match-set", name, flags, action, target ] else: if check_mac(address): # outgoing can not be set if opt == "-d": return "" rule = [ add_del, zone_dispatch_chain, "%%ZONE_SOURCE%%", zone, "-t", table, "-m", "mac", "--mac-source", address.upper(), action, target ] else: if check_single_address("ipv6", address): address = normalizeIP6(address) elif check_address("ipv6", address): addr_split = address.split("/") address = normalizeIP6(addr_split[0]) + "/" + addr_split[1] rule = [ add_del, zone_dispatch_chain, "%%ZONE_SOURCE%%", zone, "-t", table, opt, address, action, target ] return [rule] def build_zone_chain_rules(self, zone, table, chain): _zone = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) self.our_chains[table].update(set([_zone, "%s_log" % _zone, "%s_deny" % _zone, "%s_allow" % _zone])) rules = [] rules.append([ "-N", _zone, "-t", table ]) rules.append([ "-N", "%s_log" % _zone, "-t", table ]) rules.append([ "-N", "%s_deny" % _zone, "-t", table ]) rules.append([ "-N", "%s_allow" % _zone, "-t", table ]) rules.append([ "-A", _zone, "-t", table, "-j", "%s_log" % _zone ]) rules.append([ "-A", _zone, "-t", table, "-j", "%s_deny" % _zone ]) rules.append([ "-A", _zone, "-t", table, "-j", "%s_allow" % _zone ]) target = self._fw.zone._zones[zone].target if self._fw.get_log_denied() != "off": if table == "filter" and \ chain in [ "INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT" ]: if target in [ "REJECT", "%%REJECT%%" ]: rules.append([ "-A", _zone, "-t", table, "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_REJECT: \"" % _zone ]) if target == "DROP": rules.append([ "-A", _zone, "-t", table, "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_DROP: \"" % _zone ]) # Handle trust, block and drop zones: # Add an additional rule with the zone target (accept, reject # or drop) to the base zone only in the filter table. # Otherwise it is not be possible to have a zone with drop # target, that is allowing traffic that is locally initiated # or that adds additional rules. (RHBZ#1055190) if table == "filter" and \ target in [ "ACCEPT", "REJECT", "%%REJECT%%", "DROP" ] and \ chain in [ "INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT" ]: rules.append([ "-A", _zone, "-t", table, "-j", target ]) return rules def _rule_limit(self, limit): if limit: return [ "-m", "limit", "--limit", limit.value ] return [] def _rich_rule_log(self, rich_rule, enable, table, target, rule_fragment): if not rich_rule.log: return [] add_del = { True: "-A", False: "-D" }[enable] rule = [ add_del, "%s_log" % (target), "-t", table] rule += rule_fragment + [ "-j", "LOG" ] if rich_rule.log.prefix: rule += [ "--log-prefix", "'%s'" % rich_rule.log.prefix ] if rich_rule.log.level: rule += [ "--log-level", "%s" % rich_rule.log.level ] rule += self._rule_limit(rich_rule.log.limit) return rule def _rich_rule_audit(self, rich_rule, enable, table, target, rule_fragment): if not rich_rule.audit: return [] add_del = { True: "-A", False: "-D" }[enable] rule = [add_del, "%s_log" % (target), "-t", table] + rule_fragment if type(rich_rule.action) == Rich_Accept: _type = "accept" elif type(rich_rule.action) == Rich_Reject: _type = "reject" elif type(rich_rule.action) == Rich_Drop: _type = "drop" else: _type = "unknown" rule += [ "-j", "AUDIT", "--type", _type ] rule += self._rule_limit(rich_rule.audit.limit) return rule def _rich_rule_action(self, zone, rich_rule, enable, table, target, rule_fragment): if not rich_rule.action: return [] add_del = { True: "-A", False: "-D" }[enable] if type(rich_rule.action) == Rich_Accept: chain = "%s_allow" % target rule_action = [ "-j", "ACCEPT" ] elif type(rich_rule.action) == Rich_Reject: chain = "%s_deny" % target rule_action = [ "-j", "REJECT" ] if rich_rule.action.type: rule_action += [ "--reject-with", rich_rule.action.type ] elif type(rich_rule.action) == Rich_Drop: chain = "%s_deny" % target rule_action = [ "-j", "DROP" ] elif type(rich_rule.action) == Rich_Mark: target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["PREROUTING"], zone=zone) table = "mangle" chain = "%s_allow" % target rule_action = [ "-j", "MARK", "--set-xmark", rich_rule.action.set ] else: raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action)) rule = [ add_del, chain, "-t", table ] rule += rule_fragment + rule_action rule += self._rule_limit(rich_rule.action.limit) return rule def _rich_rule_destination_fragment(self, rich_dest): if not rich_dest: return [] rule_fragment = [] if rich_dest.invert: rule_fragment.append("!") if check_single_address("ipv6", rich_dest.addr): rule_fragment += [ "-d", normalizeIP6(rich_dest.addr) ] elif check_address("ipv6", rich_dest.addr): addr_split = rich_dest.addr.split("/") rule_fragment += [ "-d", normalizeIP6(addr_split[0]) + "/" + addr_split[1] ] else: rule_fragment += [ "-d", rich_dest.addr ] return rule_fragment def _rich_rule_source_fragment(self, rich_source): if not rich_source: return [] rule_fragment = [] if rich_source.addr: if rich_source.invert: rule_fragment.append("!") if check_single_address("ipv6", rich_source.addr): rule_fragment += [ "-s", normalizeIP6(rich_source.addr) ] elif check_address("ipv6", rich_source.addr): addr_split = rich_source.addr.split("/") rule_fragment += [ "-s", normalizeIP6(addr_split[0]) + "/" + addr_split[1] ] else: rule_fragment += [ "-s", rich_source.addr ] elif hasattr(rich_source, "mac") and rich_source.mac: rule_fragment += [ "-m", "mac" ] if rich_source.invert: rule_fragment.append("!") rule_fragment += [ "--mac-source", rich_source.mac ] elif hasattr(rich_source, "ipset") and rich_source.ipset: rule_fragment += [ "-m", "set" ] if rich_source.invert: rule_fragment.append("!") flags = self._fw.zone._ipset_match_flags(rich_source.ipset, "src") rule_fragment += [ "--match-set", rich_source.ipset, flags ] return rule_fragment def build_zone_ports_rules(self, enable, zone, proto, port, destination=None, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [ "-p", proto ] if port: rule_fragment += [ "--dport", "%s" % portStr(port) ] if destination: rule_fragment += [ "-d", destination ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "%s_allow" % (target), "-t", table] + rule_fragment + [ "-j", "ACCEPT" ]) return rules def build_zone_protocol_rules(self, enable, zone, protocol, destination=None, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [ "-p", protocol ] if destination: rule_fragment += [ "-d", destination ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "%s_allow" % (target), "-t", table] + rule_fragment + [ "-j", "ACCEPT" ]) return rules def build_zone_source_ports_rules(self, enable, zone, proto, port, destination=None, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [ "-p", proto ] if port: rule_fragment += [ "--sport", "%s" % portStr(port) ] if destination: rule_fragment += [ "-d", destination ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([add_del, "%s_allow" % (target), "-t", table] + rule_fragment + [ "-j", "ACCEPT" ]) return rules def build_zone_helper_ports_rules(self, enable, zone, proto, port, destination, helper_name, module_short_name): add_del = { True: "-A", False: "-D" }[enable] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["PREROUTING"], zone=zone) rule = [ add_del, "%s_allow" % (target), "-t", "raw", "-p", proto ] if port: rule += [ "--dport", "%s" % portStr(port) ] if destination: rule += [ "-d", destination ] rule += [ "-j", "CT", "--helper", module_short_name ] return [rule] def build_zone_masquerade_rules(self, enable, zone, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["POSTROUTING"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules = [] rules.append([ add_del, "%s_allow" % (target), "-t", "nat" ] + rule_fragment + [ "!", "-o", "lo", "-j", "MASQUERADE" ]) # FORWARD_OUT target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["FORWARD_OUT"], zone=zone) rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules.append([ add_del, "%s_allow" % (target), "-t", "filter"] + rule_fragment + ["-m", "conntrack", "--ctstate", "NEW,UNTRACKED", "-j", "ACCEPT" ]) return rules def build_zone_forward_port_rules(self, enable, zone, filter_chain, port, protocol, toport, toaddr, mark_id, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] mark_str = "0x%x" % mark_id mark = [ "-m", "mark", "--mark", mark_str ] to = "" if toaddr: if check_single_address("ipv6", toaddr): to += "[%s]" % normalizeIP6(toaddr) else: to += toaddr if toport and toport != "": to += ":%s" % portStr(toport, "-") target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["PREROUTING"], zone=zone) rule_fragment = [ "-p", protocol, "--dport", portStr(port) ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules = [] if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, "mangle", target, rule_fragment)) rules.append([ add_del, "%s_allow" % (target), "-t", "mangle"] + rule_fragment + [ "-j", "MARK", "--set-mark", mark_str ]) # local and remote rules.append([ add_del, "%s_allow" % (target), "-t", "nat", "-p", protocol ] + mark + [ "-j", "DNAT", "--to-destination", to ]) target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[filter_chain], zone=zone) rules.append([ add_del, "%s_allow" % (target), "-t", "filter", "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] + mark + [ "-j", "ACCEPT" ]) return rules def build_zone_icmp_block_rules(self, enable, zone, ict, rich_rule=None): table = "filter" add_del = { True: "-A", False: "-D" }[enable] if self.ipv == "ipv4": proto = [ "-p", "icmp" ] match = [ "-m", "icmp", "--icmp-type", ict.name ] else: proto = [ "-p", "ipv6-icmp" ] match = [ "-m", "icmp6", "--icmpv6-type", ict.name ] rules = [] for chain in ["INPUT", "FORWARD_IN"]: target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) if self._fw.zone.query_icmp_block_inversion(zone): final_chain = "%s_allow" % target final_target = "ACCEPT" else: final_chain = "%s_deny" % target final_target = "%%REJECT%%" rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rule_fragment += proto + match if rich_rule: rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) if rich_rule.action: rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) else: rules.append([ add_del, "%s_deny" % target, "-t", table ] + rule_fragment + [ "-j", "%%REJECT%%" ]) else: if self._fw.get_log_denied() != "off" and final_target != "ACCEPT": rules.append([ add_del, final_chain, "-t", table ] + rule_fragment + [ "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_ICMP_BLOCK: \"" % zone ]) rules.append([ add_del, final_chain, "-t", table ] + rule_fragment + [ "-j", final_target ]) return rules def build_zone_icmp_block_inversion_rules(self, enable, zone): table = "filter" rules = [] for chain in [ "INPUT", "FORWARD_IN" ]: rule_idx = 4 _zone = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) if self._fw.zone.query_icmp_block_inversion(zone): ibi_target = "%%REJECT%%" if self._fw.get_log_denied() != "off": if enable: rule = [ "-I", _zone, str(rule_idx) ] else: rule = [ "-D", _zone ] rule = rule + [ "-t", table, "-p", "%%ICMP%%", "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_ICMP_BLOCK: \"" % _zone ] rules.append(rule) rule_idx += 1 else: ibi_target = "ACCEPT" if enable: rule = [ "-I", _zone, str(rule_idx) ] else: rule = [ "-D", _zone ] rule = rule + [ "-t", table, "-p", "%%ICMP%%", "-j", ibi_target ] rules.append(rule) return rules def build_zone_rich_source_destination_rules(self, enable, zone, rich_rule): table = "filter" target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS["INPUT"], zone=zone) rule_fragment = [] rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules = [] rules.append(self._rich_rule_log(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_audit(rich_rule, enable, table, target, rule_fragment)) rules.append(self._rich_rule_action(zone, rich_rule, enable, table, target, rule_fragment)) return rules def is_ipv_supported(self, ipv): return ipv == self.ipv class ip6tables(ip4tables): ipv = "ipv6" name = "ip6tables" def build_rpfilter_rules(self, log_denied=False): rules = [] rules.append([ "-I", "PREROUTING", "-t", "raw", "-m", "rpfilter", "--invert", "-j", "DROP" ]) if log_denied != "off": rules.append([ "-I", "PREROUTING", "-t", "raw", "-m", "rpfilter", "--invert", "-j", "LOG", "--log-prefix", "rpfilter_DROP: " ]) rules.append([ "-I", "PREROUTING", "-t", "raw", "-p", "ipv6-icmp", "--icmpv6-type=neighbour-solicitation", "-j", "ACCEPT" ]) # RHBZ#1575431, kernel bug in 4.16-4.17 rules.append([ "-I", "PREROUTING", "-t", "raw", "-p", "ipv6-icmp", "--icmpv6-type=router-advertisement", "-j", "ACCEPT" ]) # RHBZ#1058505 return rules PK!Y++fw_transaction.pyonu[ c`c@sdZddgZddlmZddlmZddlmZddlm Z de fd YZ de fd YZ de fd YZ d S( s!Transaction classes for firewalldtFirewallTransactiontFirewallZoneTransactioni(tlog(terrors(t FirewallError(tLastUpdatedOrderedDicttSimpleFirewallTransactioncBseZdZdZdZdZdZdZdZdZ dZ d Z ddd Z d Zd Zd ZRS(s>Base class for FirewallTransaction and FirewallZoneTransactioncCs1||_i|_g|_g|_g|_dS(N(tfwtrulest pre_funcst post_funcst fail_funcs(tselfR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt__init__"s     cCs&|jj|j2|j2|j2dS(N(RtclearR R R (R ((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR)s cCs#|jj|jgj|dS(N(Rt setdefaulttnametappend(R tbackendtrule((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_rule/scCs%x|D]}|j||qWdS(N(R(R RRR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_rules2s cCs&|j|jko%||j|jkS(N(RR(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt query_rule6scCsF|j|jkrB||j|jkrB|j|jj|ndS(N(RRtremove(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_rule9s(cGs|jj||fdS(N(R R(R tfunctargs((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_pre=scGs|jj||fdS(N(R R(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_post@scGs|jj||fdS(N(R R(R RR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytadd_failCscCstjdt||df|dkr5i}n|dkrJg}n|sx|jD]R}xIt|j|D]4}|j|gj|jj |j |qtWqZWn4x1|jD]&}|j|gj |j|qW||fS(Ns%s.prepare(%s, %s)s...( Rtdebug4ttypetNoneRtreversedRRRtget_backend_by_namet reverse_ruletextend(R tenableRtmodulest backend_nameR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytprepareFs     '$cCs1tjdt||f|j|\}}|jt}d}g}xe|D]]}y|jj|||Wn,tk r}t }|}tj |qUX|j |qUW|s|jj ||} | r| \} }| rtj |qqn|r#i} xY|D]Q}g| |t||D],} | |j |jj|j| q3WqWxL| D]D}y|jj|| |Wqntk r}tj |qnXqnWxU|jD]J\} }y| |Wqtk r }tj d| ||fqXqWttj|n|jdS(Ns%s.execute(%s)ts#Calling fail func %s(%s) failed: %s(RRRR(tpretFalseRRt ExceptiontTrueterrorRthandle_modulestdebug1R!R"R#R RRtCOMMAND_FAILEDtpost(R R%RR&R.terrorMsgtdoneR'tmsgt module_returntstatust undo_rulesRRR((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytexecuteZsP      $  cCsstjdt|xU|jD]J\}}y||Wq!tk rj}tjd|||fq!Xq!WdS(Ns%s.pre()s"Calling pre func %s(%s) failed: %s(RRRR R,R.(R RRR5((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR*s cCsstjdt|xU|jD]J\}}y||Wq!tk rj}tjd|||fq!Xq!WdS(Ns %s.post()s#Calling post func %s(%s) failed: %s(RRRR R,R.(R RRR5((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR2s N(t__name__t __module__t__doc__R RRRRRRRRR R(R9R*R2(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs          = cBsJeZdZdZdZdZdddZdZdZ RS(s<General FirewallTransaction, contains also zone transactionscCs&tt|j|t|_dS(N(tsuperRR Rtzone_transactions(R R((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR scCs$tt|j|jjdS(N(R=RRR>(R ((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRscCs9||jkr.t|j|||j|RR(R tzone((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytzone_transactionscCstjdt||dftt|j|||\}}x|jD]}yR|j|j||x4|j|jD]"}||kr|j|qqWWqNt k r}tj dt |qNXqNW||fS(Ns%s.prepare(%s, %s)s...s1Failed to prepare transaction rules for zone '%s'( RRRR=RR(R>R&RRR.tstr(R R%RR&R?tmoduleR5((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR(s   cCsStjdt|tt|jx"|jD]}|j|jq4WdS(Ns%s.pre()(RRRR=RR*R>(R R?((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR*scCsStjdt|tt|jx"|jD]}|j|jq4WdS(Ns %s.post()(RRRR=RR2R>(R R?((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR2sN( R:R;R<R RR@R R(R*R2(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs    cBseZdZd dZdZd d dZdZdZdZ dZ dZ d Z d Z d Zd ZRS(s;Zone transaction with additional chain and module interfacecCs>tt|j|||_||_g|_g|_dS(N(R=RR R?tfw_transactiontchainsR&(R RR?RC((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR s    cCs|jr~tt|jjx}|jjjD]E}tt|jj|j|jj|j2|jj|j2q2Wn!tt|j|j2|j2dS(N( RCR=RRR>tkeysRRDR&(R R?((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs cCs~tjdt||dftt|j|||\}}x-|jD]"}||krN|j|qNqNW||fS(Ns%s.prepare(%s, %s)s...(RRRR=RR(R&R(R R%RR&RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR(s  cCs6|jr|jj|ntt|j|dS(N(RCR9R=R(R R%((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyR9s cCsT||f}||jkrP|jjj|jt|g||jj|ndS(N(RDRR?tgen_chain_rulesR-R(R ttabletchaint table_chain((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_chains "cCs2||f}||jkr.|jj|ndS(N(RDR(R RGRHRI((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_chains cCs?x8|D]0}||jkr|j|d|dqqWdS(Nii(RDRJ(R RDRI((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_chainss cCs7x0|D](}||jkr|jj|qqWdS(N(RDR(R RDRI((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_chains s cCs&||jkr"|jj|ndS(N(R&R(R RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_module%scCs&||jkr"|jj|ndS(N(R&R(R RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt remove_module)scCs"x|D]}|j|qWdS(N(RN(R R&RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyt add_modules-s cCs"x|D]}|j|qWdS(N(RO(R R&RB((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pytremove_modules1s N(R:R;R<R R RR(R9RJRKRLRMRNRORPRQ(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyRs         N(R<t__all__tfirewall.core.loggerRtfirewallRtfirewall.errorsRtfirewall.fw_typesRtobjectRRR(((s@/usr/lib/python2.7/site-packages/firewall/core/fw_transaction.pyts 5PK!㏷ fw_nm.pyonu[ c`c@sWdZddddddddgZd d lZd d lmZyejd d Wnek rmeZnAXyd dlm Z e ZWn#e eej fk reZnXd ad dlmZd dlmZd dlmZd d lZdZdZdZdZdZdZdZdZdZdZdZ d S(s(Functions for NetworkManager interactiontcheck_nm_importedtnm_is_importedtnm_get_zone_of_connectiontnm_set_zone_of_connectiontnm_get_connectionstnm_get_connection_of_interfacetnm_get_bus_nametnm_get_dbus_interfaceiN(tGLibtNMs1.0(R (terrors(t FirewallError(tlogcCststtjdndS(sNCheck function to raise a MISSING_IMPORT error if the import of NM failed sgi.repository.NM = 1.0N(t _nm_importedR R tMISSING_IMPORT(((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyR0scCstS(snReturns true if NM has been properly imported @return True if import was successful, False otherwirse (R (((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyR6scCststjjdantS(sReturns the NM client object or None if the import of NM failed @return NM.Client instance if import was successful, None otherwise N(t _nm_clientR tClienttnewtNone(((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyt nm_get_client<scCsttj|}|dkr)dS|j}|dkrEdSy(|jtjjtjj B@rldSWn!t k r|j rdSnX|j }|dkrd}n|S(sGet zone of connection from NM @param connection name @return zone string setting of connection, empty string if not set, None if connection is unknown tN( RRtget_connection_by_uuidRtget_setting_connectiont get_flagsR tSettingsConnectionFlagst NM_GENERATEDt NM_VOLATILEtAttributeErrort get_unsavedtget_zone(t connectiontcont setting_contzone((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyREs$        cCszttj|}|dkr)tS|j}|dkrEtS|dkrZd}n|jd||jtdS(sSet the zone for a connection @param zone name @param connection name @return True if zone was set, else False RR!N( RRRRtFalseRt set_propertytcommit_changestTrue(R!RRR ((s7/usr/lib/python2.7/site-packages/firewall/core/fw_nm.pyRcs     cCs|j|jttj}xo|D]g}|jrIq1n|j}|j}|j}|||s>               PK!gnbk.k. fw_zone.pynu[# -*- 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 time from firewall.core.base import SHORTCUTS, DEFAULT_ZONE_TARGET, \ ZONE_SOURCE_IPSET_TYPES from firewall.core.logger import log from firewall.functions import portStr, checkIPnMask, checkIP6nMask, \ checkProtocol, enable_ip_forwarding, check_single_address, check_mac, \ portInPortRange, get_nf_conntrack_short_name from firewall.core.rich import Rich_Rule, Rich_Accept, \ Rich_Mark, Rich_Service, Rich_Port, Rich_Protocol, \ Rich_Masquerade, Rich_ForwardPort, Rich_SourcePort, Rich_IcmpBlock, \ Rich_IcmpType from firewall.core.fw_transaction import FirewallTransaction, \ FirewallZoneTransaction from firewall import errors from firewall.errors import FirewallError from firewall.fw_types import LastUpdatedOrderedDict class FirewallZone(object): def __init__(self, fw): self._fw = fw self._chains = { } self._zones = { } def __repr__(self): return '%s(%r, %r)' % (self.__class__, self._chains, self._zones) def cleanup(self): self._chains.clear() self._zones.clear() # transaction def new_transaction(self): return FirewallTransaction(self._fw) def new_zone_transaction(self, zone): return FirewallZoneTransaction(self._fw, zone) # zones def get_zones(self): return sorted(self._zones.keys()) def get_zone_of_interface(self, interface): interface_id = self.__interface_id(interface) for zone in self._zones: if interface_id in self._zones[zone].settings["interfaces"]: # an interface can only be part of one zone return zone return None def get_zone_of_source(self, source): source_id = self.__source_id(source) for zone in self._zones: if source_id in self._zones[zone].settings["sources"]: # a source_id can only be part of one zone return zone return None def get_zone(self, zone): z = self._fw.check_zone(zone) return self._zones[z] def _error2warning(self, f, name, *args, **kwargs): # transform errors into warnings try: f(name, *args, **kwargs) except FirewallError as error: msg = str(error) log.warning("%s: %s" % (name, msg)) def add_zone(self, obj): obj.settings = { x : LastUpdatedOrderedDict() for x in [ "interfaces", "sources", "services", "ports", "masquerade", "forward_ports", "source_ports", "icmp_blocks", "rules", "protocols", "icmp_block_inversion" ] } self._zones[obj.name] = obj def remove_zone(self, zone): obj = self._zones[zone] if obj.applied: self.unapply_zone_settings(zone) obj.settings.clear() del self._zones[zone] def apply_zones(self, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction for zone in self.get_zones(): obj = self._zones[zone] zone_transaction = transaction.zone_transaction(zone) # register icmp block inversion setting but don't apply if obj.icmp_block_inversion: self._error2warning(self.add_icmp_block_inversion, obj.name, use_zone_transaction=zone_transaction) if len(obj.interfaces) > 0 or len(obj.sources) > 0: obj.applied = True log.debug1("Applying zone '%s'", obj.name) # load zone in case of missing services, icmptypes etc. for args in obj.icmp_blocks: self._error2warning(self.add_icmp_block, obj.name, args, use_zone_transaction=zone_transaction) for args in obj.forward_ports: self._error2warning(self.add_forward_port, obj.name, *args, use_zone_transaction=zone_transaction) for args in obj.services: self._error2warning(self.add_service, obj.name, args, use_zone_transaction=zone_transaction) for args in obj.ports: self._error2warning(self.add_port, obj.name, *args, use_zone_transaction=zone_transaction) for args in obj.protocols: self._error2warning(self.add_protocol, obj.name, args, use_zone_transaction=zone_transaction) for args in obj.source_ports: self._error2warning(self.add_source_port, obj.name, *args, use_zone_transaction=zone_transaction) if obj.masquerade: self._error2warning(self.add_masquerade, obj.name, use_zone_transaction=zone_transaction) for args in obj.rules: self._error2warning(self.add_rule, obj.name, args, use_zone_transaction=zone_transaction) for args in obj.interfaces: self._error2warning(self.add_interface, obj.name, args, use_zone_transaction=zone_transaction) for args in obj.sources: self._error2warning(self.add_source, obj.name, args, use_zone_transaction=zone_transaction) # apply icmp accept/reject rule always if obj.applied: self._error2warning(self._icmp_block_inversion, True, obj.name, zone_transaction) if use_transaction is None: transaction.execute(True) def set_zone_applied(self, zone, applied): obj = self._zones[zone] obj.applied = applied # zone from chain def zone_from_chain(self, chain): if "_" not in chain: # no zone chain return None splits = chain.split("_") if len(splits) < 2: return None _chain = None for x in SHORTCUTS: if splits[0] == SHORTCUTS[x]: _chain = x if _chain is not None: # next part needs to be zone name if splits[1] not in self.get_zones(): return None if len(splits) == 2 or \ (len(splits) == 3 and splits[2] in [ "log", "deny", "allow" ]): return (splits[1], _chain) return None def create_zone_base_by_chain(self, ipv, table, chain, use_transaction=None): # Create zone base chains if the chain is reserved for a zone if ipv in [ "ipv4", "ipv6" ]: x = self.zone_from_chain(chain) if x is not None: (_zone, _chain) = x if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self.gen_chain_rules(_zone, True, [(table, _chain)], transaction) if use_transaction is None: transaction.execute(True) # dynamic chain handling def _register_chains(self, zone, create, chains): # this method is used by FirewallZoneTransaction for (table, chain) in chains: if create: self._chains.setdefault(zone, { }).setdefault(table, [ ]).append(chain) else: self._chains[zone][table].remove(chain) if len(self._chains[zone][table]) == 0: del self._chains[zone][table] if len(self._chains[zone]) == 0: del self._chains[zone] # settings # generate settings record with sender, timeout, mark def __gen_settings(self, timeout, sender, mark=None): ret = { "date": time.time(), "sender": sender, "timeout": timeout, } if mark: ret["mark"] = mark return ret def get_settings(self, zone): return self.get_zone(zone).settings def set_settings(self, zone, settings): _obj = self.get_zone(zone) try: for key in settings: for args in settings[key]: if args in _obj.settings[key]: # do not add things, that are already active in the # zone configuration, also do not restore date, # sender and timeout continue if key == "icmp_blocks": self.add_icmp_block(zone, args) elif key == "forward_ports": self.add_forward_port(zone, *args) elif key == "services": self.add_service(zone, args) elif key == "ports": self.add_port(zone, *args) elif key == "protocols": self.add_protocol(zone, *args) elif key == "source_ports": self.add_source_port(zone, *args) elif key == "masquerade": self.add_masquerade(zone) elif key == "rules": self.add_rule(zone, Rich_Rule(rule_str=args)) elif key == "interfaces": self.change_zone_of_interface(zone, args) elif key == "sources": self.change_zone_of_source(zone, args) else: log.warning("Zone '%s': Unknown setting '%s:%s', " "unable to restore.", zone, key, args) # restore old date, sender and timeout if args in _obj.settings[key]: _obj.settings[key][args] = settings[key][args] except FirewallError as msg: log.warning(str(msg)) def __zone_settings(self, enable, zone, use_zone_transaction=None): _zone = self._fw.check_zone(zone) obj = self._zones[_zone] if (enable and obj.applied) or (not enable and not obj.applied): return if enable: obj.applied = True if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(zone) else: zone_transaction = use_zone_transaction settings = self.get_settings(zone) for key in settings: for args in settings[key]: try: if key == "icmp_blocks": self._icmp_block(enable, _zone, args, zone_transaction) elif key == "icmp_block_inversion": continue elif key == "forward_ports": mark = obj.settings["forward_ports"][args]["mark"] self._forward_port(enable, _zone, zone_transaction, *args, mark_id=mark) elif key == "services": self._service(enable, _zone, args, zone_transaction) elif key == "ports": self._port(enable, _zone, args[0], args[1], zone_transaction) elif key == "protocols": self._protocol(enable, _zone, args, zone_transaction) elif key == "source_ports": self._source_port(enable, _zone, args[0], args[1], zone_transaction) elif key == "masquerade": self._masquerade(enable, _zone, zone_transaction) elif key == "rules": if "mark" in obj.settings["rules"][args]: mark = obj.settings["rules"][args]["mark"] else: mark = None self.__rule(enable, _zone, Rich_Rule(rule_str=args), mark, zone_transaction) elif key == "interfaces": self._interface(enable, _zone, args, zone_transaction) elif key == "sources": self._source(enable, _zone, args[0], args[1], zone_transaction) else: log.warning("Zone '%s': Unknown setting '%s:%s', " "unable to apply", zone, key, args) except FirewallError as msg: log.warning(str(msg)) if enable: # add icmp rule(s) always self._icmp_block_inversion(True, obj.name, zone_transaction) if use_zone_transaction is None: zone_transaction.execute(enable) def apply_zone_settings(self, zone, use_zone_transaction=None): self.__zone_settings(True, zone, use_zone_transaction) def unapply_zone_settings(self, zone, use_zone_transaction=None): self.__zone_settings(False, zone, use_zone_transaction) def unapply_zone_settings_if_unused(self, zone): obj = self._zones[zone] if len(obj.interfaces) == 0 and len(obj.sources) == 0: self.unapply_zone_settings(zone) def get_config_with_settings(self, zone): """ :return: exported config updated with runtime settings """ conf = list(self.get_zone(zone).export_config()) if conf[4] == DEFAULT_ZONE_TARGET: conf[4] = "default" conf[5] = self.list_services(zone) conf[6] = self.list_ports(zone) conf[7] = self.list_icmp_blocks(zone) conf[8] = self.query_masquerade(zone) conf[9] = self.list_forward_ports(zone) conf[10] = self.list_interfaces(zone) conf[11] = self.list_sources(zone) conf[12] = self.list_rules(zone) conf[13] = self.list_protocols(zone) conf[14] = self.list_source_ports(zone) conf[15] = self.query_icmp_block_inversion(zone) return tuple(conf) # INTERFACES def check_interface(self, interface): self._fw.check_interface(interface) def interface_get_sender(self, zone, interface): _zone = self._fw.check_zone(zone) _obj = self._zones[_zone] interface_id = self.__interface_id(interface) if interface_id in _obj.settings["interfaces"]: settings = _obj.settings["interfaces"][interface_id] if "sender" in settings and settings["sender"] is not None: return settings["sender"] return None def __interface_id(self, interface): self.check_interface(interface) return interface def add_interface(self, zone, interface, sender=None, use_zone_transaction=None): self._fw.check_panic() _zone = self._fw.check_zone(zone) _obj = self._zones[_zone] interface_id = self.__interface_id(interface) if interface_id in _obj.settings["interfaces"]: raise FirewallError(errors.ZONE_ALREADY_SET, "'%s' already bound to '%s'" % (interface, zone)) if self.get_zone_of_interface(interface) is not None: raise FirewallError(errors.ZONE_CONFLICT, "'%s' already bound to a zone" % interface) log.debug1("Setting zone of interface '%s' to '%s'" % (interface, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if not _obj.applied: self.apply_zone_settings(zone, use_zone_transaction=zone_transaction) zone_transaction.add_fail(self.set_zone_applied, _zone, False) self._interface(True, _zone, interface, zone_transaction) self.__register_interface(_obj, interface_id, zone, sender) zone_transaction.add_fail(self.__unregister_interface, _obj, interface_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_interface(self, _obj, interface_id, zone, sender): _obj.settings["interfaces"][interface_id] = \ self.__gen_settings(0, sender) # add information whether we add to default or specific zone _obj.settings["interfaces"][interface_id]["__default__"] = \ (not zone or zone == "") def change_zone_of_interface(self, zone, interface, sender=None): self._fw.check_panic() _old_zone = self.get_zone_of_interface(interface) _new_zone = self._fw.check_zone(zone) if _new_zone == _old_zone: return _old_zone if _old_zone is not None: self.remove_interface(_old_zone, interface) _zone = self.add_interface(zone, interface, sender) return _zone def change_default_zone(self, old_zone, new_zone, use_transaction=None): self._fw.check_panic() if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction zone_transaction = transaction.zone_transaction(new_zone) self.apply_zone_settings(new_zone, zone_transaction) self._interface(True, new_zone, "+", zone_transaction, append=True) if old_zone is not None and old_zone != "": zone_transaction = transaction.zone_transaction(old_zone) self._interface(False, old_zone, "+", zone_transaction, append=True) if use_transaction is None: transaction.execute(True) def remove_interface(self, zone, interface, use_zone_transaction=None): self._fw.check_panic() zoi = self.get_zone_of_interface(interface) if zoi is None: raise FirewallError(errors.UNKNOWN_INTERFACE, "'%s' is not in any zone" % interface) _zone = zoi if zone == "" else self._fw.check_zone(zone) if zoi != _zone: raise FirewallError(errors.ZONE_CONFLICT, "remove_interface(%s, %s): zoi='%s'" % \ (zone, interface, zoi)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction _obj = self._zones[_zone] interface_id = self.__interface_id(interface) self._interface(False, _zone, interface, zone_transaction) zone_transaction.add_post(self.__unregister_interface, _obj, interface_id) if use_zone_transaction is None: zone_transaction.execute(True) # self.unapply_zone_settings_if_unused(_zone) return _zone def __unregister_interface(self, _obj, interface_id): if interface_id in _obj.settings["interfaces"]: del _obj.settings["interfaces"][interface_id] def query_interface(self, zone, interface): return self.__interface_id(interface) in self.get_settings(zone)["interfaces"] def list_interfaces(self, zone): return self.get_settings(zone)["interfaces"].keys() # SOURCES def check_source(self, source): if checkIPnMask(source): return "ipv4" elif checkIP6nMask(source): return "ipv6" elif check_mac(source): return "" elif source.startswith("ipset:"): self._check_ipset_type_for_source(source[6:]) self._check_ipset_applied(source[6:]) return self._ipset_family(source[6:]) else: raise FirewallError(errors.INVALID_ADDR, source) def __source_id(self, source): ipv = self.check_source(source) return (ipv, source) def add_source(self, zone, source, sender=None, use_zone_transaction=None): self._fw.check_panic() _zone = self._fw.check_zone(zone) _obj = self._zones[_zone] if check_mac(source): source = source.upper() source_id = self.__source_id(source) if source_id in _obj.settings["sources"]: raise FirewallError(errors.ZONE_ALREADY_SET, "'%s' already bound to '%s'" % (source, _zone)) if self.get_zone_of_source(source) is not None: raise FirewallError(errors.ZONE_CONFLICT, "'%s' already bound to a zone" % source) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if not _obj.applied: self.apply_zone_settings(zone, use_zone_transaction=zone_transaction) zone_transaction.add_fail(self.set_zone_applied, _zone, False) self._source(True, _zone, source_id[0], source_id[1], zone_transaction) self.__register_source(_obj, source_id, zone, sender) zone_transaction.add_fail(self.__unregister_source, _obj, source_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_source(self, _obj, source_id, zone, sender): _obj.settings["sources"][source_id] = \ self.__gen_settings(0, sender) # add information whether we add to default or specific zone _obj.settings["sources"][source_id]["__default__"] = (not zone or zone == "") def change_zone_of_source(self, zone, source, sender=None): self._fw.check_panic() _old_zone = self.get_zone_of_source(source) _new_zone = self._fw.check_zone(zone) if _new_zone == _old_zone: return _old_zone if check_mac(source): source = source.upper() if _old_zone is not None: self.remove_source(_old_zone, source) _zone = self.add_source(zone, source, sender) return _zone def remove_source(self, zone, source, use_zone_transaction=None): self._fw.check_panic() if check_mac(source): source = source.upper() zos = self.get_zone_of_source(source) if zos is None: raise FirewallError(errors.UNKNOWN_SOURCE, "'%s' is not in any zone" % source) _zone = zos if zone == "" else self._fw.check_zone(zone) if zos != _zone: raise FirewallError(errors.ZONE_CONFLICT, "remove_source(%s, %s): zos='%s'" % \ (zone, source, zos)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction _obj = self._zones[_zone] source_id = self.__source_id(source) self._source(False, _zone, source_id[0], source_id[1], zone_transaction) zone_transaction.add_post(self.__unregister_source, _obj, source_id) if use_zone_transaction is None: zone_transaction.execute(True) # self.unapply_zone_settings_if_unused(_zone) return _zone def __unregister_source(self, _obj, source_id): if source_id in _obj.settings["sources"]: del _obj.settings["sources"][source_id] def query_source(self, zone, source): if check_mac(source): source = source.upper() return self.__source_id(source) in self.get_settings(zone)["sources"] def list_sources(self, zone): return [ k[1] for k in self.get_settings(zone)["sources"].keys() ] # RICH LANGUAGE def check_rule(self, rule): rule.check() def __rule_id(self, rule): self.check_rule(rule) return str(rule) def _rule_source_ipv(self, source): if not source: return None if source.addr: if checkIPnMask(source.addr): return "ipv4" elif checkIP6nMask(source.addr): return "ipv6" elif hasattr(source, "mac") and source.mac: return "" elif hasattr(source, "ipset") and source.ipset: self._check_ipset_type_for_source(source.ipset) self._check_ipset_applied(source.ipset) return self._ipset_family(source.ipset) return None def __rule(self, enable, zone, rule, mark_id, zone_transaction): self._rule_prepare(enable, zone, rule, mark_id, zone_transaction) def add_rule(self, zone, rule, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] rule_id = self.__rule_id(rule) if rule_id in _obj.settings["rules"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (rule, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if type(rule.element) == Rich_ForwardPort: mark = self._fw.new_mark() else: mark = None if _obj.applied: self.__rule(True, _zone, rule, mark, zone_transaction) self.__register_rule(_obj, rule_id, mark, timeout, sender) zone_transaction.add_fail(self.__unregister_rule, _obj, rule_id, mark) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_rule(self, _obj, rule_id, mark, timeout, sender): _obj.settings["rules"][rule_id] = self.__gen_settings( timeout, sender, mark=mark) def remove_rule(self, zone, rule, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] rule_id = self.__rule_id(rule) if rule_id not in _obj.settings["rules"]: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (rule, _zone)) if "mark" in _obj.settings["rules"][rule_id]: mark = _obj.settings["rules"][rule_id]["mark"] else: mark = None if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self.__rule(False, _zone, rule, mark, zone_transaction) zone_transaction.add_post(self.__unregister_rule, _obj, rule_id, mark) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_rule(self, _obj, rule_id, mark=None): if rule_id in _obj.settings["rules"]: del _obj.settings["rules"][rule_id] if mark: self._fw.del_mark(mark) def query_rule(self, zone, rule): return self.__rule_id(rule) in self.get_settings(zone)["rules"] def list_rules(self, zone): return list(self.get_settings(zone)["rules"].keys()) # SERVICES def check_service(self, service): self._fw.check_service(service) def __service_id(self, service): self.check_service(service) return service def add_service(self, zone, service, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] service_id = self.__service_id(service) if service_id in _obj.settings["services"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (service, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._service(True, _zone, service, zone_transaction) self.__register_service(_obj, service_id, timeout, sender) zone_transaction.add_fail(self.__unregister_service, _obj, service_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_service(self, _obj, service_id, timeout, sender): _obj.settings["services"][service_id] = \ self.__gen_settings(timeout, sender) def remove_service(self, zone, service, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] service_id = self.__service_id(service) if service_id not in _obj.settings["services"]: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (service, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._service(False, _zone, service, zone_transaction) zone_transaction.add_post(self.__unregister_service, _obj, service_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_service(self, _obj, service_id): if service_id in _obj.settings["services"]: del _obj.settings["services"][service_id] def query_service(self, zone, service): return self.__service_id(service) in self.get_settings(zone)["services"] def list_services(self, zone): return self.get_settings(zone)["services"].keys() def get_helpers_for_service_modules(self, modules, enable): # If automatic helper assignment is turned off, helpers that # do not have ports defined will be replaced by the helpers # that the helper.module defines. _helpers = [ ] for module in modules: try: helper = self._fw.helper.get_helper(module) except FirewallError: raise FirewallError(errors.INVALID_HELPER, module) if self._fw.nf_conntrack_helper_setting == 0 and \ len(helper.ports) < 1: _module_short_name = get_nf_conntrack_short_name(helper.module) try: _helper = self._fw.helper.get_helper(_module_short_name) _helpers.append(_helper) except FirewallError: if enable: log.warning("Helper '%s' is not available" % _module_short_name) continue else: _helpers.append(helper) return _helpers # PORTS def check_port(self, port, protocol): self._fw.check_port(port) self._fw.check_tcpudp(protocol) def __port_id(self, port, protocol): self.check_port(port, protocol) return (portStr(port, "-"), protocol) def add_port(self, zone, port, protocol, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] port_id = self.__port_id(port, protocol) if port_id in _obj.settings["ports"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s:%s' already in '%s'" % (port, protocol, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._port(True, _zone, port, protocol, zone_transaction) self.__register_port(_obj, port_id, timeout, sender) zone_transaction.add_fail(self.__unregister_port, _obj, port_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_port(self, _obj, port_id, timeout, sender): _obj.settings["ports"][port_id] = \ self.__gen_settings(timeout, sender) def remove_port(self, zone, port, protocol, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] port_id = self.__port_id(port, protocol) if port_id not in _obj.settings["ports"]: raise FirewallError(errors.NOT_ENABLED, "'%s:%s' not in '%s'" % (port, protocol, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._port(False, _zone, port, protocol, zone_transaction) zone_transaction.add_post(self.__unregister_port, _obj, port_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_port(self, _obj, port_id): if port_id in _obj.settings["ports"]: del _obj.settings["ports"][port_id] def query_port(self, zone, port, protocol): if self.__port_id(port, protocol) in self.get_settings(zone)["ports"]: return True else: # It might be a single port query that is inside a range for (_port, _protocol) in self.get_settings(zone)["ports"]: if portInPortRange(port, _port) and protocol == _protocol: return True return False def list_ports(self, zone): return list(self.get_settings(zone)["ports"].keys()) # PROTOCOLS def check_protocol(self, protocol): if not checkProtocol(protocol): raise FirewallError(errors.INVALID_PROTOCOL, protocol) def __protocol_id(self, protocol): self.check_protocol(protocol) return protocol def add_protocol(self, zone, protocol, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] protocol_id = self.__protocol_id(protocol) if protocol_id in _obj.settings["protocols"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (protocol, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._protocol(True, _zone, protocol, zone_transaction) self.__register_protocol(_obj, protocol_id, timeout, sender) zone_transaction.add_fail(self.__unregister_protocol, _obj, protocol_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_protocol(self, _obj, protocol_id, timeout, sender): _obj.settings["protocols"][protocol_id] = \ self.__gen_settings(timeout, sender) def remove_protocol(self, zone, protocol, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] protocol_id = self.__protocol_id(protocol) if protocol_id not in _obj.settings["protocols"]: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (protocol, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._protocol(False, _zone, protocol, zone_transaction) zone_transaction.add_post(self.__unregister_protocol, _obj, protocol_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_protocol(self, _obj, protocol_id): if protocol_id in _obj.settings["protocols"]: del _obj.settings["protocols"][protocol_id] def query_protocol(self, zone, protocol): return self.__protocol_id(protocol) in self.get_settings(zone)["protocols"] def list_protocols(self, zone): return list(self.get_settings(zone)["protocols"].keys()) # SOURCE PORTS def __source_port_id(self, port, protocol): self.check_port(port, protocol) return (portStr(port, "-"), protocol) def add_source_port(self, zone, port, protocol, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] port_id = self.__source_port_id(port, protocol) if port_id in _obj.settings["source_ports"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s:%s' already in '%s'" % (port, protocol, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._source_port(True, _zone, port, protocol, zone_transaction) self.__register_source_port(_obj, port_id, timeout, sender) zone_transaction.add_fail(self.__unregister_source_port, _obj, port_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_source_port(self, _obj, port_id, timeout, sender): _obj.settings["source_ports"][port_id] = \ self.__gen_settings(timeout, sender) def remove_source_port(self, zone, port, protocol, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] port_id = self.__source_port_id(port, protocol) if port_id not in _obj.settings["source_ports"]: raise FirewallError(errors.NOT_ENABLED, "'%s:%s' not in '%s'" % (port, protocol, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._source_port(False, _zone, port, protocol, zone_transaction) zone_transaction.add_post(self.__unregister_source_port, _obj, port_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_source_port(self, _obj, port_id): if port_id in _obj.settings["source_ports"]: del _obj.settings["source_ports"][port_id] def query_source_port(self, zone, port, protocol): return self.__source_port_id(port, protocol) in \ self.get_settings(zone)["source_ports"] def list_source_ports(self, zone): return list(self.get_settings(zone)["source_ports"].keys()) # MASQUERADE def __masquerade_id(self): return True def add_masquerade(self, zone, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] masquerade_id = self.__masquerade_id() if masquerade_id in _obj.settings["masquerade"]: raise FirewallError(errors.ALREADY_ENABLED, "masquerade already enabled in '%s'" % _zone) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._masquerade(True, _zone, zone_transaction) self.__register_masquerade(_obj, masquerade_id, timeout, sender) zone_transaction.add_fail(self.__unregister_masquerade, _obj, masquerade_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_masquerade(self, _obj, masquerade_id, timeout, sender): _obj.settings["masquerade"][masquerade_id] = \ self.__gen_settings(timeout, sender) def remove_masquerade(self, zone, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] masquerade_id = self.__masquerade_id() if masquerade_id not in _obj.settings["masquerade"]: raise FirewallError(errors.NOT_ENABLED, "masquerade not enabled in '%s'" % _zone) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._masquerade(False, _zone, zone_transaction) zone_transaction.add_post(self.__unregister_masquerade, _obj, masquerade_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_masquerade(self, _obj, masquerade_id): if masquerade_id in _obj.settings["masquerade"]: del _obj.settings["masquerade"][masquerade_id] def query_masquerade(self, zone): return self.__masquerade_id() in self.get_settings(zone)["masquerade"] # PORT FORWARDING def check_forward_port(self, ipv, port, protocol, toport=None, toaddr=None): self._fw.check_port(port) self._fw.check_tcpudp(protocol) if toport: self._fw.check_port(toport) if toaddr: if not check_single_address(ipv, toaddr): raise FirewallError(errors.INVALID_ADDR, toaddr) if not toport and not toaddr: raise FirewallError( errors.INVALID_FORWARD, "port-forwarding is missing to-port AND to-addr") def __forward_port_id(self, port, protocol, toport=None, toaddr=None): if check_single_address("ipv6", toaddr): self.check_forward_port("ipv6", port, protocol, toport, toaddr) else: self.check_forward_port("ipv4", port, protocol, toport, toaddr) return (portStr(port, "-"), protocol, portStr(toport, "-"), str(toaddr)) def add_forward_port(self, zone, port, protocol, toport=None, toaddr=None, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] forward_id = self.__forward_port_id(port, protocol, toport, toaddr) if forward_id in _obj.settings["forward_ports"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s:%s:%s:%s' already in '%s'" % \ (port, protocol, toport, toaddr, _zone)) mark = self._fw.new_mark() if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._forward_port(True, _zone, zone_transaction, port, protocol, toport, toaddr, mark_id=mark) self.__register_forward_port(_obj, forward_id, timeout, sender, mark) zone_transaction.add_fail(self.__unregister_forward_port, _obj, forward_id, mark) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_forward_port(self, _obj, forward_id, timeout, sender, mark): _obj.settings["forward_ports"][forward_id] = \ self.__gen_settings(timeout, sender, mark=mark) def remove_forward_port(self, zone, port, protocol, toport=None, toaddr=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] forward_id = self.__forward_port_id(port, protocol, toport, toaddr) if forward_id not in _obj.settings["forward_ports"]: raise FirewallError(errors.NOT_ENABLED, "'%s:%s:%s:%s' not in '%s'" % \ (port, protocol, toport, toaddr, _zone)) mark = _obj.settings["forward_ports"][forward_id]["mark"] if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._forward_port(False, _zone, zone_transaction, port, protocol, toport, toaddr, mark_id=mark) zone_transaction.add_post(self.__unregister_forward_port, _obj, forward_id, mark) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_forward_port(self, _obj, forward_id, mark): if forward_id in _obj.settings["forward_ports"]: del _obj.settings["forward_ports"][forward_id] self._fw.del_mark(mark) def query_forward_port(self, zone, port, protocol, toport=None, toaddr=None): forward_id = self.__forward_port_id(port, protocol, toport, toaddr) return forward_id in self.get_settings(zone)["forward_ports"] def list_forward_ports(self, zone): return list(self.get_settings(zone)["forward_ports"].keys()) # ICMP BLOCK def check_icmp_block(self, icmp): self._fw.check_icmptype(icmp) def __icmp_block_id(self, icmp): self.check_icmp_block(icmp) return icmp def add_icmp_block(self, zone, icmp, timeout=0, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] icmp_id = self.__icmp_block_id(icmp) if icmp_id in _obj.settings["icmp_blocks"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (icmp, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._icmp_block(True, _zone, icmp, zone_transaction) self.__register_icmp_block(_obj, icmp_id, timeout, sender) zone_transaction.add_fail(self.__unregister_icmp_block, _obj, icmp_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_icmp_block(self, _obj, icmp_id, timeout, sender): _obj.settings["icmp_blocks"][icmp_id] = \ self.__gen_settings(timeout, sender) def remove_icmp_block(self, zone, icmp, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] icmp_id = self.__icmp_block_id(icmp) if icmp_id not in _obj.settings["icmp_blocks"]: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (icmp, _zone)) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: self._icmp_block(False, _zone, icmp, zone_transaction) zone_transaction.add_post(self.__unregister_icmp_block, _obj, icmp_id) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_icmp_block(self, _obj, icmp_id): if icmp_id in _obj.settings["icmp_blocks"]: del _obj.settings["icmp_blocks"][icmp_id] def query_icmp_block(self, zone, icmp): return self.__icmp_block_id(icmp) in self.get_settings(zone)["icmp_blocks"] def list_icmp_blocks(self, zone): return self.get_settings(zone)["icmp_blocks"].keys() # ICMP BLOCK INVERSION def __icmp_block_inversion_id(self): return True def add_icmp_block_inversion(self, zone, sender=None, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] icmp_block_inversion_id = self.__icmp_block_inversion_id() if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]: raise FirewallError( errors.ALREADY_ENABLED, "icmp-block-inversion already enabled in '%s'" % _zone) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: # undo icmp blocks for args in self.get_settings(_zone)["icmp_blocks"]: self._icmp_block(False, _zone, args, zone_transaction) self._icmp_block_inversion(False, _zone, zone_transaction) self.__register_icmp_block_inversion(_obj, icmp_block_inversion_id, sender) zone_transaction.add_fail(self.__undo_icmp_block_inversion, _zone, _obj, icmp_block_inversion_id) # redo icmp blocks if _obj.applied: for args in self.get_settings(_zone)["icmp_blocks"]: self._icmp_block(True, _zone, args, zone_transaction) self._icmp_block_inversion(True, _zone, zone_transaction) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __register_icmp_block_inversion(self, _obj, icmp_block_inversion_id, sender): _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] = \ self.__gen_settings(0, sender) def __undo_icmp_block_inversion(self, _zone, _obj, icmp_block_inversion_id): zone_transaction = self.new_zone_transaction(_zone) # undo icmp blocks if _obj.applied: for args in self.get_settings(_zone)["icmp_blocks"]: self._icmp_block(False, _zone, args, zone_transaction) if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]: del _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] # redo icmp blocks if _obj.applied: for args in self.get_settings(_zone)["icmp_blocks"]: self._icmp_block(True, _zone, args, zone_transaction) zone_transaction.execute(True) def remove_icmp_block_inversion(self, zone, use_zone_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] icmp_block_inversion_id = self.__icmp_block_inversion_id() if icmp_block_inversion_id not in _obj.settings["icmp_block_inversion"]: raise FirewallError( errors.NOT_ENABLED, "icmp-block-inversion not enabled in '%s'" % _zone) if use_zone_transaction is None: zone_transaction = self.new_zone_transaction(_zone) else: zone_transaction = use_zone_transaction if _obj.applied: # undo icmp blocks for args in self.get_settings(_zone)["icmp_blocks"]: self._icmp_block(False, _zone, args, zone_transaction) self._icmp_block_inversion(False, _zone, zone_transaction) self.__unregister_icmp_block_inversion(_obj, icmp_block_inversion_id) zone_transaction.add_fail(self.__register_icmp_block_inversion, _obj, icmp_block_inversion_id, None) # redo icmp blocks if _obj.applied: for args in self.get_settings(_zone)["icmp_blocks"]: self._icmp_block(True, _zone, args, zone_transaction) self._icmp_block_inversion(True, _zone, zone_transaction) if use_zone_transaction is None: zone_transaction.execute(True) return _zone def __unregister_icmp_block_inversion(self, _obj, icmp_block_inversion_id): if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]: del _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] def query_icmp_block_inversion(self, zone): return self.__icmp_block_inversion_id() in \ self.get_settings(zone)["icmp_block_inversion"] # dynamic chain handling def gen_chain_rules(self, zone, create, chains, transaction): for (table, chain) in chains: if create: if zone in self._chains and \ table in self._chains[zone] and \ chain in self._chains[zone][table]: continue else: if zone not in self._chains or \ table not in self._chains[zone] or \ chain not in self._chains[zone][table]: continue for backend in self._fw.enabled_backends(): if backend.zones_supported and \ table in backend.get_available_tables(): rules = backend.build_zone_chain_rules(zone, table, chain) transaction.add_rules(backend, rules) self._register_chains(zone, create, chains) transaction.add_fail(self._register_chains, zone, create, chains) def _interface(self, enable, zone, interface, zone_transaction, append=False): for backend in self._fw.enabled_backends(): if not backend.zones_supported: continue for table in backend.get_available_tables(): for chain in backend.get_zone_table_chains(table): # create needed chains if not done already if enable: zone_transaction.add_chain(table, chain) rules = backend.build_zone_source_interface_rules(enable, zone, interface, table, chain, append) zone_transaction.add_rules(backend, rules) # IPSETS def _ipset_family(self, name): if self._fw.ipset.get_type(name) == "hash:mac": return None return self._fw.ipset.get_family(name) def __ipset_type(self, name): return self._fw.ipset.get_type(name) def _ipset_match_flags(self, name, flag): return ",".join([flag] * self._fw.ipset.get_dimension(name)) def _check_ipset_applied(self, name): return self._fw.ipset.check_applied(name) def _check_ipset_type_for_source(self, name): _type = self.__ipset_type(name) if _type not in ZONE_SOURCE_IPSET_TYPES: raise FirewallError( errors.INVALID_IPSET, "ipset '%s' with type '%s' not usable as source" % \ (name, _type)) def _source(self, enable, zone, ipv, source, zone_transaction): # For mac source bindings ipv is an empty string, the mac source will # be added for ipv4 and ipv6 for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends(): if not backend.zones_supported: continue for table in backend.get_available_tables(): for chain in backend.get_zone_table_chains(table): # create needed chains if not done already if enable: zone_transaction.add_chain(table, chain) rules = backend.build_zone_source_address_rules(enable, zone, source, table, chain) zone_transaction.add_rules(backend, rules) def _rule_prepare(self, enable, zone, rule, mark_id, zone_transaction): if rule.family is not None: ipvs = [ rule.family ] else: ipvs = [ipv for ipv in ["ipv4", "ipv6"] if self._fw.is_ipv_enabled(ipv)] source_ipv = self._rule_source_ipv(rule.source) if source_ipv is not None and source_ipv != "": if rule.family is not None: # rule family is defined by user, no way to change it if rule.family != source_ipv: raise FirewallError(errors.INVALID_RULE, "Source address family '%s' conflicts with rule family '%s'." % (source_ipv, rule.family)) else: # use the source family as rule family ipvs = [ source_ipv ] # add an element to object to allow backends to know what ipvs this applies to rule.ipvs = ipvs for backend in set([self._fw.get_backend_by_ipv(x) for x in ipvs]): # SERVICE if type(rule.element) == Rich_Service: svc = self._fw.service.get_service(rule.element.name) destinations = [] if len(svc.destination) > 0: if rule.destination: # we can not use two destinations at the same time raise FirewallError(errors.INVALID_RULE, "Destination conflict with service.") for ipv in ipvs: if ipv in svc.destination and backend.is_ipv_supported(ipv): destinations.append(svc.destination[ipv]) else: # dummy for the following for loop destinations.append(None) for destination in destinations: if enable: zone_transaction.add_chain("filter", "INPUT") if self._fw.nf_conntrack_helper_setting == 0: zone_transaction.add_chain("raw", "PREROUTING") if type(rule.action) == Rich_Accept: # only load modules for accept action helpers = self.get_helpers_for_service_modules(svc.modules, enable) modules = [ ] for helper in helpers: module = helper.module _module_short_name = get_nf_conntrack_short_name(module) if self._fw.nf_conntrack_helper_setting == 0: nat_module = module.replace("conntrack", "nat") modules.append(nat_module) if helper.family != "" and not backend.is_ipv_supported(helper.family): # no support for family ipv, continue continue if len(helper.ports) < 1: modules.append(module) else: for (port,proto) in helper.ports: rules = backend.build_zone_helper_ports_rules( enable, zone, proto, port, destination, helper.name, _module_short_name) zone_transaction.add_rules(backend, rules) else: if helper.module not in modules: modules.append(helper.module) nat_module = helper.module.replace("conntrack", "nat") modules.append(nat_module) zone_transaction.add_modules(modules) # create rules for (port,proto) in svc.ports: if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_ports_rules( enable, zone, proto, port, destination, rule) zone_transaction.add_rules(backend, rules) for proto in svc.protocols: if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_protocol_rules( enable, zone, proto, destination, rule) zone_transaction.add_rules(backend, rules) # create rules for (port,proto) in svc.source_ports: if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_source_ports_rules( enable, zone, proto, port, destination, rule) zone_transaction.add_rules(backend, rules) # PORT elif type(rule.element) == Rich_Port: port = rule.element.port protocol = rule.element.protocol self.check_port(port, protocol) if enable: zone_transaction.add_chain("filter", "INPUT") if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_ports_rules( enable, zone, protocol, port, None, rule) zone_transaction.add_rules(backend, rules) # PROTOCOL elif type(rule.element) == Rich_Protocol: protocol = rule.element.value self.check_protocol(protocol) if enable: zone_transaction.add_chain("filter", "INPUT") if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_protocol_rules( enable, zone, protocol, None, rule) zone_transaction.add_rules(backend, rules) # MASQUERADE elif type(rule.element) == Rich_Masquerade: if enable: zone_transaction.add_chain("nat", "POSTROUTING") zone_transaction.add_chain("filter", "FORWARD_OUT") for ipv in ipvs: if backend.is_ipv_supported(ipv): zone_transaction.add_post(enable_ip_forwarding, ipv) rules = backend.build_zone_masquerade_rules(enable, zone, rule) zone_transaction.add_rules(backend, rules) # FORWARD PORT elif type(rule.element) == Rich_ForwardPort: port = rule.element.port protocol = rule.element.protocol toport = rule.element.to_port toaddr = rule.element.to_address for ipv in ipvs: if backend.is_ipv_supported(ipv): self.check_forward_port(ipv, port, protocol, toport, toaddr) if toaddr and enable: zone_transaction.add_post(enable_ip_forwarding, ipv) filter_chain = "INPUT" if not toaddr else "FORWARD_IN" if enable: zone_transaction.add_chain("mangle", "PREROUTING") zone_transaction.add_chain("nat", "PREROUTING") zone_transaction.add_chain("filter", filter_chain) rules = backend.build_zone_forward_port_rules( enable, zone, filter_chain, port, protocol, toport, toaddr, mark_id, rule) zone_transaction.add_rules(backend, rules) # SOURCE PORT elif type(rule.element) == Rich_SourcePort: port = rule.element.port protocol = rule.element.protocol self.check_port(port, protocol) if enable: zone_transaction.add_chain("filter", "INPUT") if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_source_ports_rules( enable, zone, protocol, port, None, rule) zone_transaction.add_rules(backend, rules) # ICMP BLOCK and ICMP TYPE elif type(rule.element) == Rich_IcmpBlock or \ type(rule.element) == Rich_IcmpType: ict = self._fw.icmptype.get_icmptype(rule.element.name) if type(rule.element) == Rich_IcmpBlock and \ rule.action and type(rule.action) == Rich_Accept: # icmp block might have reject or drop action, but not accept raise FirewallError(errors.INVALID_RULE, "IcmpBlock not usable with accept action") if ict.destination: for ipv in ipvs: if ipv in ict.destination \ and not backend.is_ipv_supported(ipv): raise FirewallError( errors.INVALID_RULE, "Icmp%s %s not usable with %s" % \ ("Block" if type(rule.element) == \ Rich_IcmpBlock else "Type", rule.element.name, backend.name)) table = "filter" if enable: zone_transaction.add_chain(table, "INPUT") zone_transaction.add_chain(table, "FORWARD_IN") rules = backend.build_zone_icmp_block_rules(enable, zone, ict, rule) zone_transaction.add_rules(backend, rules) elif rule.element is None: if enable: zone_transaction.add_chain("filter", "INPUT") if enable and type(rule.action) == Rich_Mark: zone_transaction.add_chain("mangle", "PREROUTING") rules = backend.build_zone_rich_source_destination_rules( enable, zone, rule) zone_transaction.add_rules(backend, rules) # EVERYTHING ELSE else: raise FirewallError(errors.INVALID_RULE, "Unknown element %s" % type(rule.element)) return mark_id def _service(self, enable, zone, service, zone_transaction): svc = self._fw.service.get_service(service) helpers = self.get_helpers_for_service_modules(svc.modules, enable) if enable: if self._fw.nf_conntrack_helper_setting == 0: zone_transaction.add_chain("raw", "PREROUTING") else: modules = [ ] for helper in helpers: modules.append(helper.module) nat_module = helper.module.replace("conntrack", "nat") modules.append(nat_module) zone_transaction.add_modules(modules) zone_transaction.add_chain("filter", "INPUT") # build a list of (backend, destination). The destination may be ipv4, # ipv6 or None # backends_ipv = [] for ipv in ["ipv4", "ipv6"]: if not self._fw.is_ipv_enabled(ipv): continue backend = self._fw.get_backend_by_ipv(ipv) if len(svc.destination) > 0: if ipv in svc.destination: backends_ipv.append((backend, svc.destination[ipv])) else: if (backend, None) not in backends_ipv: backends_ipv.append((backend, None)) for (backend,destination) in backends_ipv: if self._fw.nf_conntrack_helper_setting == 0: for helper in helpers: module = helper.module _module_short_name = get_nf_conntrack_short_name(module) nat_module = helper.module.replace("conntrack", "nat") zone_transaction.add_module(nat_module) if helper.family != "" and not backend.is_ipv_supported(helper.family): # no support for family ipv, continue continue if len(helper.ports) < 1: zone_transaction.add_module(module) else: for (port,proto) in helper.ports: rules = backend.build_zone_helper_ports_rules( enable, zone, proto, port, destination, helper.name, _module_short_name) zone_transaction.add_rules(backend, rules) for (port,proto) in svc.ports: rules = backend.build_zone_ports_rules(enable, zone, proto, port, destination) zone_transaction.add_rules(backend, rules) for protocol in svc.protocols: rules = backend.build_zone_protocol_rules( enable, zone, protocol, destination) zone_transaction.add_rules(backend, rules) for (port,proto) in svc.source_ports: rules = backend.build_zone_source_ports_rules( enable, zone, proto, port, destination) zone_transaction.add_rules(backend, rules) def _port(self, enable, zone, port, protocol, zone_transaction): if enable: zone_transaction.add_chain("filter", "INPUT") for backend in self._fw.enabled_backends(): if not backend.zones_supported: continue rules = backend.build_zone_ports_rules(enable, zone, protocol, port) zone_transaction.add_rules(backend, rules) def _protocol(self, enable, zone, protocol, zone_transaction): if enable: zone_transaction.add_chain("filter", "INPUT") for backend in self._fw.enabled_backends(): if not backend.zones_supported: continue rules = backend.build_zone_protocol_rules(enable, zone, protocol) zone_transaction.add_rules(backend, rules) def _source_port(self, enable, zone, port, protocol, zone_transaction): if enable: zone_transaction.add_chain("filter", "INPUT") for backend in self._fw.enabled_backends(): if not backend.zones_supported: continue rules = backend.build_zone_source_ports_rules(enable, zone, protocol, port) zone_transaction.add_rules(backend, rules) def _masquerade(self, enable, zone, zone_transaction): if enable: zone_transaction.add_chain("nat", "POSTROUTING") zone_transaction.add_chain("filter", "FORWARD_OUT") ipv = "ipv4" zone_transaction.add_post(enable_ip_forwarding, ipv) backend = self._fw.get_backend_by_ipv(ipv) rules = backend.build_zone_masquerade_rules(enable, zone) zone_transaction.add_rules(backend, rules) def _forward_port(self, enable, zone, zone_transaction, port, protocol, toport=None, toaddr=None, mark_id=None): if check_single_address("ipv6", toaddr): ipv = "ipv6" else: ipv = "ipv4" filter_chain = "INPUT" if not toaddr else "FORWARD_IN" if enable: zone_transaction.add_chain("mangle", "PREROUTING") zone_transaction.add_chain("nat", "PREROUTING") zone_transaction.add_chain("filter", filter_chain) if toaddr and enable: zone_transaction.add_post(enable_ip_forwarding, ipv) backend = self._fw.get_backend_by_ipv(ipv) rules = backend.build_zone_forward_port_rules( enable, zone, filter_chain, port, protocol, toport, toaddr, mark_id) zone_transaction.add_rules(backend, rules) def _icmp_block(self, enable, zone, icmp, zone_transaction): ict = self._fw.icmptype.get_icmptype(icmp) if enable: zone_transaction.add_chain("filter", "INPUT") zone_transaction.add_chain("filter", "FORWARD_IN") for backend in self._fw.enabled_backends(): if not backend.zones_supported: continue skip_backend = False if ict.destination: for ipv in ["ipv4", "ipv6"]: if ipv in ict.destination: if not backend.is_ipv_supported(ipv): skip_backend = True break if skip_backend: continue rules = backend.build_zone_icmp_block_rules(enable, zone, ict) zone_transaction.add_rules(backend, rules) def _icmp_block_inversion(self, enable, zone, zone_transaction): target = self._zones[zone].target # Do not add general icmp accept rules into a trusted, block or drop # zone. if target in [ "DROP", "%%REJECT%%", "REJECT" ]: return if not self.query_icmp_block_inversion(zone) and target == "ACCEPT": # ibi target and zone target are ACCEPT, no need to add an extra # rule return zone_transaction.add_chain("filter", "INPUT") zone_transaction.add_chain("filter", "FORWARD_IN") # To satisfy nftables backend rule lookup we must execute pending # rules. See nftables.build_zone_icmp_block_inversion_rules() if enable: zone_transaction.execute(enable) zone_transaction.clear() for backend in self._fw.enabled_backends(): if not backend.zones_supported: continue rules = backend.build_zone_icmp_block_inversion_rules(enable, zone) zone_transaction.add_rules(backend, rules) PK!/>EE fw_test.pycnu[ c`c@sdgZddlZddlZddlZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#m$Z$ddl%m&Z&ddl'm(Z(ddl)m*Z*ddlm+Z+ddl,m-Z-de.fdYZ/dS(t Firewall_testiN(tconfig(t functions(tFirewallIcmpType(tFirewallService(t FirewallZone(tFirewallDirect(tFirewallConfig(tFirewallPolicies(t FirewallIPSet(tFirewallHelper(tlog(tfirewalld_conf(tDirect(tservice_reader(ticmptype_reader(t zone_readertZone(t ipset_reader(t IPSET_TYPES(t helper_reader(terrors(t FirewallErrorcBs+eZdZdZdZdZeedZdZedZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZedZdZdZdZdZdZdZdZdZdZdZdZ dZ!RS(cCsttj|_t|_t|_t|_t|_t |_ t ||_ t ||_t||_t||_t||_t|_t||_t||_|jdS(N(R RtFIREWALLD_CONFt_firewalld_conftFalsetip4tables_enabledtip6tables_enabledtebtables_enabledt ipset_enabledRtipset_supported_typesRticmptypeRtserviceRtzoneRtdirectRRtpoliciesR tipsetR thelpert_Firewall_test__init_vars(tself((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt__init__8s      cCshd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |j|jfS(Ns>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)(t __class__RRRt_statet_panict _default_zonet_module_refcountt_markst _min_marktcleanup_on_exittipv6_rpfilter_enabledRt_individual_callst _log_deniedt_automatic_helpers(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt__repr__LscCsyd|_t|_d|_i|_g|_tj|_tj |_ tj |_ tj |_tj|_tj|_dS(NtINITt(R*RR+R,R-R.RtFALLBACK_MINIMAL_MARKR/tFALLBACK_CLEANUP_ON_EXITR0tFALLBACK_IPV6_RPFILTERR1tFALLBACK_INDIVIDUAL_CALLSR2tFALLBACK_LOG_DENIEDR3tFALLBACK_AUTOMATIC_HELPERSR4(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt __init_varsUs          cCs|jS(N(R2(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytindividual_callscsc Cstj}tjdtjy|jjWntk rMtjdn X|jj dru|jj d}n|jj drt |jj d|_ n|jj dr|jj d}|dk r|j d-krt|_qn|jj drp|jj d}|dk rp|j d.krptjd y|jjWqmtk riqmXqpn|jj d r|jj d }|dk r|j d/krt|_n|j d0krt|_qqn|jrtjd n tjd|jj drf|jj d}|dk rf|j d1krftjdt|_qfn|jj dr|jj d}|dks|j dkrd|_q|j |_tjd|jn|jj drm|jj d}|dk rm|j d2kr'd|_n-|j d3krEd |_n|j |_tjd|jqmn|jjtj|jtjdy|jjjWn]tk r }|jjrtjd|jjj|q tjd|jjj|nX|jjtj|j|j tj!d|j tj"d|j tj#d|j tj$dt%|j&j'dkrtjdn|j tj(d|j tj)d|j tj*d|j tj+dt%|j,j-dkrtjdn|j tj.d|j tj/dt%|j0j1dkrrtj2d t3j4d!nt}xEd"d#d$gD]4}||j0j1krtj2d%|t}qqW|rt3j4d!n||j0j1krId&|j0j1kr d&}n$d'|j0j1kr'd'}nd"}tjd(|||}ntjd)|t5tj6} t7j8j9tj6rtjd*tj6y| jWqtk r}tjd+tj6|qXn|jj:tj| |j;||_<d,|_=dS(4Ns"Loading firewalld config file '%s's0Using fallback firewalld configuration settings.t DefaultZonet MinimalMarkt CleanupOnExittnotfalsetLockdowntyesttruesLockdown is enabledt IPv6_rpfiltersIPv6 rpfilter is enabledsIPV6 rpfilter is disabledtIndividualCallssIndividualCalls is enabledt LogDeniedtoffsLogDenied is set to '%s'tAutomaticHelperssAutomaticHelpers is set to '%s'sLoading lockdown whitelists*Failed to load lockdown whitelist '%s': %sR$RisNo icmptypes found.R%R sNo services found.R!sNo zones found.itblocktdropttrustedsZone '%s' is not available.tpublictexternals+Default zone '%s' is not valid. Using '%s'.sUsing default zone '%s'sLoading direct rules file '%s's)Failed to load direct rules file '%s': %stRUNNING(RCRD(syesRG(RCRD(syesRG(syesRG(RCRD(syesRG(>Rt FALLBACK_ZONER tdebug1RRtreadt ExceptiontwarningtgettintR/tNonetlowerRR0R#tenable_lockdownRR1tTrueR2R3R4tset_firewalld_conftcopytdeepcopytlockdown_whitelisttquery_lockdownterrortfilenamet set_policiest_loadertFIREWALLD_IPSETStETC_FIREWALLD_IPSETStFIREWALLD_ICMPTYPEStETC_FIREWALLD_ICMPTYPEStlenRt get_icmptypestFIREWALLD_HELPERStETC_FIREWALLD_HELPERStFIREWALLD_SERVICEStETC_FIREWALLD_SERVICESR t get_servicestFIREWALLD_ZONEStETC_FIREWALLD_ZONESR!t get_zonestfataltsystexitR tFIREWALLD_DIRECTtostpathtexistst set_directt check_zoneR,R*( R'treloadtcomplete_reloadt default_zonetvaluetmsgRctzR!tobj((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt_startfs                            cCs|jdS(N(R(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytstartsc Cstjj|sdS|r|jtjr}|dkr}t}tjj||_|j |j||_t |_ qt }nxt tj |D]}|jds|jtjr|dkrtjjd||fr|jd||f|dtqqnd||f}tjd||y|dkrt||}|j|jjkr|jj|j}tjd||j|j|j|jj|jn!|jjtjrt|_ n|jj||jjtj|n |dkrt||}|j|jjkr|jj|j}tjd||j|j|j|jj |jn!|jjtjrt|_ n|jj!||jj!tj|n>|dkrht"||d |}|r@dtjj|tjj|d d !f|_|j |jntj|} |j|j#j$kr|j#j%|j}|j#j&|j|j'rtjd ||j|||j(|qtjd||j|j|jn*|jjtjrt|_ t| _ n|jj)| |rUtjd ||j|||j(|q|j#j)|n|d kr5t*||}|j|j+j,kr|j+j-|j}tjd||j|j|j|j+j.|jn!|jjtjr t|_ n|j+j/||jj/tj|n|dkrt0||}|j|j1j2kr|j1j3|j}tjd||j|j|j|j1j4|jn!|jjtjrt|_ n|j1j5||jj5tj|ntj6d|Wqt7k r>} tj8d||| qt9k rktj8d||tj:qXqW|r|j'r|j|j#j$kr|j#j%|j}tjd||j|j|jy|j#j&|jWnnX|jj;|jn|j#j)|ndS(NR!s.xmls%s/%stcombinesLoading %s file '%s'Rs Overloads %s '%s' ('%s/%s')R t no_check_nameiis Combining %s '%s' ('%s/%s')R$R%sUnknown reader type %ssFailed to load %s file '%s': %ssFailed to load %s file '%s':s0 Overloading and deactivating %s '%s' ('%s/%s')(<RyRztisdirt startswithRt ETC_FIREWALLDRtbasenametnamet check_nameRtdefaulttsortedtlistdirtendswithRfR]R RTRRRlt get_icmptypeRdtremove_icmptypet add_icmptypeR_R`RR Rqt get_servicetremove_servicet add_serviceRR!Rttget_zonet remove_zonetcombinedRtadd_zoneRR$t get_ipsetst get_ipsett remove_ipsett add_ipsetRR%t get_helperst get_helpert remove_helpert add_helperRuRRcRVt exceptiont forget_zone( R'Rzt reader_typeRt combined_zoneRdRRtorig_objt config_objR((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRfs                                             cCs|jj|jj|jj|jj|jj|jj|jj|jj|j j|j dS(N( RtcleanupR R!R$R%RR"R#RR&(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRs         cCs|jdS(N(R(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytstopscCsdS(N((R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_panicscCsV|}| s|dkr(|j}n||jjkrRttj|n|S(NR7(tget_default_zoneR!RtRRt INVALID_ZONE(R'R!t_zone((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR}s cCs(tj|s$ttj|ndS(N(RtcheckInterfaceRRtINVALID_INTERFACE(R't interface((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytcheck_interfacescCs|jj|dS(N(R t check_service(R'R ((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRscCs tj|}|dksY|dksY|dksYt|dkr|d|dkr|dkrytjd|nz|dkrtjd|nZ|dkrtjd|n:t|dkr|d|dkrtjd |nttj|ndS( Niiiiis'%s': port > 65535s'%s': port is invalids'%s': port is ambiguouss'%s': range start >= end( Rt getPortRangeRZRkR RTRRt INVALID_PORT(R'tporttrange((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_ports$&   &cCsA|sttjn|dkr=ttjd|ndS(Nttcptudptsctptdccps''%s' not in {'tcp'|'udp'|'sctp'|'dccp'}(RRRR(RRtMISSING_PROTOCOLtINVALID_PROTOCOL(R'tprotocol((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_tcpudps   cCs(tj|s$ttj|ndS(N(RtcheckIPRRt INVALID_ADDR(R'tip((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytcheck_ipscCs||dkr3tj|sxttj|qxnE|dkrftj|sxttj|qxnttjddS(Ntipv4tipv6s'%s' not in {'ipv4'|'ipv6'}(Rt checkIPnMaskRRRt checkIP6nMaskt INVALID_IPV(R'tipvtsource((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt check_addresss   cCs|jj|dS(N(Rtcheck_icmptype(R'ticmp((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRscCsdS(N((R'R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR~scCs|jS(N(R*(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyt get_statescCsdS(N((R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytenable_panic_modescCsdS(N((R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytdisable_panic_modescCs|jS(N(R+(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytquery_panic_modescCs|jS(N(R3(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytget_log_deniedscCs|tjkr:ttjd|djtjfn||jkr||_|jj d||jj |j nttj |dS(Ns'%s', choose from '%s's','RJ( RtLOG_DENIED_VALUESRRt INVALID_VALUEtjoinRR3RtsettwriteR~t ALREADY_SET(R'R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytset_log_denieds    cCs|jS(N(R4(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytget_automatic_helpersscCs|tjkr:ttjd|djtjfn||jkr||_|jj d||jj |j nttj |dS(Ns'%s', choose from '%s's','RL( RtAUTOMATIC_HELPERS_VALUESRRRRRR4RRRR~R(R'R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytset_automatic_helperss    cCs|jS(N(R,(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyRscCs`|j|}||jkrJ||_|jjd||jjnttj|dS(NR@(R}R,RRRRRtZONE_ALREADY_SET(R'R!R((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytset_default_zones  cCs$|jjdd|jjdS(NRERF(RRR(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR\(scCs$|jjdd|jjdS(NRERC(RRR(R'((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pytdisable_lockdown,s("t__name__t __module__R(R5R&R?RRRRfRRRR}RRRRRRRR~RRRRRRRRRRR\R(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyR7s>                        (0t__all__tos.pathRyRvR_tfirewallRRtfirewall.core.fw_icmptypeRtfirewall.core.fw_serviceRtfirewall.core.fw_zoneRtfirewall.core.fw_directRtfirewall.core.fw_configRtfirewall.core.fw_policiesRtfirewall.core.fw_ipsetR tfirewall.core.fw_helperR tfirewall.core.loggerR tfirewall.core.io.firewalld_confR tfirewall.core.io.directR tfirewall.core.io.serviceRtfirewall.core.io.icmptypeRtfirewall.core.io.zoneRRtfirewall.core.io.ipsetRtfirewall.core.ipsetRtfirewall.core.io.helperRRtfirewall.errorsRtobjectR(((s9/usr/lib/python2.7/site-packages/firewall/core/fw_test.pyts2    PK!gg fw_service.pynu[# -*- 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__ = [ "FirewallService" ] from firewall import errors from firewall.errors import FirewallError class FirewallService(object): def __init__(self, fw): self._fw = fw self._services = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._services) def cleanup(self): self._services.clear() # zones def get_services(self): return sorted(self._services.keys()) def check_service(self, service): if service not in self._services: raise FirewallError(errors.INVALID_SERVICE, service) def get_service(self, service): self.check_service(service) return self._services[service] def add_service(self, obj): self._services[obj.name] = obj def remove_service(self, service): self.check_service(service) del self._services[service] PK!99 io/direct.pyonu[ c`c@s ddljZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZddlmZddlmZdd lmZdd lmZd efd YZd efdYZdS(iN(tconfig(tLastUpdatedOrderedDict(t splitArgstjoinArgst u2b_if_py2(t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(tlog(t ipXtables(tebtables(terrors(t FirewallErrortdirect_ContentHandlercBs#eZdZdZdZRS(cCstj||t|_dS(N(Rt__init__tFalsetdirect(tselftitem((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR(scCstj||||jj|||dkr\|jrPttjdnt|_n|dkr|jst j ddS|d}|d}|d}|jj t |t |t |n+|dkr|jst j ddS|d}|dkr ttj d |n|d}|d}yt|d }Wn'tk rqt j d|d dSXt |t |t ||g|_nZ|dkr|jst j ddS|d}t |g|_nt j d|dSdS(NRsMore than one direct tag.tchains$Parse Error: chain outside of directtipvttabletrules#Parse Error: rule outside of directtipv4tipv6tebs"'%s' not from {'ipv4'|'ipv6'|'eb'}tprioritys'Parse Error: %s is not a valid priorityt passthroughs&Parse Error: command outside of directsUnknown XML element %s(RRR(Rt startElementRtparser_check_element_attrsRR R t PARSE_ERRORtTrueRterrort add_chainRt INVALID_IPVtintt ValueErrort_rulet _passthrough(RtnametattrsRRRR((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR,sT                          cCstj|||dkr|jrm|jjgt|jD]}t|^q>|jj|jn t j dd|_nz|dkr|jr|j jgt|jD]}t|^q|jj |j nt j ddd|_ ndS(NRs2Error: rule does not have any arguments, ignoring.Rs0Error: passthrough does not have any arguments, s ignoring.(Rt endElementt_elementR%tappendRRRtadd_ruleRR tNoneR&tadd_passthrough(RR'tx((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR)^s    &     & (t__name__t __module__RRR)(((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR 's  2tDirectcBseZdZdd(gfddddddgfgfdddgfgffZdZid)d6dd d gd 6dd d d gd 6dgd 6ZiZdZdZ dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZdZdZd Zd!Zd"Zd#Zd$Zd%Zd&Z d'Z!RS(*s Direct class tchainsttrulesit passthroughss(a(sss)a(sssias)a(sas))RRRRRRRcCsDtt|j||_t|_t|_t|_dS(N(tsuperR2RtfilenameRR3R5R6(RR8((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyRs    cCsdS(N((RtconfR((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt _check_configsc CsNg}g}xO|jD]D}x;|j|D],}|jtt|t|gq*WqW|j|g}xe|jD]Z}xQ|j|D]B}|jt|d|d|d|dt|dfqWq{W|j|g}xH|jD]=}x4|j|D]%}|jt|t|fq WqW|j|t|S(Niii(R3R+ttupletlistR5R6(RtretR/tkeyRR((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt export_configs$. % ' cCs|j|j|xt|jD]\}\}}|dkrjx"||D]}|j|qPWn|dkrx"||D]}|j|qWn|dkr'x"||D]}|j|qWq'q'WdS(NR3R5R6(tcleanupt check_configt enumeratetIMPORT_EXPORT_STRUCTURER!R,R.(RR9titelementtdummyR/((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt import_configs  "   cCs+|jj|jj|jjdS(N(R3tclearR5R6(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR@s  cCsdGHx;|jD]0}d|d|ddj|j|fGHqWdGHxe|jD]Z}d|d|d|dfGHx3|j|D]$\}}d |d j|fGHqWqRWd GHxD|jD]9}d |GHx'|j|D]}d d j|GHqWqWdS(NR3s (%s, %s): %siit,R5s (%s, %s, %s):is (%d, ('%s'))s','R6s %s:s ('%s')(R3tjoinR5R6(RR>Rtargs((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pytoutputs  cCs>dddg}||kr:ttjd||fndS(NRRRs'%s' not in '%s'(R R R"(RRtipvs((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt _check_ipvs  cCsf|j||dkr(tjjn tjj}||krbttjd||fndS(NRRs'%s' not in '%s'(sipv4sipv6(RNR tBUILT_IN_CHAINStkeysR R R t INVALID_TABLE(RRRttables((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt_check_ipv_tables    cCs|j||||f}||jkr;g|j|((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR!s  cCs|j||||f}||jkr{||j|kr{|j|j|t|j|dkr|j|=qntd|||fdS(Nis4Chain '%s' with table '%s' with ipv '%s' not in list(RSR3tremovetlenR$(RRRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt remove_chains "cCs<|j||||f}||jko;||j|kS(N(RSR3(RRRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt query_chains cCsP|j||||f}||jkr6|j|Std||fdS(Ns&No chains for table '%s' with ipv '%s'(RSR3R$(RRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt get_chainss   cCs|jS(N(R3(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pytget_all_chainsscCs|j|||||f}||jkrAt|j|tvalue((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR,s'cCs|j|||||f}|t|f}||jkr||j|kr|j||=t|j|dkr|j|=qn0tddj|||fd||fdS(Nis(Rule '%s' for table '%s' and chain '%s' s',s)with ipv '%s' and priority %d not in list(RSR;R5RVR$RJ(RRRRRRKR>R[((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt remove_rules"cCs|j|||||f}||jkrx)|j|jD]}|j||=qBWt|j|dkr|j|=qndS(Ni(RSR5RPRV(RRRRR>R[((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt remove_rules"scCsQ|j|||||f}|t|f}||jkoP||j|kS(N(RSR;R5(RRRRRRKR>R[((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt query_rule+scCs[|j|||||f}||jkr9|j|Std||fd|dS(Ns'No rules for table '%s' and chain '%s' s with ipv '%s'(RSR5R$(RRRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt get_rules1s  cCs|jS(N(R5(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt get_all_rules:scCs~|j|||jkr,g|j|RRRRRK((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pytwriteusZ               (R4R4R4N("R0R1t__doc__RCtDBUS_SIGNATURER-tPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRR:R?RGR@RLRNRSR!RWRXRYRZR,R\R]R^R_R`R.RaRbRcRdRwR(((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR2usJ                  (txml.saxRhR{RR~tfirewallRtfirewall.fw_typesRtfirewall.functionsRRRtfirewall.core.io.io_objectRRRtfirewall.core.loggerRt firewall.coreR R R tfirewall.errorsR R R2(((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyts   NPK!m io/ifcfg.pynu[# -*- 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) PK!,:<<io/__init__.pynu[# -*- 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) PK!Bq^^ io/zone.pyonu[ c`c@sjdddgZddljZddlZddlZddlZddlmZddlm Z m Z m Z m Z m Z mZmZmZmZmZddlmZmZddlmZmZmZmZmZmZmZdd lmZdd l m!Z!dd lm"Z"dd l#m$Z$defd YZ%defdYZ&e'dZ(e)dZ*dS(tZonet zone_readert zone_writeriN(tconfig( tcheckIPtcheckIP6t checkIPnMaskt checkIP6nMasktcheckInterfacetuniqifytmax_zone_name_lent u2b_if_py2t check_mactportStr(tDEFAULT_ZONE_TARGETt ZONE_TARGETS(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudptcheck_protocol(trich(tlog(terrors(t FirewallErrorcBsEeZdZdAdBdCdefdDddgfddEgfd dgfd efd dFgfd dgfd dgfddgfddgfddGgfdeffZdZdddgZidHd6dHd6dHd6dgd6ddgd6dgd6dgd6ddgd6dgd6dHd6dHd 6d!gd"6d#gd6ddgd$6dHd%6dHd&6dHd'6dHd(6dHd)6d*gd+6d#gd,6dHd-6Zidd.ddgd6d/gd 6d0d1gd6d2gd6d!d3d4d2d5gd 6d4gd"6d6d7gd%6d8gd(6Z e d9Z d:Z d;Z d<Zd=Zd>Zd?Zd@ZRS(Is Zone class tversionttshortt descriptiontUNUSEDttargettservicestportst icmp_blockst masqueradet forward_portst interfacestsourcest rules_strt protocolst source_portsticmp_block_inversions&(sssbsasa(ss)asba(ssss)asasasasa(ss)b)t_t-t/tzonetnametservicetporttprotocols icmp-blocks icmp-types forward-portt interfacetruletsourcetaddresst destinationtvalues source-portRtaudittaccepttrejecttdroptsettmarktlimitsicmp-block-inversiont immutabletenabledsto-portsto-addrtfamilytmactinverttipsettprefixtlevelttypecCsLx3ttjD]"\}\}}||kr|SqWttjddS(Ns index_of()(t enumerateRtIMPORT_EXPORT_STRUCTURERRt UNKNOWN_ERROR(telementtiteltdummy((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytindex_ofbs" cCstt|jd|_d|_d|_t|_t|_ g|_ g|_ g|_ g|_ t|_g|_g|_g|_g|_d|_g|_g|_t|_t|_t|_dS(NR(tsuperRt__init__RRRtFalseRRR R!R"R)R#R$R%R*R&R'tNonet fw_configtrulesR(R+tcombinedtapplied(tself((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRSis*                   cCsd|_d|_d|_t|_t|_|j2|j2|j 2|j 2t|_ |j 2|j 2|j2|j2d|_|j2|j2t|_t|_t|_dS(NR(RRRRTRRR R!R"R)R#R$R%R*R&R'RURVRWR(R+RXRY(RZ((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytcleanups(         c Cs t|j|_t|j|_t|j|_t|j|_g|jD]}t|^qR|_g|jD]$\}}t|t|f^qw|_g|jD]}t|^q|_g|jD]}t|^q|_g|j D]<\}}}}t|t|t|t|f^q|_ g|j D]$\}}t|t|f^qG|_ g|j D]}t|^q~|_ g|j D]}t|^q|_ g|j D]}t|^q|_ g|jD]}t|^q|_dS(s 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.N(R RRRR R!R"R)R#R%R*R&R'RWR(( RZtstpotprRNtp1tp2tp3tp4((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytencode_stringss%7%%O4%%%cCs|dkrlg|D]}tjd|^q|_tt|j|g|jD]}t|^qPntt|j||dS(NR(trule_str(Rt Rich_RuleRWRRRt __setattr__tstr(RZR0R9R\((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRfs (8c Cs?|dkr]|jr]|jj}x|D]+}||kr+ttjd|q+q+Wn|dkrx|D]"}t|dt|dqpWn|dkrx|D]}t|qWnx|dkr |jr |jj}xQ|D]+}||krttj d|qqWn|d krx |D]} t| dt| d| d  r| d  rttj d | n| d rt| d n| d r3t | d  rt | d  rttj d | d qq3q3WnI|dkr.x:|D]"}t|dt|dqWn |dkr^|tkr;ttj|q;n|dkrx|D]'} t| sqttj| qqqqWn|dkr x|D]R} t|  rt|  rt|  r| jd rttj | qqWn0|dkr;x!|D]} tjd| qWndS(NR!s '%s' not among existing servicesR"iiR)R#s"'%s' not among existing icmp typesR%iis$'%s' is missing to-port AND to-addr s#to-addr '%s' is not a valid addressR*R R&R'sipset:R(Rd(RVt get_servicesRRtINVALID_SERVICERRRt get_icmptypestINVALID_ICMPTYPEtINVALID_FORWARDRRt INVALID_ADDRRtINVALID_TARGETRtINVALID_INTERFACERRR t startswithRRe( RZRtitemtexisting_servicesR1R2tprototexisting_icmptypesticmptypetfwd_portR4R6R5((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyt _check_configsn              "           cCstt|j||jdr>ttjd|n|jdrfttjd|n|jddkrttjd|nnd|kr||j d }n|}t |t krttjd|t |t |j fndS(NR.s'%s' can't start with '/'s'%s' can't end with '/'ismore than one '/' in '%s's'Zone of '%s' has %d chars, max is %d %s( RRRt check_nameRpRRt INVALID_NAMEtendswithtcounttfindtlenR RX(RZR0t checked_name((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRxs&      c CsEt|_d|_d|_d|_d|_x3|jD](}||jkr7|jj|q7q7Wx3|j D](}||j krm|j j|qmqmWx3|j D](}||j kr|j j|qqWx3|j D](}||j kr|j j|qqWx3|j D](}||j kr|j j|qqWx3|j D](}||j krE|j j|qEqEW|jrt|_nx3|jD](}||jkr|jj|qqWx3|jD](}||jkr|jj|qqWx7|jD],} |jj| |jjt| qW|jrAt|_ndS(NR(tTrueRXRUtfilenameRRRR&tappendR'R!R"R)R#R$R%R*RWR(RgR+( RZR/R4R6R1R2RsticmptforwardR5((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytcombinesH        (sversionR(sshortR(s descriptionR(stargetR(RR(RRRR(RRN(t__name__t __module__t__doc__RTRKtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARSRUtPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSt staticmethodRQRSR[RcRfRwRxR(((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyR(sv                                  9 tzone_ContentHandlercBs#eZdZdZdZRS(cCs/tj||d|_t|_d|_dS(N(RRSRUt_ruleRTt _rule_errort _limit_ok(RZRq((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRS,s  c Cswtj||||jr dS|jj|||dkrd|krbtjd|dnd|kr|d|j_nd|krtjd|dnd|krs|d}|tkrt t j |n|dkr|t kr||j_ qqsnk|d krn\|d kr&nM|d kr|jr|jjrmtjd t|jt|_dStj|d|j_dS|d|jjkr|jjj|dqstjd |dn |dkr|jr<|jjrtjd t|jt|_dStj|d|d|j_dSt|dt|dt|dd|df}||jjkr|jjj|qstjd|d|dn |dkrs|jr|jjrtjd t|jt|_dStj|d|j_qst|d|d|jjkr\|jjj|dqstjd|dn |dkr|jr|jjrtjd t|jt|_dStj|d|j_dS|d|jjkr|jjj|dqstjd|dnU |dkr|jr|jjretjd t|jt|_dStj |d|j_dStjd|dn |dkrZd|kr|dj!d`krtjd|ddS|jr/|jjrtjd t|jt|_dStj"|j_qs|jj#rKtjdqst|j_#n |dkrd}d|kr|d}nd}d |kr|d }n|jr |jjrtjd t|jt|_dStj$|d|d|||j_dSt|dt|d|r8t|n|rtt%| rtt&| rtt t j'd!|qtnt|dd|dt|dt|f}||jj(kr|jj(j|qstjd"|d|d|rd#|nd|rd$|ndna|d%kr|jr}|jjrYtjd t|jt|_dStj)|d|d|j_dSt|dt|dt|dd|df}||jj*kr|jj*j|qstjd&|d|dnw|d'kr|jr+tjd(t|_dSd|krQtjd)t|_dS|d|jj+kr|jj+j|dqstjd*|dn|d+kr, |jr |jj,rtjd,t|jt|_dSt-}d-|kr |d-j!dakr t}nd}} } d0|kr7 |d0}nd1|krP |d1} nd2|kri |d2} ntj/|| | d-||j_,dSd0|kr d2|kr tjd3dSd0|kr d2|kr tjd4dSd5|kr tjd6|d5nd-|kr tjd7dSd0|kr{ t0|d0 r{ t1|d0 r{ t2|d0 r{ t t j'|d0q{ nd2|kr d8|d2}||jj3kr |jj3j|q tjd9|d0nd0|krs|d0}||jj3kr |jj3j|q) tjd9|d0qsnG|d:kr |js[ tjd;t|_dS|jj4r tjd<t|jdSt-}d-|kr |d-j!dbkr t}ntj5|d0||j_4n|dckr |js tjdAt|_dS|jj6r) tjdBt|_dS|d=krJ tj7|j_6n|d>kr d} dC|kru |dC} ntj8| |j_6nO|d?kr tj9|j_6n.|d@kr |dD} tj:| |j_6n|jj6|_;n|dEkr |js tjdFdS|jjr1 tjdGdSd} dH|krv |dH} | ddkrv tjdQt|_dSndR|kr |dRnd}tj<|| |j_|jj|_;n|dSkr8|js tjdTdS|jj=rtjdUt|jt|_dStj>|j_=|jj=|_;n;|dVkrd}d5|kr|d5}|dekrtjdY|d5t|_dSntj?||_n|dZkr(|j;stjd[t|_dS|j;j@rtjd\t|jt|_dS|d}tjA||j;_@nK|d]kr_|jjBrPtjd^qst|j_Bntjd_|dSdS(fNR/R0s'Ignoring deprecated attribute name='%s'RRAs,Ignoring deprecated attribute immutable='%s'R RRRR1s;Invalid rule: More than one element in rule '%s', ignoring.s#Service '%s' already set, ignoring.R2R3R-s#Port '%s/%s' already set, ignoring.R9s$Protocol '%s' already set, ignoring.s icmp-blocks&icmp-block '%s' already set, ignoring.s icmp-types-Invalid rule: icmp-block '%s' outside of ruleR$RBtnotfalses*Ignoring deprecated attribute enabled='%s's!Masquerade already set, ignoring.s forward-portsto-portsto-addrs#to-addr '%s' is not a valid addresss-Forward port %s/%s%s%s already set, ignoring.s >%ss @%ss source-ports*Source port '%s/%s' already set, ignoring.R4s$Invalid rule: interface use in rule.s Invalid interface: Name missing.s%Interface '%s' already set, ignoring.R6s:Invalid rule: More than one source in rule '%s', ignoring.REtyesttrueR7RDRFs$Invalid source: No address no ipset.s"Invalid source: Address and ipset.RCs)Ignoring deprecated attribute family='%s's+Invalid source: Invertion not allowed here.sipset:%ss"Source '%s' already set, ignoring.R8s)Invalid rule: Destination outside of rules?Invalid rule: More than one destination in rule '%s', ignoring.R;R<R=R?s$Invalid rule: Action outside of rules"Invalid rule: More than one actionRIR>Rs!Invalid rule: Log outside of rulesInvalid rule: More than one logRHtemergtalerttcritterrortwarningtnoticetinfotdebugsInvalid rule: Invalid log levelRGR:s#Invalid rule: Audit outside of rules9Invalid rule: More than one audit in rule '%s', ignoring.R5tipv4tipv6s&Invalid rule: Rule family "%s" invalidR@s4Invalid rule: Limit outside of action, log and audits9Invalid rule: More than one limit in rule '%s', ignoring.sicmp-block-inversions+Icmp-Block-Inversion already set, ignoring.sUnknown XML element '%s'(RR(syesR(syesR(sacceptsrejectsdropsmark(RRRserrorswarningRsinfosdebug(RR(CRt startElementRRqtparser_check_element_attrsRRRRRRRnRR RRMRgRRt Rich_ServiceR!Rt Rich_PortRRR R"t Rich_ProtocolRR)tRich_IcmpBlockR#t Rich_IcmpTypetlowertRich_MasqueradeR$tRich_ForwardPortRRRmR%tRich_SourcePortR*R&R6RTRUt Rich_SourceRRR R'R8tRich_Destinationtactiont Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_MarkRtRich_LogR:t Rich_AuditReR@t Rich_LimitR+(RZR0tattrsR tentrytto_porttto_addrREtaddrRDRFt_typet_setRHRGRCR9((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyR2st                                                                                                                                                                 cCstj|||dkr|jsy|jjWn/tk rg}tjd|t|jqXt|j|j j kr|j j j |j|j j j t|jqtjdt|jnd|_t|_n|d krd|_ndS( NR5s%s: %ss Rule '%s' already set, ignoring.R;R<R=R?RR:(sacceptsrejectsdropsmarkslogsaudit(Rt endElementRRtcheckt ExceptionRRRgRqR(RWRRURTR(RZR0te((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRs        (RRRSRR(((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyR+s  dc Csbt}|jds1ttjd|n|d |_|sW|j|jn||_||_|j t j rt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r>} ttjd| jnXWdQX~~tr^|jn|S(Ns.xmls'%s' is missing .xml suffixis%s/%strbsnot a valid zone file: %s(RRzRRRyR0RxRtpathRpRt ETC_FIREWALLDRTRtbuiltintdefaultRtsaxt make_parsertsetContentHandlertopent InputSourceRUt setByteStreamtparsetSAXParseExceptiont INVALID_ZONEt getExceptionRRc( RRt no_check_nameR/thandlertparserR0tfR6tmsg((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRs:     !       c Cs% |r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|jrq|jd krq|j|d d kr{ |j0j>|d%t1|jG|jGjEr |jd-|j|||jd4|jd5i|jGjEj8d6|jd6|j|n|jd-|j|||jdn|jd|jd)|jdqW|jd |jd|jN|jO~dS(?Ns%s/%ss %s/%s.xmls%s.oldsBackup of file '%s' failed: %sitmodetwttencodingsUTF-8RRR R/s s RRR4R0sipset:R6iRFR7R1R2iiR3R9sicmp-block-inversions icmp-blockR$isto-portisto-addrs forward-ports source-portRCR5RDRREs R8s icmp-types#Unknown element '%s' in zone_writerRGRHRs R@s R:R;R<RIR=R?R>sUnknown action '%s'(PRRR0tostexiststshutiltcopy2RRRtdirnameRpRRtmkdirtioRRt startDocumentRR RRtignorableWhitespaceRt charactersRRR R&t simpleElementR'R!R"R)R+R#R$R%R*RWRCR6RRDRFRER8RMRIRRRR2R3RR9RRRRRt to_addressRRRtINVALID_OBJECTRGRHR@R:RRRRRR>Rt endDocumenttclose(R/Rt_pathR0RtdirpathRRRR4R6R1R2R3RRR5RMR((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRs %            &                                                         (+t__all__txml.saxRRRRtfirewallRtfirewall.functionsRRRRRR R R R R tfirewall.core.baseRRtfirewall.core.io.io_objectRRRRRRRt firewall.coreRtfirewall.core.loggerRRtfirewall.errorsRRRRTRRUR(((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyts$   F4 PK!!  io/helper.pycnu[ c`c@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZdd lmZdd lmZde fd YZd e fd YZdZddZdS(tHelpert helper_readert helper_writeriN(tconfig(t u2b_if_py2(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudp(tlog(terrors(t FirewallErrorcBseZdddddddgffZdZdd gZidd6dd6dgd 6Zid ddgd 6d d gd 6ZdZdZ dZ dZ dZ RS(tversionttshortt descriptiontfamilytmoduletportss (sssssa(ss))t-t.thelpertnametporttprotocolcCsMtt|jd|_d|_d|_d|_d|_g|_dS(NR( tsuperRt__init__RRRRRR(tself((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR;s     cCs8d|_d|_d|_d|_d|_|j2dS(NR(RRRRRR(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pytcleanupDs      cCst|j|_t|j|_t|j|_t|j|_t|j|_g|jD]$\}}t|t|f^qd|_dS(s 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.N(RRRRRRR(Rtpotpr((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pytencode_stringsLs cCs;ddg}||kr7ttjd||fndS(Ntipv4tipv6s'%s' not in '%s'(R R t INVALID_IPV(Rtipvtipvs((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyt check_ipvWs   cCs|dkr<x|D]"}t|dt|dqWnn|dkr|jdspttjd|nt|jdddkrttjd|qndS( NRiiRt nf_conntrack_s('%s' does not start with 'nf_conntrack_'RsModule name '%s' too short(R R t startswithR R tINVALID_MODULEtlentreplace(RRtitemR((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyt _check_config]s    (sversionR(sshortR(s descriptionR(sfamilyR(smoduleR(RRN( t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRRR!R'R.(((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR&s(    thelper_ContentHandlercBseZdZRS(cCstj||||jj|||dkrd|krQ|d|j_nd|kr|jj|d|d|j_nd|kr|djdstt j d|dnt |dj dddkrtt j d |dn|d|j_ qn|d kr$n|d kr3n|d krt|d t|d |d |d f}||jjkr|jjj|qtjd|d |d ndS(NRRRRR(s('%s' does not start with 'nf_conntrack_'RisModule name '%s' too shortRRRRs#Port '%s/%s' already set, ignoring.(Rt startElementR-tparser_check_element_attrsRR'RR)R R R*R+R,RR R RtappendR twarning(RRtattrstentry((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR8ns>    "    (R/R0R8(((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR7msc CsYt}|jds1ttjd|n|d |_|j|j||_||_|j t j rxt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r5}ttjd|jnXWdQX~~trU|jn|S(Ns.xmls'%s' is missing .xml suffixis%s/%strbsnot a valid helper file: %s(RtendswithR R t INVALID_NAMERt check_nametfilenametpathR)Rt ETC_FIREWALLDtFalsetTruetbuiltintdefaultR7tsaxt make_parsertsetContentHandlertopent InputSourceR4t setByteStreamtparsetSAXParseExceptiontINVALID_HELPERt getExceptionRR!( RBRCRthandlertparserRtftsourcetmsg((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyRs8     !       c Cs|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|j|d <|jr~|jd kr~|j|d s   .G# PK!oyr66 io/ipset.pyonu[ c`c@sgdZdddgZddljZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZdd lmZmZdd lmZmZmZmZdd l m!Z!dd lm"Z"dd l#m$Z$defdYZ%defdYZ&dZ'e(dZ)dS(s$ipset io XML handler, reader, writertIPSett ipset_readert ipset_writeriN(tconfig( tcheckIPtcheckIP6t checkIPnMaskt checkIP6nMaskt u2b_if_py2t check_mact check_porttcheckInterfacet checkProtocol(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(t IPSET_TYPEStIPSET_CREATE_OPTIONS(tcheck_icmp_nametcheck_icmp_typetcheck_icmpv6_nametcheck_icmpv6_type(tlog(terrors(t FirewallErrorcBseZdddddidd6fddgffZdZdd d d gZidd6dd6dgd 6d gd6dd6Zidgd 6dgd6ZdZdZ dZ e dZ dZ dZRS(tversionttshortt descriptionttypetoptionstentriess (ssssa{ss}as)t_t-t:t.tipsettnametoptiontentrytvaluecCsVtt|jd|_d|_d|_d|_g|_i|_t |_ dS(NR( tsuperRt__init__RRRRR RtFalsetapplied(tself((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyR+Cs      cCsEd|_d|_d|_d|_|j2|jjt|_dS(NR( RRRRR RtclearR,R-(R.((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pytcleanupMs     cCst|j|_t|j|_t|j|_t|j|_d|jjD|_g|jD]}t|^qn|_dS(s 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+i|]!\}}t|t|qS((R(t.0tktv((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pys ^s N(RRRRRRtitemsR (R.te((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pytencode_stringsVsc Csd}d|kr.|ddkr.d}q.n|jdsVttjd|n|djd}|jd}t|t|kst|d krttjd ||fnx'tt|D]}||}||}|d krd |kr|dkr|d kr@ttjd |||fn|jd } t| dkrttjd||||fnx| D]]} |dkrt|  s|dkrt |  rttjd| |||fqqWq|dkrL|dkr.ttjd||||fn|dkrCt } qRt} nt } | |sttjd||||fqq|dkrbd |kr|jd } t| dkrttjd||||fn|dkrt| d s|dkrGt | d rGttjd| d|||fn|dkrdt | d  s|dkr_t | d  r_ttjd| d |||fq_q|j dr|dko|dko|dksttjd||||fqn|dkr!t | s:|dkrt | rttjd||||fqq|dkrt | s|dkrttjd||fqq|dkrd|kr{|jd} t| dkrttjd|n| ddkr~|dkr6ttjd||fnt| d  rxt| d  rxttjd| d |fqxq| dd1kr|dkrttjd||fnt| d  rxt| d  rxttjd!| d |fqxq| dd2krEt| d rEttjd&| d|fqt| d sttjd'| d |fqqt|sttjd(||fqq|d)kr|jd*r yt|d+} WqJtk rttjd,||fqJXn@yt|} Wn-tk rIttjd,||fnX| dksb| d-krttjd,||fqq|d.krt| st|d/krttjd0||fqqttjd|qWdS(3Ntipv4tfamilytinet6tipv6shash:sipset type '%s' not usableit,is)entry '%s' does not match ipset type '%s'tipR"s invalid address '%s' in '%s'[%d]is.invalid address range '%s' in '%s' for %s (%s)s(invalid address '%s' in '%s' for %s (%s)s0.0.0.0itnets/0shash:net,ifacetmacs00:00:00:00:00:00s invalid mac address '%s' in '%s'tportR#sinvalid port '%s'ticmps(invalid protocol for family '%s' in '%s'sinvalid icmp type '%s' in '%s'ticmpv6s ipv6-icmps invalid icmpv6 type '%s' in '%s'ttcptsctptudptudplitesinvalid protocol '%s' in '%s'sinvalid port '%s'in '%s'sinvalid port '%s' in '%s'tmarkt0xisinvalid mark '%s' in '%s'Itifaceisinvalid interface '%s' in '%s'(RAs ipv6-icmp(RBRCRDRE(t startswithRRt INVALID_IPSETtsplittlent INVALID_ENTRYtrangeRRRRtendswithR RRRRR R tintt ValueErrorR ( R(Rt ipset_typeR8tflagsR4titflagtitemtsplitst_splittip_checktint_val((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyt check_entrybs@   *                            cCs>|dkr4|tkr4ttjd|q4n|dkr:x|jD]}|tkrxttjd|n|dkryt||}Wn1tk rttj d|||fnX|d kr3ttj d |||fq3qM|d krM||dkrMttj ||qMqMWndS(NRs'%s' is not valid ipset typeRsipset invalid option '%s'ttimeoutthashsizetmaxelems)Option '%s': Value '%s' is not an integeris#Option '%s': Value '%s' is negativeR8tinetR9(R\R]R^(R_sinet6( RRRt INVALID_TYPEtkeysRRJRPRQt INVALID_VALUEtINVALID_FAMILY(R.RRVtkeyt int_value((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyt _check_configs2          cCsd|dkrO|dddkrOt|ddkrOttjqOnx-|dD]!}tj||d|dqZWtt|j|dS(NR\it0iii(RLRRtIPSET_WITH_TIMEOUTRR[R*t import_config(R.RR(((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRi3s $(sversionR(sshortR(s descriptionR(stypeRN(t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSR+R0R6t staticmethodR[RfRi(((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyR,s.       tipset_ContentHandlercBseZdZdZRS(cCstj||||jj|||dkrd|kr~|dtkrkttjd|dn|d|j_nd|kr|d|j_ qn|dkrn|dkrn|dkrd}d |kr|d }n|d dkrttj d|d n|jjdkra|d dkrattj d|d |jjfn|d dkr| rttj d|d n|d dkryt |}Wn1t k rttj d|d |fnX|dkrttj d|d |fqn|d d krL|dkrLttj|n|d |jjkry||jj|d sd         "  cCs9tj|||dkr5|jjj|jndS(NR((Rt endElementRVR tappendt_element(R.R&((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRyus (RjRkRtRy(((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRs=s 7c Cst}|jds1ttjd|n|d |_|j|j||_||_|j t j rxt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r5}ttjd|jnXWdQX~~d|jkr|jddkrt|jd krtj d |j|j2nd } t!} x| t|jkru|j| | krtj d |j| |jj"| qy$|j#|j| |j|j$Wn3tk rS} tj d | |jj"| qX| j%|j| | d 7} qW~ t&r|j'n|S(Ns.xmls'%s' is missing .xml suffixis%s/%strbsnot a valid ipset file: %sR\Rgis6ipset '%s': timeout option is set, entries are ignoredsEntry %s already set, ignoring.s %s, ignoring.i((RRORRt INVALID_NAMER&t check_nametfilenametpathRIRt ETC_FIREWALLDR,tTruetbuiltintdefaultRstsaxt make_parsertsetContentHandlertopent InputSourceRot setByteStreamtparsetSAXParseExceptionRJt getExceptionRRLR RRwtsettpopR[RtaddR R6( RRR%thandlertparserR&tftsourcetmsgRTt entries_setR5((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRzs^     !      "    $ c Csg|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji|jd 6}|jr{|jd kr{|j|d s$   @""= 5PK!) io/functions.pycnu[ c`c@sddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd ZdS( iN(tconfig(t FirewallError(t zone_reader(tservice_reader(t ipset_reader(ticmptype_reader(t helper_reader(tDirect(tLockdownWhitelist(tfirewalld_confcCsittjtjgfd6ttjtjgfd6ttjtj gfd6t tj tj gfd6t tjtjgfd6}x#|jD]}x ||dD]}tjj|sqnxttj|D]}|jdryO||d||}|r)|dkr)|j|_n|j|jWqtk rq}t|jd ||jfqtk r}td ||fqXqqWqWqWtjjtjrTy0t tj}|j!|j|jWqTtk r%}t|jd tj|jfqTtk rP}td tj|fqTXntjjtj"ry0t#tj"}|j!|j|jWqtk r}t|jd tj"|jfqtk r}td tj"|fqXntjjtj$ryt%tj$}|j!Wqtk rh}t|jd tj$|jfqtk r}td tj$|fqXndS( Ntipsetthelperticmptypetservicetzoneis.xmlis'%s': %s(&RRtFIREWALLD_IPSETStETC_FIREWALLD_IPSETSRtFIREWALLD_HELPERStETC_FIREWALLD_HELPERSRtFIREWALLD_ICMPTYPEStETC_FIREWALLD_ICMPTYPESRtFIREWALLD_SERVICEStETC_FIREWALLD_SERVICESRtFIREWALLD_ZONEStETC_FIREWALLD_ZONEStkeystostpathtisdirtsortedtlistdirtendswitht fw_configt check_configt export_configRtcodetmsgt ExceptiontisfiletFIREWALLD_DIRECTRtreadtLOCKDOWN_WHITELISTRtFIREWALLD_CONFR (tfwtreaderstreadertdirtfiletobjterrorR$((s>/usr/lib/python2.7/site-packages/firewall/core/io/functions.pyR!$s^") %  % %(RtfirewallRtfirewall.errorsRtfirewall.core.io.zoneRtfirewall.core.io.serviceRtfirewall.core.io.ipsetRtfirewall.core.io.icmptypeRtfirewall.core.io.helperRtfirewall.core.io.directRt#firewall.core.io.lockdown_whitelistRtfirewall.core.io.firewalld_confR tNoneR!(((s>/usr/lib/python2.7/site-packages/firewall/core/io/functions.pyts PK!@>>io/firewalld_conf.pycnu[ c`c @sddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddddd d d d d g Z defdYZdS(iN(tconfig(tlog(tb2utu2btPY2t DefaultZonet MinimalMarkt CleanupOnExittLockdownt IPv6_rpfiltertIndividualCallst LogDeniedtAutomaticHelperstAllowZoneDriftingtfirewalld_confcBsPeZdZdZdZdZdZdZdZdZ RS(cCs)i|_g|_||_|jdS(N(t_configt_deletedtfilenametclear(tselfR((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyt__init__$s   cCsi|_g|_dS(N(RR(R((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyR*s cCs|jjg|_dS(N(RRR(R((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pytcleanup.s cCs|jj|jS(N(Rtgettstrip(Rtkey((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyR2scCsQt|j}t|j|j|<||jkrM|jj|ndS(N(RRRRtremove(RRtvaluet_key((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pytset5scCsad}xD|jjD]3\}}|r5|d7}n|d||f7}qWtr]t|S|S(Nts s%s=%s(RtitemsRR(RtsRR((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyt__str__;s  c Cs|jyt|jd}Wntk r;}tjd|j||jdtj|jdt tj |jdtj rdnd|jdtj rdnd|jd tj rdnd|jd tjrdnd|jd tj|jd tj|jd tjr.dndnXxG|D]?}|sSPn|j}t|dksC|dd$krqCng|jdD]}|j^q}t|dkrtjd|jqCn|dtkr tjd|jqCnd|ddkr5tjd|jqCn8|jj|ddk rmtjd|jqCn|d|j|ds       PK!H˨io/functions.pynu[# -*- 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.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.direct import Direct from firewall.core.io.lockdown_whitelist import LockdownWhitelist from firewall.core.io.firewalld_conf import firewalld_conf def check_config(fw=None): readers = { "ipset" : (ipset_reader, [config.FIREWALLD_IPSETS, config.ETC_FIREWALLD_IPSETS]), "helper" : (helper_reader, [config.FIREWALLD_HELPERS, config.ETC_FIREWALLD_HELPERS]), "icmptype" : (icmptype_reader, [config.FIREWALLD_ICMPTYPES, config.ETC_FIREWALLD_ICMPTYPES]), "service" : (service_reader, [config.FIREWALLD_SERVICES, config.ETC_FIREWALLD_SERVICES]), "zone" : (zone_reader, [config.FIREWALLD_ZONES, config.ETC_FIREWALLD_ZONES]), } for reader in readers.keys(): for dir in readers[reader][1]: if not os.path.isdir(dir): continue for file in sorted(os.listdir(dir)): if file.endswith(".xml"): try: obj = readers[reader][0](file, dir) if fw and reader == "zone": obj.fw_config = fw.config obj.check_config(obj.export_config()) 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)) PK!%yUUio/icmptype.pyonu[ c`c@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlmZdd lmZdd lmZde fd YZd e fd YZdZddZdS(tIcmpTypeticmptype_readerticmptype_writeriN(tconfig(t u2b_if_py2(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(tlog(terrors(t FirewallErrorcBseZdddddgffZdZddgZidd6dd6dd6Zid dgd6d d gd6Zd Zd Z dZ dZ RS(tversionttshortt descriptiont destinations(sssas)t_t-ticmptypetnametipv4tipv6cCs;tt|jd|_d|_d|_g|_dS(NR (tsuperRt__init__R RRR(tself((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR8s    cCs&d|_d|_d|_|j2dS(NR (R RRR(R((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pytcleanup?s   cCs_t|j|_t|j|_t|j|_g|jD]}t|^q@|_dS(s 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.N(RR RRR(Rtm((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pytencode_stringsEscCsI|dkrEx6|D]+}|dkrttjd|qqWndS(NRRRs'%s' not from {'ipv4'|'ipv6'}(RR(R R tINVALID_DESTINATION(RRtitemR((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyt _check_configNs     (sversionR (sshortR (s descriptionR N( t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRRRR(((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR%s"      ticmptype_ContentHandlercBseZdZRS(cCstj||||jj|||dkrxd|krVtjd|dnd|kr|d|j_qn|dkrns|dkrnd|dkrxUdd gD]D}||kr||jd kr|jjj t |qqWndS( NRRs'Ignoring deprecated attribute name='%s'R RRRRRtyesttrue(syesR*( Rt startElementRtparser_check_element_attrsR twarningR tlowerRtappendtstr(RRtattrstx((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR+Ys"        (R R!R+(((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR(Xsc CsYt}|jds1ttjd|n|d |_|j|j||_||_|j t j rxt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r5}ttjd|jnXWdQX~~trU|jn|S(Ns.xmls%s is missing .xml suffixis%s/%strbsnot a valid icmptype file: %s(RtendswithR R t INVALID_NAMERt check_nametfilenametpatht startswithRt ETC_FIREWALLDtFalsetTruetbuiltintdefaultR(tsaxt make_parsertsetContentHandlertopent InputSourceR%t setByteStreamtparsetSAXParseExceptiontINVALID_ICMPTYPEt getExceptionRR( R7R8RthandlertparserRtftsourcetmsg((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyRms8     !       c Cs|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|jrq|jd krq|j|d s   "3 PK!Bq^^ io/zone.pycnu[ c`c@sjdddgZddljZddlZddlZddlZddlmZddlm Z m Z m Z m Z m Z mZmZmZmZmZddlmZmZddlmZmZmZmZmZmZmZdd lmZdd l m!Z!dd lm"Z"dd l#m$Z$defd YZ%defdYZ&e'dZ(e)dZ*dS(tZonet zone_readert zone_writeriN(tconfig( tcheckIPtcheckIP6t checkIPnMaskt checkIP6nMasktcheckInterfacetuniqifytmax_zone_name_lent u2b_if_py2t check_mactportStr(tDEFAULT_ZONE_TARGETt ZONE_TARGETS(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudptcheck_protocol(trich(tlog(terrors(t FirewallErrorcBsEeZdZdAdBdCdefdDddgfddEgfd dgfd efd dFgfd dgfd dgfddgfddgfddGgfdeffZdZdddgZidHd6dHd6dHd6dgd6ddgd6dgd6dgd6ddgd6dgd6dHd6dHd 6d!gd"6d#gd6ddgd$6dHd%6dHd&6dHd'6dHd(6dHd)6d*gd+6d#gd,6dHd-6Zidd.ddgd6d/gd 6d0d1gd6d2gd6d!d3d4d2d5gd 6d4gd"6d6d7gd%6d8gd(6Z e d9Z d:Z d;Z d<Zd=Zd>Zd?Zd@ZRS(Is Zone class tversionttshortt descriptiontUNUSEDttargettservicestportst icmp_blockst masqueradet forward_portst interfacestsourcest rules_strt protocolst source_portsticmp_block_inversions&(sssbsasa(ss)asba(ssss)asasasasa(ss)b)t_t-t/tzonetnametservicetporttprotocols icmp-blocks icmp-types forward-portt interfacetruletsourcetaddresst destinationtvalues source-portRtaudittaccepttrejecttdroptsettmarktlimitsicmp-block-inversiont immutabletenabledsto-portsto-addrtfamilytmactinverttipsettprefixtlevelttypecCsLx3ttjD]"\}\}}||kr|SqWttjddS(Ns index_of()(t enumerateRtIMPORT_EXPORT_STRUCTURERRt UNKNOWN_ERROR(telementtiteltdummy((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytindex_ofbs" cCstt|jd|_d|_d|_t|_t|_ g|_ g|_ g|_ g|_ t|_g|_g|_g|_g|_d|_g|_g|_t|_t|_t|_dS(NR(tsuperRt__init__RRRtFalseRRR R!R"R)R#R$R%R*R&R'tNonet fw_configtrulesR(R+tcombinedtapplied(tself((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRSis*                   cCsd|_d|_d|_t|_t|_|j2|j2|j 2|j 2t|_ |j 2|j 2|j2|j2d|_|j2|j2t|_t|_t|_dS(NR(RRRRTRRR R!R"R)R#R$R%R*R&R'RURVRWR(R+RXRY(RZ((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytcleanups(         c Cs t|j|_t|j|_t|j|_t|j|_g|jD]}t|^qR|_g|jD]$\}}t|t|f^qw|_g|jD]}t|^q|_g|jD]}t|^q|_g|j D]<\}}}}t|t|t|t|f^q|_ g|j D]$\}}t|t|f^qG|_ g|j D]}t|^q~|_ g|j D]}t|^q|_ g|j D]}t|^q|_ g|jD]}t|^q|_dS(s 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.N(R RRRR R!R"R)R#R%R*R&R'RWR(( RZtstpotprRNtp1tp2tp3tp4((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytencode_stringss%7%%O4%%%cCs|dkrlg|D]}tjd|^q|_tt|j|g|jD]}t|^qPntt|j||dS(NR(trule_str(Rt Rich_RuleRWRRRt __setattr__tstr(RZR0R9R\((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRfs (8c Cs?|dkr]|jr]|jj}x|D]+}||kr+ttjd|q+q+Wn|dkrx|D]"}t|dt|dqpWn|dkrx|D]}t|qWnx|dkr |jr |jj}xQ|D]+}||krttj d|qqWn|d krx |D]} t| dt| d| d  r| d  rttj d | n| d rt| d n| d r3t | d  rt | d  rttj d | d qq3q3WnI|dkr.x:|D]"}t|dt|dqWn |dkr^|tkr;ttj|q;n|dkrx|D]'} t| sqttj| qqqqWn|dkr x|D]R} t|  rt|  rt|  r| jd rttj | qqWn0|dkr;x!|D]} tjd| qWndS(NR!s '%s' not among existing servicesR"iiR)R#s"'%s' not among existing icmp typesR%iis$'%s' is missing to-port AND to-addr s#to-addr '%s' is not a valid addressR*R R&R'sipset:R(Rd(RVt get_servicesRRtINVALID_SERVICERRRt get_icmptypestINVALID_ICMPTYPEtINVALID_FORWARDRRt INVALID_ADDRRtINVALID_TARGETRtINVALID_INTERFACERRR t startswithRRe( RZRtitemtexisting_servicesR1R2tprototexisting_icmptypesticmptypetfwd_portR4R6R5((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyt _check_configsn              "           cCstt|j||jdr>ttjd|n|jdrfttjd|n|jddkrttjd|nnd|kr||j d }n|}t |t krttjd|t |t |j fndS(NR.s'%s' can't start with '/'s'%s' can't end with '/'ismore than one '/' in '%s's'Zone of '%s' has %d chars, max is %d %s( RRRt check_nameRpRRt INVALID_NAMEtendswithtcounttfindtlenR RX(RZR0t checked_name((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRxs&      c CsEt|_d|_d|_d|_d|_x3|jD](}||jkr7|jj|q7q7Wx3|j D](}||j krm|j j|qmqmWx3|j D](}||j kr|j j|qqWx3|j D](}||j kr|j j|qqWx3|j D](}||j kr|j j|qqWx3|j D](}||j krE|j j|qEqEW|jrt|_nx3|jD](}||jkr|jj|qqWx3|jD](}||jkr|jj|qqWx7|jD],} |jj| |jjt| qW|jrAt|_ndS(NR(tTrueRXRUtfilenameRRRR&tappendR'R!R"R)R#R$R%R*RWR(RgR+( RZR/R4R6R1R2RsticmptforwardR5((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pytcombinesH        (sversionR(sshortR(s descriptionR(stargetR(RR(RRRR(RRN(t__name__t __module__t__doc__RTRKtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARSRUtPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSt staticmethodRQRSR[RcRfRwRxR(((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyR(sv                                  9 tzone_ContentHandlercBs#eZdZdZdZRS(cCs/tj||d|_t|_d|_dS(N(RRSRUt_ruleRTt _rule_errort _limit_ok(RZRq((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRS,s  c Cswtj||||jr dS|jj|||dkrd|krbtjd|dnd|kr|d|j_nd|krtjd|dnd|krs|d}|tkrt t j |n|dkr|t kr||j_ qqsnk|d krn\|d kr&nM|d kr|jr|jjrmtjd t|jt|_dStj|d|j_dS|d|jjkr|jjj|dqstjd |dn |dkr|jr<|jjrtjd t|jt|_dStj|d|d|j_dSt|dt|dt|dd|df}||jjkr|jjj|qstjd|d|dn |dkrs|jr|jjrtjd t|jt|_dStj|d|j_qst|d|d|jjkr\|jjj|dqstjd|dn |dkr|jr|jjrtjd t|jt|_dStj|d|j_dS|d|jjkr|jjj|dqstjd|dnU |dkr|jr|jjretjd t|jt|_dStj |d|j_dStjd|dn |dkrZd|kr|dj!d`krtjd|ddS|jr/|jjrtjd t|jt|_dStj"|j_qs|jj#rKtjdqst|j_#n |dkrd}d|kr|d}nd}d |kr|d }n|jr |jjrtjd t|jt|_dStj$|d|d|||j_dSt|dt|d|r8t|n|rtt%| rtt&| rtt t j'd!|qtnt|dd|dt|dt|f}||jj(kr|jj(j|qstjd"|d|d|rd#|nd|rd$|ndna|d%kr|jr}|jjrYtjd t|jt|_dStj)|d|d|j_dSt|dt|dt|dd|df}||jj*kr|jj*j|qstjd&|d|dnw|d'kr|jr+tjd(t|_dSd|krQtjd)t|_dS|d|jj+kr|jj+j|dqstjd*|dn|d+kr, |jr |jj,rtjd,t|jt|_dSt-}d-|kr |d-j!dakr t}nd}} } d0|kr7 |d0}nd1|krP |d1} nd2|kri |d2} ntj/|| | d-||j_,dSd0|kr d2|kr tjd3dSd0|kr d2|kr tjd4dSd5|kr tjd6|d5nd-|kr tjd7dSd0|kr{ t0|d0 r{ t1|d0 r{ t2|d0 r{ t t j'|d0q{ nd2|kr d8|d2}||jj3kr |jj3j|q tjd9|d0nd0|krs|d0}||jj3kr |jj3j|q) tjd9|d0qsnG|d:kr |js[ tjd;t|_dS|jj4r tjd<t|jdSt-}d-|kr |d-j!dbkr t}ntj5|d0||j_4n|dckr |js tjdAt|_dS|jj6r) tjdBt|_dS|d=krJ tj7|j_6n|d>kr d} dC|kru |dC} ntj8| |j_6nO|d?kr tj9|j_6n.|d@kr |dD} tj:| |j_6n|jj6|_;n|dEkr |js tjdFdS|jjr1 tjdGdSd} dH|krv |dH} | ddkrv tjdQt|_dSndR|kr |dRnd}tj<|| |j_|jj|_;n|dSkr8|js tjdTdS|jj=rtjdUt|jt|_dStj>|j_=|jj=|_;n;|dVkrd}d5|kr|d5}|dekrtjdY|d5t|_dSntj?||_n|dZkr(|j;stjd[t|_dS|j;j@rtjd\t|jt|_dS|d}tjA||j;_@nK|d]kr_|jjBrPtjd^qst|j_Bntjd_|dSdS(fNR/R0s'Ignoring deprecated attribute name='%s'RRAs,Ignoring deprecated attribute immutable='%s'R RRRR1s;Invalid rule: More than one element in rule '%s', ignoring.s#Service '%s' already set, ignoring.R2R3R-s#Port '%s/%s' already set, ignoring.R9s$Protocol '%s' already set, ignoring.s icmp-blocks&icmp-block '%s' already set, ignoring.s icmp-types-Invalid rule: icmp-block '%s' outside of ruleR$RBtnotfalses*Ignoring deprecated attribute enabled='%s's!Masquerade already set, ignoring.s forward-portsto-portsto-addrs#to-addr '%s' is not a valid addresss-Forward port %s/%s%s%s already set, ignoring.s >%ss @%ss source-ports*Source port '%s/%s' already set, ignoring.R4s$Invalid rule: interface use in rule.s Invalid interface: Name missing.s%Interface '%s' already set, ignoring.R6s:Invalid rule: More than one source in rule '%s', ignoring.REtyesttrueR7RDRFs$Invalid source: No address no ipset.s"Invalid source: Address and ipset.RCs)Ignoring deprecated attribute family='%s's+Invalid source: Invertion not allowed here.sipset:%ss"Source '%s' already set, ignoring.R8s)Invalid rule: Destination outside of rules?Invalid rule: More than one destination in rule '%s', ignoring.R;R<R=R?s$Invalid rule: Action outside of rules"Invalid rule: More than one actionRIR>Rs!Invalid rule: Log outside of rulesInvalid rule: More than one logRHtemergtalerttcritterrortwarningtnoticetinfotdebugsInvalid rule: Invalid log levelRGR:s#Invalid rule: Audit outside of rules9Invalid rule: More than one audit in rule '%s', ignoring.R5tipv4tipv6s&Invalid rule: Rule family "%s" invalidR@s4Invalid rule: Limit outside of action, log and audits9Invalid rule: More than one limit in rule '%s', ignoring.sicmp-block-inversions+Icmp-Block-Inversion already set, ignoring.sUnknown XML element '%s'(RR(syesR(syesR(sacceptsrejectsdropsmark(RRRserrorswarningRsinfosdebug(RR(CRt startElementRRqtparser_check_element_attrsRRRRRRRnRR RRMRgRRt Rich_ServiceR!Rt Rich_PortRRR R"t Rich_ProtocolRR)tRich_IcmpBlockR#t Rich_IcmpTypetlowertRich_MasqueradeR$tRich_ForwardPortRRRmR%tRich_SourcePortR*R&R6RTRUt Rich_SourceRRR R'R8tRich_Destinationtactiont Rich_Acceptt Rich_Rejectt Rich_Dropt Rich_MarkRtRich_LogR:t Rich_AuditReR@t Rich_LimitR+(RZR0tattrsR tentrytto_porttto_addrREtaddrRDRFt_typet_setRHRGRCR9((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyR2st                                                                                                                                                                 cCstj|||dkr|jsy|jjWn/tk rg}tjd|t|jqXt|j|j j kr|j j j |j|j j j t|jqtjdt|jnd|_t|_n|d krd|_ndS( NR5s%s: %ss Rule '%s' already set, ignoring.R;R<R=R?RR:(sacceptsrejectsdropsmarkslogsaudit(Rt endElementRRtcheckt ExceptionRRRgRqR(RWRRURTR(RZR0te((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRs        (RRRSRR(((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyR+s  dc Csbt}|jds1ttjd|n|d |_|sW|j|jn||_||_|j t j rt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r>} ttjd| jnXWdQX~~tr^|jn|S(Ns.xmls'%s' is missing .xml suffixis%s/%strbsnot a valid zone file: %s(RRzRRRyR0RxRtpathRpRt ETC_FIREWALLDRTRtbuiltintdefaultRtsaxt make_parsertsetContentHandlertopent InputSourceRUt setByteStreamtparsetSAXParseExceptiont INVALID_ZONEt getExceptionRRc( RRt no_check_nameR/thandlertparserR0tfR6tmsg((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRs:     !       c Cs% |r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|jrq|jd krq|j|d d kr{ |j0j>|d%t1|jG|jGjEr |jd-|j|||jd4|jd5i|jGjEj8d6|jd6|j|n|jd-|j|||jdn|jd|jd)|jdqW|jd |jd|jN|jO~dS(?Ns%s/%ss %s/%s.xmls%s.oldsBackup of file '%s' failed: %sitmodetwttencodingsUTF-8RRR R/s s RRR4R0sipset:R6iRFR7R1R2iiR3R9sicmp-block-inversions icmp-blockR$isto-portisto-addrs forward-ports source-portRCR5RDRREs R8s icmp-types#Unknown element '%s' in zone_writerRGRHRs R@s R:R;R<RIR=R?R>sUnknown action '%s'(PRRR0tostexiststshutiltcopy2RRRtdirnameRpRRtmkdirtioRRt startDocumentRR RRtignorableWhitespaceRt charactersRRR R&t simpleElementR'R!R"R)R+R#R$R%R*RWRCR6RRDRFRER8RMRIRRRR2R3RR9RRRRRt to_addressRRRtINVALID_OBJECTRGRHR@R:RRRRRR>Rt endDocumenttclose(R/Rt_pathR0RtdirpathRRRR4R6R1R2R3RRR5RMR((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyRs %            &                                                         (+t__all__txml.saxRRRRtfirewallRtfirewall.functionsRRRRRR R R R R tfirewall.core.baseRRtfirewall.core.io.io_objectRRRRRRRt firewall.coreRtfirewall.core.loggerRRtfirewall.errorsRRRRTRRUR(((s9/usr/lib/python2.7/site-packages/firewall/core/io/zone.pyts$   F4 PK!,== io/direct.pynu[# -*- 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): 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 PK! io/helper.pynu[# -*- 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): 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 PK!ʱ/io/__init__.pycnu[ c`c@sddlZdejkrddlmZeedsVdZeedenddlmZeedsdZ eede qndS( iNt_xmlplus(tAttributesImplt __contains__cCs|t|dkS(Nt_attrs(tgetattr(tselftname((s=/usr/lib/python2.7/site-packages/firewall/core/io/__init__.pyt__AttributesImpl__contains__s(t XMLGeneratort_writecCst|dj|dS(Nt_out(Rtwrite(Rttext((s=/usr/lib/python2.7/site-packages/firewall/core/io/__init__.pyt__XMLGenerator_write$s( txmlt__file__txml.sax.xmlreaderRthasattrRtsetattrtxml.sax.saxutilsRR (((s=/usr/lib/python2.7/site-packages/firewall/core/io/__init__.pyts   PK!hΘio/icmptype.pynu[# -*- 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): 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 PK!@>>io/firewalld_conf.pyonu[ c`c @sddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddddd d d d d g Z defdYZdS(iN(tconfig(tlog(tb2utu2btPY2t DefaultZonet MinimalMarkt CleanupOnExittLockdownt IPv6_rpfiltertIndividualCallst LogDeniedtAutomaticHelperstAllowZoneDriftingtfirewalld_confcBsPeZdZdZdZdZdZdZdZdZ RS(cCs)i|_g|_||_|jdS(N(t_configt_deletedtfilenametclear(tselfR((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyt__init__$s   cCsi|_g|_dS(N(RR(R((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyR*s cCs|jjg|_dS(N(RRR(R((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pytcleanup.s cCs|jj|jS(N(Rtgettstrip(Rtkey((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyR2scCsQt|j}t|j|j|<||jkrM|jj|ndS(N(RRRRtremove(RRtvaluet_key((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pytset5scCsad}xD|jjD]3\}}|r5|d7}n|d||f7}qWtr]t|S|S(Nts s%s=%s(RtitemsRR(RtsRR((sC/usr/lib/python2.7/site-packages/firewall/core/io/firewalld_conf.pyt__str__;s  c Cs|jyt|jd}Wntk r;}tjd|j||jdtj|jdt tj |jdtj rdnd|jdtj rdnd|jd tj rdnd|jd tjrdnd|jd tj|jd tj|jd tjr.dndnXxG|D]?}|sSPn|j}t|dksC|dd$krqCng|jdD]}|j^q}t|dkrtjd|jqCn|dtkr tjd|jqCnd|ddkr5tjd|jqCn8|jj|ddk rmtjd|jqCn|d|j|ds       PK! Ɵ//io/io_object.pynu[# -*- 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 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 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 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))) for i,(element,value) in enumerate(self.IMPORT_EXPORT_STRUCTURE): self._check_config_structure(conf[i], value) self._check_config(conf[i], element) def _check_config(self, dummy1, dummy2): # to be overloaded by sub classes return def _check_config_structure(self, conf, structure): if not type(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 type(key) != type(skey): raise FirewallError(errors.INVALID_TYPE, "'%s' not of type %s, but %s" % (\ key, type(skey), type(key))) if type(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)) PK!DܳU##io/service.pycnu[ c`c@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZdd lmZdd lmZde fd YZd e fd YZdZddZdS(tServicetservice_readertservice_writeriN(tconfig(t u2b_if_py2(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudptcheck_protocolt check_address(tlog(terrors(t FirewallErrorc BseZdddddgfddgfdidd6fddgfddgffZd Zd d gZidd6dd6dd 6Zid dgd 6ddgd6dgd6d gd6ddgd6ddgd6ZdZdZ dZ dZ RS(tversionttshortt descriptiontportstmodulest destinationt protocolst source_portss(sssa(ss)asa{ss}asa(ss))t_t-tservicetnametporttprotocoltvaluetmoduletipv4tipv6s source-portcCs_tt|jd|_d|_d|_g|_g|_g|_i|_ g|_ dS(NR( tsuperRt__init__RRRRRRRR(tself((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyR$As       cCsHd|_d|_d|_|j2|j2|j2|jj|j2dS(NR( RRRRRRRtclearR(R%((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pytcleanupLs    cCst|j|_t|j|_t|j|_g|jD]$\}}t|t|f^q@|_g|jD]}t|^qw|_d|jjD|_g|jD]}t|^q|_g|j D]$\}}t|t|f^q|_ dS(s 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+i|]!\}}t|t|qS((R(t.0tktv((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pys _s N( RRRRRRRtitemsRR(R%tpotprtm((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pytencode_stringsVs7%%cCs|dkr]x|D]C}|ddkrHt|dt|dqt|dqWnH|dkrx9|D]}t|qpWn|dkrx|D]"}t|dt|dqWn|dkrx|D]<}|dkrttjd |nt|||qWn|d krx}|D]r}|jd rw|jd d}d |krw|jd d}qwnt |dkr,ttj |q,q,WndS(NRiRiRRRR!R"s'%s' not in {'ipv4'|'ipv6'}Rt nf_conntrack_RRi(R!R"( R R R RRtINVALID_DESTINATIONR t startswithtreplacetlentINVALID_MODULE(R%RtitemRtprotoRR ((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyt _check_configds8              (sversionR(sshortR(s descriptionR(RR(RRN( t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSR$R'R/R8(((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyR&s2           tservice_ContentHandlercBseZdZRS(cCsxtj||||jj|||dkrwd|krUtjd|dnd|krt|d|j_qtn|dkrn|dkrn|dkr||ddkr't|dt|d |d|d f}||jj kr |jj j |qytjd |d|d qtt |d |d |jj kre|jj j |d qttjd |d n|d krt |d |d |jj kr|jj j |d qttjd |d n|d kr_t|dt|d |d|d f}||jj krA|jj j |qttjd|d|d n|dkrxddgD]_}||krxt|||||jjkrtjd|q|||jj|t setByteStreamtparsetSAXParseExceptiontINVALID_SERVICEt getExceptionRR/( RMRNRthandlertparserRtftsourcetmsg((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyRs8     !       c Cs|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|jrq|jd krq|j|d R(((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyts   :dE PK!oyr66 io/ipset.pycnu[ c`c@sgdZdddgZddljZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZdd lmZmZdd lmZmZmZmZdd l m!Z!dd lm"Z"dd l#m$Z$defdYZ%defdYZ&dZ'e(dZ)dS(s$ipset io XML handler, reader, writertIPSett ipset_readert ipset_writeriN(tconfig( tcheckIPtcheckIP6t checkIPnMaskt checkIP6nMaskt u2b_if_py2t check_mact check_porttcheckInterfacet checkProtocol(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(t IPSET_TYPEStIPSET_CREATE_OPTIONS(tcheck_icmp_nametcheck_icmp_typetcheck_icmpv6_nametcheck_icmpv6_type(tlog(terrors(t FirewallErrorcBseZdddddidd6fddgffZdZdd d d gZidd6dd6dgd 6d gd6dd6Zidgd 6dgd6ZdZdZ dZ e dZ dZ dZRS(tversionttshortt descriptionttypetoptionstentriess (ssssa{ss}as)t_t-t:t.tipsettnametoptiontentrytvaluecCsVtt|jd|_d|_d|_d|_g|_i|_t |_ dS(NR( tsuperRt__init__RRRRR RtFalsetapplied(tself((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyR+Cs      cCsEd|_d|_d|_d|_|j2|jjt|_dS(NR( RRRRR RtclearR,R-(R.((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pytcleanupMs     cCst|j|_t|j|_t|j|_t|j|_d|jjD|_g|jD]}t|^qn|_dS(s 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+i|]!\}}t|t|qS((R(t.0tktv((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pys ^s N(RRRRRRtitemsR (R.te((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pytencode_stringsVsc Csd}d|kr.|ddkr.d}q.n|jdsVttjd|n|djd}|jd}t|t|kst|d krttjd ||fnx'tt|D]}||}||}|d krd |kr|dkr|d kr@ttjd |||fn|jd } t| dkrttjd||||fnx| D]]} |dkrt|  s|dkrt |  rttjd| |||fqqWq|dkrL|dkr.ttjd||||fn|dkrCt } qRt} nt } | |sttjd||||fqq|dkrbd |kr|jd } t| dkrttjd||||fn|dkrt| d s|dkrGt | d rGttjd| d|||fn|dkrdt | d  s|dkr_t | d  r_ttjd| d |||fq_q|j dr|dko|dko|dksttjd||||fqn|dkr!t | s:|dkrt | rttjd||||fqq|dkrt | s|dkrttjd||fqq|dkrd|kr{|jd} t| dkrttjd|n| ddkr~|dkr6ttjd||fnt| d  rxt| d  rxttjd| d |fqxq| dd1kr|dkrttjd||fnt| d  rxt| d  rxttjd!| d |fqxq| dd2krEt| d rEttjd&| d|fqt| d sttjd'| d |fqqt|sttjd(||fqq|d)kr|jd*r yt|d+} WqJtk rttjd,||fqJXn@yt|} Wn-tk rIttjd,||fnX| dksb| d-krttjd,||fqq|d.krt| st|d/krttjd0||fqqttjd|qWdS(3Ntipv4tfamilytinet6tipv6shash:sipset type '%s' not usableit,is)entry '%s' does not match ipset type '%s'tipR"s invalid address '%s' in '%s'[%d]is.invalid address range '%s' in '%s' for %s (%s)s(invalid address '%s' in '%s' for %s (%s)s0.0.0.0itnets/0shash:net,ifacetmacs00:00:00:00:00:00s invalid mac address '%s' in '%s'tportR#sinvalid port '%s'ticmps(invalid protocol for family '%s' in '%s'sinvalid icmp type '%s' in '%s'ticmpv6s ipv6-icmps invalid icmpv6 type '%s' in '%s'ttcptsctptudptudplitesinvalid protocol '%s' in '%s'sinvalid port '%s'in '%s'sinvalid port '%s' in '%s'tmarkt0xisinvalid mark '%s' in '%s'Itifaceisinvalid interface '%s' in '%s'(RAs ipv6-icmp(RBRCRDRE(t startswithRRt INVALID_IPSETtsplittlent INVALID_ENTRYtrangeRRRRtendswithR RRRRR R tintt ValueErrorR ( R(Rt ipset_typeR8tflagsR4titflagtitemtsplitst_splittip_checktint_val((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyt check_entrybs@   *                            cCs>|dkr4|tkr4ttjd|q4n|dkr:x|jD]}|tkrxttjd|n|dkryt||}Wn1tk rttj d|||fnX|d kr3ttj d |||fq3qM|d krM||dkrMttj ||qMqMWndS(NRs'%s' is not valid ipset typeRsipset invalid option '%s'ttimeoutthashsizetmaxelems)Option '%s': Value '%s' is not an integeris#Option '%s': Value '%s' is negativeR8tinetR9(R\R]R^(R_sinet6( RRRt INVALID_TYPEtkeysRRJRPRQt INVALID_VALUEtINVALID_FAMILY(R.RRVtkeyt int_value((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyt _check_configs2          cCsd|dkrO|dddkrOt|ddkrOttjqOnx-|dD]!}tj||d|dqZWtt|j|dS(NR\it0iii(RLRRtIPSET_WITH_TIMEOUTRR[R*t import_config(R.RR(((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRi3s $(sversionR(sshortR(s descriptionR(stypeRN(t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSR+R0R6t staticmethodR[RfRi(((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyR,s.       tipset_ContentHandlercBseZdZdZRS(cCstj||||jj|||dkrd|kr~|dtkrkttjd|dn|d|j_nd|kr|d|j_ qn|dkrn|dkrn|dkrd}d |kr|d }n|d dkrttj d|d n|jjdkra|d dkrattj d|d |jjfn|d dkr| rttj d|d n|d dkryt |}Wn1t k rttj d|d |fnX|dkrttj d|d |fqn|d d krL|dkrLttj|n|d |jjkry||jj|d sd         "  cCs9tj|||dkr5|jjj|jndS(NR((Rt endElementRVR tappendt_element(R.R&((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRyus (RjRkRtRy(((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRs=s 7c Cst}|jds1ttjd|n|d |_|j|j||_||_|j t j rxt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r5}ttjd|jnXWdQX~~d|jkr|jddkrt|jd krtj d |j|j2nd } t!} x| t|jkru|j| | krtj d |j| |jj"| qy$|j#|j| |j|j$Wn3tk rS} tj d | |jj"| qX| j%|j| | d 7} qW~ t&r|j'n|S(Ns.xmls'%s' is missing .xml suffixis%s/%strbsnot a valid ipset file: %sR\Rgis6ipset '%s': timeout option is set, entries are ignoredsEntry %s already set, ignoring.s %s, ignoring.i((RRORRt INVALID_NAMER&t check_nametfilenametpathRIRt ETC_FIREWALLDR,tTruetbuiltintdefaultRstsaxt make_parsertsetContentHandlertopent InputSourceRot setByteStreamtparsetSAXParseExceptionRJt getExceptionRRLR RRwtsettpopR[RtaddR R6( RRR%thandlertparserR&tftsourcetmsgRTt entries_setR5((s:/usr/lib/python2.7/site-packages/firewall/core/io/ipset.pyRzs^     !      "    $ c Csg|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji|jd 6}|jr{|jd kr{|j|d s$   @""= 5PK!99 io/direct.pycnu[ c`c@s ddljZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZddlmZddlmZdd lmZdd lmZd efd YZd efdYZdS(iN(tconfig(tLastUpdatedOrderedDict(t splitArgstjoinArgst u2b_if_py2(t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(tlog(t ipXtables(tebtables(terrors(t FirewallErrortdirect_ContentHandlercBs#eZdZdZdZRS(cCstj||t|_dS(N(Rt__init__tFalsetdirect(tselftitem((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR(scCstj||||jj|||dkr\|jrPttjdnt|_n|dkr|jst j ddS|d}|d}|d}|jj t |t |t |n+|dkr|jst j ddS|d}|dkr ttj d |n|d}|d}yt|d }Wn'tk rqt j d|d dSXt |t |t ||g|_nZ|dkr|jst j ddS|d}t |g|_nt j d|dSdS(NRsMore than one direct tag.tchains$Parse Error: chain outside of directtipvttabletrules#Parse Error: rule outside of directtipv4tipv6tebs"'%s' not from {'ipv4'|'ipv6'|'eb'}tprioritys'Parse Error: %s is not a valid priorityt passthroughs&Parse Error: command outside of directsUnknown XML element %s(RRR(Rt startElementRtparser_check_element_attrsRR R t PARSE_ERRORtTrueRterrort add_chainRt INVALID_IPVtintt ValueErrort_rulet _passthrough(RtnametattrsRRRR((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR,sT                          cCstj|||dkr|jrm|jjgt|jD]}t|^q>|jj|jn t j dd|_nz|dkr|jr|j jgt|jD]}t|^q|jj |j nt j ddd|_ ndS(NRs2Error: rule does not have any arguments, ignoring.Rs0Error: passthrough does not have any arguments, s ignoring.(Rt endElementt_elementR%tappendRRRtadd_ruleRR tNoneR&tadd_passthrough(RR'tx((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR)^s    &     & (t__name__t __module__RRR)(((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR 's  2tDirectcBseZdZdd(gfddddddgfgfdddgfgffZdZid)d6dd d gd 6dd d d gd 6dgd 6ZiZdZdZ dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZdZdZd Zd!Zd"Zd#Zd$Zd%Zd&Z d'Z!RS(*s Direct class tchainsttrulesit passthroughss(a(sss)a(sssias)a(sas))RRRRRRRcCsDtt|j||_t|_t|_t|_dS(N(tsuperR2RtfilenameRR3R5R6(RR8((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyRs    cCsdS(N((RtconfR((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt _check_configsc CsNg}g}xO|jD]D}x;|j|D],}|jtt|t|gq*WqW|j|g}xe|jD]Z}xQ|j|D]B}|jt|d|d|d|dt|dfqWq{W|j|g}xH|jD]=}x4|j|D]%}|jt|t|fq WqW|j|t|S(Niii(R3R+ttupletlistR5R6(RtretR/tkeyRR((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt export_configs$. % ' cCs|j|j|xt|jD]\}\}}|dkrjx"||D]}|j|qPWn|dkrx"||D]}|j|qWn|dkr'x"||D]}|j|qWq'q'WdS(NR3R5R6(tcleanupt check_configt enumeratetIMPORT_EXPORT_STRUCTURER!R,R.(RR9titelementtdummyR/((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt import_configs  "   cCs+|jj|jj|jjdS(N(R3tclearR5R6(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR@s  cCsdGHx;|jD]0}d|d|ddj|j|fGHqWdGHxe|jD]Z}d|d|d|dfGHx3|j|D]$\}}d |d j|fGHqWqRWd GHxD|jD]9}d |GHx'|j|D]}d d j|GHqWqWdS(NR3s (%s, %s): %siit,R5s (%s, %s, %s):is (%d, ('%s'))s','R6s %s:s ('%s')(R3tjoinR5R6(RR>Rtargs((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pytoutputs  cCs>dddg}||kr:ttjd||fndS(NRRRs'%s' not in '%s'(R R R"(RRtipvs((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt _check_ipvs  cCsf|j||dkr(tjjn tjj}||krbttjd||fndS(NRRs'%s' not in '%s'(sipv4sipv6(RNR tBUILT_IN_CHAINStkeysR R R t INVALID_TABLE(RRRttables((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt_check_ipv_tables    cCs|j||||f}||jkr;g|j|((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR!s  cCs|j||||f}||jkr{||j|kr{|j|j|t|j|dkr|j|=qntd|||fdS(Nis4Chain '%s' with table '%s' with ipv '%s' not in list(RSR3tremovetlenR$(RRRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt remove_chains "cCs<|j||||f}||jko;||j|kS(N(RSR3(RRRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt query_chains cCsP|j||||f}||jkr6|j|Std||fdS(Ns&No chains for table '%s' with ipv '%s'(RSR3R$(RRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt get_chainss   cCs|jS(N(R3(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pytget_all_chainsscCs|j|||||f}||jkrAt|j|tvalue((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR,s'cCs|j|||||f}|t|f}||jkr||j|kr|j||=t|j|dkr|j|=qn0tddj|||fd||fdS(Nis(Rule '%s' for table '%s' and chain '%s' s',s)with ipv '%s' and priority %d not in list(RSR;R5RVR$RJ(RRRRRRKR>R[((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt remove_rules"cCs|j|||||f}||jkrx)|j|jD]}|j||=qBWt|j|dkr|j|=qndS(Ni(RSR5RPRV(RRRRR>R[((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt remove_rules"scCsQ|j|||||f}|t|f}||jkoP||j|kS(N(RSR;R5(RRRRRRKR>R[((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt query_rule+scCs[|j|||||f}||jkr9|j|Std||fd|dS(Ns'No rules for table '%s' and chain '%s' s with ipv '%s'(RSR5R$(RRRRR>((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt get_rules1s  cCs|jS(N(R5(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyt get_all_rules:scCs~|j|||jkr,g|j|RRRRRK((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pytwriteusZ               (R4R4R4N("R0R1t__doc__RCtDBUS_SIGNATURER-tPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRR:R?RGR@RLRNRSR!RWRXRYRZR,R\R]R^R_R`R.RaRbRcRdRwR(((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyR2usJ                  (txml.saxRhR{RR~tfirewallRtfirewall.fw_typesRtfirewall.functionsRRRtfirewall.core.io.io_objectRRRtfirewall.core.loggerRt firewall.coreR R R tfirewall.errorsR R R2(((s;/usr/lib/python2.7/site-packages/firewall/core/io/direct.pyts   NPK!%yUUio/icmptype.pycnu[ c`c@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlmZdd lmZdd lmZde fd YZd e fd YZdZddZdS(tIcmpTypeticmptype_readerticmptype_writeriN(tconfig(t u2b_if_py2(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(tlog(terrors(t FirewallErrorcBseZdddddgffZdZddgZidd6dd6dd6Zid dgd6d d gd6Zd Zd Z dZ dZ RS(tversionttshortt descriptiont destinations(sssas)t_t-ticmptypetnametipv4tipv6cCs;tt|jd|_d|_d|_g|_dS(NR (tsuperRt__init__R RRR(tself((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR8s    cCs&d|_d|_d|_|j2dS(NR (R RRR(R((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pytcleanup?s   cCs_t|j|_t|j|_t|j|_g|jD]}t|^q@|_dS(s 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.N(RR RRR(Rtm((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pytencode_stringsEscCsI|dkrEx6|D]+}|dkrttjd|qqWndS(NRRRs'%s' not from {'ipv4'|'ipv6'}(RR(R R tINVALID_DESTINATION(RRtitemR((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyt _check_configNs     (sversionR (sshortR (s descriptionR N( t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRRRR(((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR%s"      ticmptype_ContentHandlercBseZdZRS(cCstj||||jj|||dkrxd|krVtjd|dnd|kr|d|j_qn|dkrns|dkrnd|dkrxUdd gD]D}||kr||jd kr|jjj t |qqWndS( NRRs'Ignoring deprecated attribute name='%s'R RRRRRtyesttrue(syesR*( Rt startElementRtparser_check_element_attrsR twarningR tlowerRtappendtstr(RRtattrstx((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR+Ys"        (R R!R+(((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyR(Xsc CsYt}|jds1ttjd|n|d |_|j|j||_||_|j t j rxt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r5}ttjd|jnXWdQX~~trU|jn|S(Ns.xmls%s is missing .xml suffixis%s/%strbsnot a valid icmptype file: %s(RtendswithR R t INVALID_NAMERt check_nametfilenametpatht startswithRt ETC_FIREWALLDtFalsetTruetbuiltintdefaultR(tsaxt make_parsertsetContentHandlertopent InputSourceR%t setByteStreamtparsetSAXParseExceptiontINVALID_ICMPTYPEt getExceptionRR( R7R8RthandlertparserRtftsourcetmsg((s=/usr/lib/python2.7/site-packages/firewall/core/io/icmptype.pyRms8     !       c Cs|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|jrq|jd krq|j|d s   "3 PK! L\44io/io_object.pyonu[ c`c@sadZddddddddgZd d ljZd d ljjZd d lZd d lZd d lm Z d d l m Z d d lm Z d dl mZejdkZdefdYZdefdYZdefdYZdefdYZdejjfdYZdejfdYZdZdZdZdZd S(s5Generic io_object handler, io specific check methods.tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudptcheck_protocolt check_addressiN(t functions(tb2u(terrors(t FirewallErrort3cBsteZdZd ZdZgZiZiZdZdZ dZ dZ dZ dZ dZd ZRS( s; Abstract IO_Object as base for icmptype, service and zone s()cCs1d|_d|_d|_t|_t|_dS(Nt(tfilenametpathtnametFalsetdefaulttbuiltin(tself((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt__init__1s     cCsGg}x4|jD])}|jtjt||dqWt|S(Ni(tIMPORT_EXPORT_STRUCTUREtappendtcopytdeepcopytgetattrttuple(Rtrettx((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt export_config8s'cCs|j|xt|jD]\}\}}t||trg}t}x;||D]/}||kr\|j||j|q\q\W~t||t j |qt||t j ||qWdS(N( t check_configt enumerateRt isinstancetlisttsetRtaddtsetattrRR(Rtconftitelementtdummyt_conft_setR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt import_config>s "   cCst|ts=ttjd|tdt|fnt|dkrdttjdnxI|D]A}|j rk||j krkttjd||fqkqkWdS(Ns'%s' not of type %s, but %sR isname can't be emptys'%s' is not allowed in '%s'( R!tstrR R t INVALID_TYPEttypetlent INVALID_NAMEtisalnumtADDITIONAL_ALNUM_CHARS(RRtchar((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt check_nameNs  cCst|t|jkrIttjdt|t|jfnxKt|jD]:\}\}}|j||||j|||qYWdS(Ns structure size mismatch %d != %d(R0RR R R.R t_check_config_structuret _check_config(RR&R'R(tvalue((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR[s""cCsdS(N((Rtdummy1tdummy2((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR7esc Cst|t|ksFttjd|t|t|fnt|trt|dkrttjd|nx||D]}|j||dqWnWt|tr(t|t|krttjd|t|fnxt |D] \}}|j|||qWnt|t rt|j d\}}x|j D]\}}t|t|krttjd|t|t|fnt|t|kr`ttjd|t|t|fq`q`WndS(Ns'%s' not of type %s, but %sislen('%s') != 1islen('%s') != %d( R/R R R.R!R"R0R6RR tdicttitems( RR&t structureRR'R8tskeytsvaluetkey((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR6is8 "    " cCs,|j}t}||jkrt}|j|dk rxP|j|D]>}||krj|j|qHttjd||fqHWqn||j krt}x4|j |D]"}||kr|j|qqWn|sttjd|nx*|D]"}ttjd||fqWdS(NsMissing attribute %s for %ssUnexpected element %ss%s: Unexpected attribute %s( tgetNamesRtPARSER_REQUIRED_ELEMENT_ATTRStTruetNonetremoveR R t PARSE_ERRORtPARSER_OPTIONAL_ELEMENT_ATTRS(RRtattrst_attrstfoundR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pytparser_check_element_attrss,      ((t__name__t __module__t__doc__RtDBUS_SIGNATURER3RBRGRRR,R5RR7R6RK(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR(s     !tUnexpectedElementErrorcBseZdZdZRS(cCs tt|j||_dS(N(tsuperRPRR(RR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRscCs d|jS(NsUnexpected element '%s'(R(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt__str__s(RLRMRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRPs tMissingAttributeErrorcBseZdZdZRS(cCs)tt|j||_||_dS(N(RQRSRRt attribute(RRRT((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs cCsd|j|jfS(Ns$Element '%s': missing '%s' attribute(RRT(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRRs(RLRMRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRSs tUnexpectedAttributeErrorcBseZdZdZRS(cCs)tt|j||_||_dS(N(RQRURRRT(RRRT((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs cCsd|j|jfS(Ns'Element '%s': unexpected attribute '%s'(RRT(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRRs(RLRMRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRUs cBs5eZdZdZdZdZdZRS(cCs||_d|_dS(NR (titemt_element(RRV((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs cCs d|_dS(NR (RW(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt startDocumentscCs d|_dS(NR (RW(RRRH((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt startElementscCs@|dkr|j|j_n|dkr<|j|j_ndS(Ntshortt description(RWRVRZR[(RR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt endElements  cCs|j|jdd7_dS(Ns t (RWtreplace(Rtcontent((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt characterss(RLRMRRXRYR\R`(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs     cBs>eZdZdZdZdZdZdZRS(cCsotjjj||j|_|j|_ig|_|jd|_ g|_ d|_ t |_ t |_dS(Nisutf-8(tsaxthandlertContentHandlerRtwritet_writetflusht_flusht _ns_contextst_current_contextt_undeclared_ns_mapst _encodingRt_pending_start_elementt_short_empty_elements(Rtout((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs      cCs9trd|jD}ntjj|||dS(s 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. cSs+i|]!\}}t|t|qS((R (t.0RR8((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pys s N(RR<tsaxutilst XMLGeneratorRY(RRRH((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRYscCstrv|jdt|xF|jD]8\}}|jdt|tjt|fq*W|jdn[|jd|x:|jD],\}}|jd|tj|fqW|jddS(s* slightly modified startElement() utN(RReR R<Rpt quoteattr(RRRHR8((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt simpleElements$cCstjj|t|dS(s 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(RpRqR\R (RR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR\scCstjj|t|dS(s 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(RpRqR`R (RR_((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR`scCstjj|t|dS(s 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(RpRqtignorableWhitespaceR (RR_((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRus(RLRMRRYRtR\R`Ru(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs     cCstj|}|dkr4ttjd|n|dkrYttjd|nd|dkr~ttjd|n?t|dkr|d|dkrttjd|ndS( Nisport number in '%s' is too bigis'%s' is invalid port rangesport range '%s' is ambiguousiii(Rt getPortRangeR R t INVALID_PORTRDR0(tportt port_range((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs      & cCs)|dkr%ttjd|ndS(Nttcptudptsctptdccps)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'}(RzR{R|R}(R R tINVALID_PROTOCOL(tprotocol((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR&s  cCs(tj|s$ttj|ndS(N(Rt checkProtocolR R R~(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR,scCs5tj||s1ttjd||fndS(Ns'%s' is not valid %s address(RRR R t INVALID_ADDR(tipvtaddr((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR0s ( RNt__all__txml.saxRatxml.sax.saxutilsRpRtsystfirewallRtfirewall.functionsR R tfirewall.errorsR tversionRtobjectRt ExceptionRPRSRURbRcRRqRRRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyts,     C   PK!ʱ/io/__init__.pyonu[ c`c@sddlZdejkrddlmZeedsVdZeedenddlmZeedsdZ eede qndS( iNt_xmlplus(tAttributesImplt __contains__cCs|t|dkS(Nt_attrs(tgetattr(tselftname((s=/usr/lib/python2.7/site-packages/firewall/core/io/__init__.pyt__AttributesImpl__contains__s(t XMLGeneratort_writecCst|dj|dS(Nt_out(Rtwrite(Rttext((s=/usr/lib/python2.7/site-packages/firewall/core/io/__init__.pyt__XMLGenerator_write$s( txmlt__file__txml.sax.xmlreaderRthasattrRtsetattrtxml.sax.saxutilsRR (((s=/usr/lib/python2.7/site-packages/firewall/core/io/__init__.pyts   PK!DܳU##io/service.pyonu[ c`c@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZdd lmZdd lmZde fd YZd e fd YZdZddZdS(tServicetservice_readertservice_writeriN(tconfig(t u2b_if_py2(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudptcheck_protocolt check_address(tlog(terrors(t FirewallErrorc BseZdddddgfddgfdidd6fddgfddgffZd Zd d gZidd6dd6dd 6Zid dgd 6ddgd6dgd6d gd6ddgd6ddgd6ZdZdZ dZ dZ RS(tversionttshortt descriptiontportstmodulest destinationt protocolst source_portss(sssa(ss)asa{ss}asa(ss))t_t-tservicetnametporttprotocoltvaluetmoduletipv4tipv6s source-portcCs_tt|jd|_d|_d|_g|_g|_g|_i|_ g|_ dS(NR( tsuperRt__init__RRRRRRRR(tself((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyR$As       cCsHd|_d|_d|_|j2|j2|j2|jj|j2dS(NR( RRRRRRRtclearR(R%((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pytcleanupLs    cCst|j|_t|j|_t|j|_g|jD]$\}}t|t|f^q@|_g|jD]}t|^qw|_d|jjD|_g|jD]}t|^q|_g|j D]$\}}t|t|f^q|_ dS(s 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+i|]!\}}t|t|qS((R(t.0tktv((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pys _s N( RRRRRRRtitemsRR(R%tpotprtm((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pytencode_stringsVs7%%cCs|dkr]x|D]C}|ddkrHt|dt|dqt|dqWnH|dkrx9|D]}t|qpWn|dkrx|D]"}t|dt|dqWn|dkrx|D]<}|dkrttjd |nt|||qWn|d krx}|D]r}|jd rw|jd d}d |krw|jd d}qwnt |dkr,ttj |q,q,WndS(NRiRiRRRR!R"s'%s' not in {'ipv4'|'ipv6'}Rt nf_conntrack_RRi(R!R"( R R R RRtINVALID_DESTINATIONR t startswithtreplacetlentINVALID_MODULE(R%RtitemRtprotoRR ((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyt _check_configds8              (sversionR(sshortR(s descriptionR(RR(RRN( t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSR$R'R/R8(((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyR&s2           tservice_ContentHandlercBseZdZRS(cCsxtj||||jj|||dkrwd|krUtjd|dnd|krt|d|j_qtn|dkrn|dkrn|dkr||ddkr't|dt|d |d|d f}||jj kr |jj j |qytjd |d|d qtt |d |d |jj kre|jj j |d qttjd |d n|d krt |d |d |jj kr|jj j |d qttjd |d n|d kr_t|dt|d |d|d f}||jj krA|jj j |qttjd|d|d n|dkrxddgD]_}||krxt|||||jjkrtjd|q|||jj|t setByteStreamtparsetSAXParseExceptiontINVALID_SERVICEt getExceptionRR/( RMRNRthandlertparserRtftsourcetmsg((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyRs8     !       c Cs|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|jrq|jd krq|j|d R(((s</usr/lib/python2.7/site-packages/firewall/core/io/service.pyts   :dE PK!C11io/lockdown_whitelist.pynu[# -*- 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): if item in [ "commands", "contexts", "users", "uids" ]: for x in config: self._check_config(x, item[:-1]) 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 PK!yRyR io/ipset.pynu[# -*- 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): 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 PK!!  io/helper.pyonu[ c`c@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZdd lmZdd lmZde fd YZd e fd YZdZddZdS(tHelpert helper_readert helper_writeriN(tconfig(t u2b_if_py2(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudp(tlog(terrors(t FirewallErrorcBseZdddddddgffZdZdd gZidd6dd6dgd 6Zid ddgd 6d d gd 6ZdZdZ dZ dZ dZ RS(tversionttshortt descriptiontfamilytmoduletportss (sssssa(ss))t-t.thelpertnametporttprotocolcCsMtt|jd|_d|_d|_d|_d|_g|_dS(NR( tsuperRt__init__RRRRRR(tself((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR;s     cCs8d|_d|_d|_d|_d|_|j2dS(NR(RRRRRR(R((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pytcleanupDs      cCst|j|_t|j|_t|j|_t|j|_t|j|_g|jD]$\}}t|t|f^qd|_dS(s 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.N(RRRRRRR(Rtpotpr((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pytencode_stringsLs cCs;ddg}||kr7ttjd||fndS(Ntipv4tipv6s'%s' not in '%s'(R R t INVALID_IPV(Rtipvtipvs((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyt check_ipvWs   cCs|dkr<x|D]"}t|dt|dqWnn|dkr|jdspttjd|nt|jdddkrttjd|qndS( NRiiRt nf_conntrack_s('%s' does not start with 'nf_conntrack_'RsModule name '%s' too short(R R t startswithR R tINVALID_MODULEtlentreplace(RRtitemR((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyt _check_config]s    (sversionR(sshortR(s descriptionR(sfamilyR(smoduleR(RRN( t__name__t __module__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARStNonetPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRRR!R'R.(((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR&s(    thelper_ContentHandlercBseZdZRS(cCstj||||jj|||dkrd|krQ|d|j_nd|kr|jj|d|d|j_nd|kr|djdstt j d|dnt |dj dddkrtt j d |dn|d|j_ qn|d kr$n|d kr3n|d krt|d t|d |d |d f}||jjkr|jjj|qtjd|d |d ndS(NRRRRR(s('%s' does not start with 'nf_conntrack_'RisModule name '%s' too shortRRRRs#Port '%s/%s' already set, ignoring.(Rt startElementR-tparser_check_element_attrsRR'RR)R R R*R+R,RR R RtappendR twarning(RRtattrstentry((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR8ns>    "    (R/R0R8(((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyR7msc CsYt}|jds1ttjd|n|d |_|j|j||_||_|j t j rxt nt |_|j|_t|}tj}|j|d||f}t|di}tjd}|j|y|j|Wn2tjk r5}ttjd|jnXWdQX~~trU|jn|S(Ns.xmls'%s' is missing .xml suffixis%s/%strbsnot a valid helper file: %s(RtendswithR R t INVALID_NAMERt check_nametfilenametpathR)Rt ETC_FIREWALLDtFalsetTruetbuiltintdefaultR7tsaxt make_parsertsetContentHandlertopent InputSourceR4t setByteStreamtparsetSAXParseExceptiontINVALID_HELPERt getExceptionRR!( RBRCRthandlertparserRtftsourcetmsg((s;/usr/lib/python2.7/site-packages/firewall/core/io/helper.pyRs8     !       c Cs|r |n|j}|jr4d||jf}nd||jf}tjj|rytj|d|Wqtk r}tj d||qXntjj |}|j t j rtjj| rtjjt j stjt j dntj|dntj|dddd }t|}|ji}|j|d <|jr~|jd kr~|j|d s   .G# PK!A io/ifcfg.pycnu[ c`c@sdZdgZddlZddlZddlZddlZddlmZddl m Z m Z m Z de fdYZdS(sifcfg file parsertifcfgiN(tlog(tb2utu2btPY2cBsPeZdZdZdZdZdZdZdZdZ RS(cCs)i|_g|_||_|jdS(N(t_configt_deletedtfilenametclear(tselfR((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyt__init__#s   cCsi|_g|_dS(N(RR(R ((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyR)s cCs|jjdS(N(RR(R ((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pytcleanup-scCs|jj|jS(N(Rtgettstrip(R tkey((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyR 0scCsQt|j}t|j|j|<||jkrM|jj|ndS(N(RR RRtremove(R Rtvaluet_key((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pytset3scCsad}xD|jjD]3\}}|r5|d7}n|d||f7}qWtr]t|S|S(Nts s%s=%s(RtitemsRR(R tsRR((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyt__str__9s  cCs|jyt|jd}Wn,tk rN}tjd|j|nXxL|D]D}|sfPn|j}t|dksV|dd krqVng|jddD]}|j^q}t|dkrqVnt|ddkr1|dj d r1|dj d r1|ddd !|d|j j |ddk rtjd |j|jqVn|d|j |ds     PK!ߓM}.}.io/lockdown_whitelist.pyonu[ c`c@sddljZddlZddlZddlZddlmZddlmZm Z m Z m Z ddl m Z ddlmZmZmZmZmZmZddlmZddlmZde fd YZd e fd YZdS( iN(tconfig(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(tlog(tuniqifyt checkUsertcheckUidt checkCommandt checkContextt u2b_if_py2(terrors(t FirewallErrort!lockdown_whitelist_ContentHandlercBseZdZdZRS(cCstj||t|_dS(N(Rt__init__tFalset whitelist(tselftitem((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR%scCstj||||jj|||dkr\|jrPttjdnt|_n[|dkr|jst j ddS|d}|jj |n|dkrH|jst j ddSd|kr"yt |d}Wn't k rt j d |ddSX|jj|qd|kr|jj|dqno|d kr|jsnt j d dSd |krt j d dS|jj|d nt j d|dSdS(NRsMore than one whitelist.tcommands)Parse Error: command outside of whitelisttnametusers&Parse Error: user outside of whitelisttids"Parse Error: %s is not a valid uidtselinuxs)Parse Error: selinux outside of whitelisttcontextsParse Error: no contextsUnknown XML element %s(Rt startElementRtparser_check_element_attrsRR R t PARSE_ERRORtTrueRterrort add_commandtintt ValueErrortadd_uidtadd_usert add_context(RRtattrsRtuid((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR)sJ                      (t__name__t __module__RR(((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR$s tLockdownWhitelistcBsxeZdZddgfddgfddgfddgffZdZdgZid*d 6d gd 6d*d 6d gd6Zidd gd 6ZdZ dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZdZd Zd!Zd"Zd#Zd$Zd%Zd&Zd'Z d(Z!d)Z"RS(+s LockdownWhitelist class tcommandsttcontextstuserstuidsis (asasasai)t_RRRRRRRcCsMtt|j||_d|_g|_g|_g|_g|_ dS(N( tsuperR)RtfilenametNonetparserR*R,R-R.(RR1((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyRns     cCs|d kr4x|D]}|j||d qWn|dkrdt|sttj|qn|dkrt|sttj|qn`|dkrt|sttj|qn0|d krt |sttj |qndS( NR*R,R-R.iRRRR&(scommandsscontextssuserssuids( t _check_configR R R tINVALID_COMMANDR tINVALID_CONTEXTRt INVALID_USERRt INVALID_UID(RRRtx((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR4ys          cCs |j2|j2|j2|j2dS(N(R*R,R-R.(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytcleanupscCssg|jD]}t|^q |_g|jD]}t|^q/|_g|jD]}t|^qT|_dS(s 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.N(R*R R,R-(RR9((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytencode_stringss%%cCs]t|s!ttj|n||jkrC|jj|nttjd|dS(Ns!Command "%s" already in whitelist(R R R R5R*tappendtALREADY_ENABLED(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyRs   cCs<||jkr"|jj|nttjd|dS(NsCommand "%s" not in whitelist.(R*tremoveR R t NOT_ENABLED(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytremove_commands cCs ||jkS(N(R*(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt has_commandscCsQxJ|jD]?}|jdr9|j|d rItSq ||kr tSq WtS(Nt*i(R*tendswitht startswithRR(RRt_command((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_commands cCs|jS(N(R*(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt get_commandsscCsct|s'ttjt|n||jkrI|jj|nttjd|dS(NsUid "%s" already in whitelist(RR R R8tstrR.R<R=(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR"s   cCs<||jkr"|jj|nttjd|dS(NsUid "%s" not in whitelist.(R.R>R R R?(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt remove_uids cCs ||jkS(N(R.(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pythas_uidscCs ||jkS(N(R.(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_uidscCs|jS(N(R.(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytget_uidsscCs]t|s!ttj|n||jkrC|jj|nttjd|dS(NsUser "%s" already in whitelist(RR R R7R-R<R=(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR#s   cCs<||jkr"|jj|nttjd|dS(NsUser "%s" not in whitelist.(R-R>R R R?(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt remove_users cCs ||jkS(N(R-(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pythas_userscCs ||jkS(N(R-(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_userscCs|jS(N(R-(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt get_usersscCs]t|s!ttj|n||jkrC|jj|nttjd|dS(Ns!Context "%s" already in whitelist(R R R R6R,R<R=(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR$"s   cCs<||jkr"|jj|nttjd|dS(NsContext "%s" not in whitelist.(R,R>R R R?(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytremove_context,s cCs ||jkS(N(R,(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt has_context3scCs ||jkS(N(R,(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_context6scCs|jS(N(R,(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt get_contexts9scCs|j|jjds8ttjd|jnt|}tj}|j |y|j |jWn2tj k r}ttj d|j nX~~tr|jndS(Ns.xmls'%s' is missing .xml suffixsNot a valid file: %s(R:R1RCR R t INVALID_NAMERtsaxt make_parsertsetContentHandlertparsetSAXParseExceptiont INVALID_TYPEt getExceptionRR;(RthandlerR3tmsg((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytread>s"      cCsHtjj|jreytj|jd|jWqetk ra}td|j|fqeXntjjtj stj tj dnt j |jdddd}t |}|j|jdi|jd xHt|jD]7}|jd |jd i|d 6|jd qWxNt|jD]=}|jd |jd it|d6|jd q<WxHt|jD]7}|jd |jd i|d 6|jd qWxHt|jD]7}|jd |jdi|d6|jd qW|jd|jd |j|j~dS(Ns%s.oldsBackup of '%s' failed: %sitmodetwttencodingsUTF-8Rs s RRRRRR(tostpathtexistsR1tshutiltcopy2t ExceptiontIOErrorRt ETC_FIREWALLDtmkdirtiotopenRt startDocumentRtignorableWhitespaceRR*t simpleElementR.RHR-R,t endElementt endDocumenttclose(RR^tfR]RR&RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytwriteQsB             N(#R'R(t__doc__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARSR2tPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRR4R:R;RR@RARFRGR"RIRJRKRLR#RMRNRORPR$RQRRRSRTR_Ru(((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR)WsP                   1     (txml.saxRVRcRlRftfirewallRtfirewall.core.io.io_objectRRRRtfirewall.core.loggerRtfirewall.functionsRRRR R R R tfirewall.errorsR RR)(((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyts   ".3PK!"" io/zone.pynu[# -*- 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 checkIP, checkIP6, checkIPnMask, checkIP6nMask, checkInterface, uniqify, max_zone_name_len, u2b_if_py2, check_mac, portStr 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, 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 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 ) DBUS_SIGNATURE = '(sssbsasa(ss)asba(ssss)asasasasa(ss)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-port": [ "port", "protocol" ], "interface": [ "name" ], "rule": None, "source": None, "destination": [ "address" ], "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" ], "source": [ "address", "mac", "invert", "family", "ipset" ], "destination": [ "invert" ], "log": [ "prefix", "level" ], "reject": [ "type" ], } @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.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.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 _check_config(self, config, item): if item == "services" and self.fw_config: existing_services = self.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 self.fw_config: existing_icmptypes = self.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 == "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) 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) elif item == "rules_str": for rule in config: rich.Rich_Rule(rule_str=rule) 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)) 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.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 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 == "short": pass elif name == "description": pass elif name == "service": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Service(attrs["name"]) return if attrs["name"] not in self.item.services: self.item.services.append(attrs["name"]) else: log.warning("Service '%s' already set, ignoring.", attrs["name"]) elif name == "port": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Port(attrs["port"], attrs["protocol"]) return check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(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"]) elif name == "protocol": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Protocol(attrs["value"]) else: 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 == "icmp-block": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_IcmpBlock(attrs["name"]) return if attrs["name"] not in self.item.icmp_blocks: self.item.icmp_blocks.append(attrs["name"]) else: log.warning("icmp-block '%s' already set, ignoring.", attrs["name"]) elif name == "icmp-type": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_IcmpType(attrs["name"]) return else: log.warning("Invalid rule: icmp-block '%s' outside of rule", attrs["name"]) elif name == "masquerade": if "enabled" in attrs and \ attrs["enabled"].lower() in [ "no", "false" ] : log.warning("Ignoring deprecated attribute enabled='%s'", attrs["enabled"]) return if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Masquerade() else: if self.item.masquerade: log.warning("Masquerade already set, ignoring.") else: self.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 self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_ForwardPort(attrs["port"], attrs["protocol"], to_port, to_addr) return 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 self.item.forward_ports: self.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 self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_SourcePort(attrs["port"], attrs["protocol"]) return check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(attrs["port"], "-"), attrs["protocol"]) if entry not in self.item.source_ports: self.item.source_ports.append(entry) else: log.warning("Source port '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) 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 == "destination": if not self._rule: log.warning('Invalid rule: Destination outside of rule') self._rule_error = True return if self._rule.destination: log.warning("Invalid rule: More than one destination in rule '%s', ignoring.", str(self._rule)) return invert = False if "invert" in attrs and \ attrs["invert"].lower() in [ "yes", "true" ]: invert = True self._rule.destination = rich.Rich_Destination(attrs["address"], invert) elif name in [ "accept", "reject", "drop", "mark" ]: if not self._rule: log.warning('Invalid rule: Action outside of rule') self._rule_error = True return if self._rule.action: log.warning('Invalid rule: More than one action') self._rule_error = True return if name == "accept": self._rule.action = rich.Rich_Accept() elif name == "reject": _type = None if "type" in attrs: _type = attrs["type"] self._rule.action = rich.Rich_Reject(_type) elif name == "drop": self._rule.action = rich.Rich_Drop() elif name == "mark": _set = attrs["set"] self._rule.action = rich.Rich_Mark(_set) self._limit_ok = self._rule.action elif name == "log": if not self._rule: log.warning('Invalid rule: Log outside of rule') return if self._rule.log: log.warning('Invalid rule: More than one log') return 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') self._rule_error = True return prefix = attrs["prefix"] if "prefix" in attrs else None self._rule.log = rich.Rich_Log(prefix, level) self._limit_ok = self._rule.log elif name == "audit": if not self._rule: log.warning('Invalid rule: Audit outside of rule') return if self._rule.audit: log.warning("Invalid rule: More than one audit in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.audit = rich.Rich_Audit() self._limit_ok = self._rule.audit elif name == "rule": family = None if "family" in attrs: family = attrs["family"] if family not in [ "ipv4", "ipv6" ]: log.warning('Invalid rule: Rule family "%s" invalid', attrs["family"]) self._rule_error = True return self._rule = rich.Rich_Rule(family) elif name == "limit": if not self._limit_ok: log.warning('Invalid rule: Limit outside of action, log and audit') self._rule_error = True return if self._limit_ok.limit: log.warning("Invalid rule: More than one limit in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return value = attrs["value"] self._limit_ok.limit = rich.Rich_Limit(value) 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) if name == "rule": if not self._rule_error: try: self._rule.check() except Exception as e: log.warning("%s: %s", e, str(self._rule)) else: if str(self._rule) not in self.item.rules_str: self.item.rules.append(self._rule) self.item.rules_str.append(str(self._rule)) else: log.warning("Rule '%s' already set, ignoring.", str(self._rule)) self._rule = None self._rule_error = False elif name in [ "accept", "reject", "drop", "mark", "log", "audit" ]: self._limit_ok = None 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") # short if zone.short and zone.short != "": handler.ignorableWhitespace(" ") handler.startElement("short", { }) handler.characters(zone.short) handler.endElement("short") handler.ignorableWhitespace("\n") # description if zone.description and zone.description != "": handler.ignorableWhitespace(" ") handler.startElement("description", { }) handler.characters(zone.description) handler.endElement("description") handler.ignorableWhitespace("\n") # 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") # services for service in uniqify(zone.services): handler.ignorableWhitespace(" ") handler.simpleElement("service", { "name": service }) handler.ignorableWhitespace("\n") # ports for port in uniqify(zone.ports): handler.ignorableWhitespace(" ") handler.simpleElement("port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # protocols for protocol in uniqify(zone.protocols): handler.ignorableWhitespace(" ") handler.simpleElement("protocol", { "value": protocol }) handler.ignorableWhitespace("\n") # icmp-block-inversion if zone.icmp_block_inversion: handler.ignorableWhitespace(" ") handler.simpleElement("icmp-block-inversion", { }) handler.ignorableWhitespace("\n") # icmp-blocks for icmp in uniqify(zone.icmp_blocks): handler.ignorableWhitespace(" ") handler.simpleElement("icmp-block", { "name": icmp }) handler.ignorableWhitespace("\n") # masquerade if zone.masquerade: handler.ignorableWhitespace(" ") handler.simpleElement("masquerade", { }) handler.ignorableWhitespace("\n") # forward-ports for forward in uniqify(zone.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(zone.source_ports): handler.ignorableWhitespace(" ") handler.simpleElement("source-port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # rules for rule in zone.rules: attrs = { } if rule.family: attrs["family"] = rule.family 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 = { "address": rule.destination.addr } 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 zone_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.simpleElement("limit", { "value": rule.log.limit.value }) 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.simpleElement("limit", { "value": rule.audit.limit.value }) 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.simpleElement("limit", { "value": rule.action.limit.value }) handler.ignorableWhitespace("\n ") handler.endElement(action) else: handler.ignorableWhitespace(" ") handler.simpleElement(action, attrs) handler.ignorableWhitespace("\n") handler.ignorableWhitespace(" ") handler.endElement("rule") handler.ignorableWhitespace("\n") # end zone element handler.endElement("zone") handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PK!ߓM}.}.io/lockdown_whitelist.pycnu[ c`c@sddljZddlZddlZddlZddlmZddlmZm Z m Z m Z ddl m Z ddlmZmZmZmZmZmZddlmZddlmZde fd YZd e fd YZdS( iN(tconfig(tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGenerator(tlog(tuniqifyt checkUsertcheckUidt checkCommandt checkContextt u2b_if_py2(terrors(t FirewallErrort!lockdown_whitelist_ContentHandlercBseZdZdZRS(cCstj||t|_dS(N(Rt__init__tFalset whitelist(tselftitem((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR%scCstj||||jj|||dkr\|jrPttjdnt|_n[|dkr|jst j ddS|d}|jj |n|dkrH|jst j ddSd|kr"yt |d}Wn't k rt j d |ddSX|jj|qd|kr|jj|dqno|d kr|jsnt j d dSd |krt j d dS|jj|d nt j d|dSdS(NRsMore than one whitelist.tcommands)Parse Error: command outside of whitelisttnametusers&Parse Error: user outside of whitelisttids"Parse Error: %s is not a valid uidtselinuxs)Parse Error: selinux outside of whitelisttcontextsParse Error: no contextsUnknown XML element %s(Rt startElementRtparser_check_element_attrsRR R t PARSE_ERRORtTrueRterrort add_commandtintt ValueErrortadd_uidtadd_usert add_context(RRtattrsRtuid((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR)sJ                      (t__name__t __module__RR(((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR$s tLockdownWhitelistcBsxeZdZddgfddgfddgfddgffZdZdgZid*d 6d gd 6d*d 6d gd6Zidd gd 6ZdZ dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZdZd Zd!Zd"Zd#Zd$Zd%Zd&Zd'Z d(Z!d)Z"RS(+s LockdownWhitelist class tcommandsttcontextstuserstuidsis (asasasai)t_RRRRRRRcCsMtt|j||_d|_g|_g|_g|_g|_ dS(N( tsuperR)RtfilenametNonetparserR*R,R-R.(RR1((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyRns     cCs|d kr4x|D]}|j||d qWn|dkrdt|sttj|qn|dkrt|sttj|qn`|dkrt|sttj|qn0|d krt |sttj |qndS( NR*R,R-R.iRRRR&(scommandsscontextssuserssuids( t _check_configR R R tINVALID_COMMANDR tINVALID_CONTEXTRt INVALID_USERRt INVALID_UID(RRRtx((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR4ys          cCs |j2|j2|j2|j2dS(N(R*R,R-R.(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytcleanupscCssg|jD]}t|^q |_g|jD]}t|^q/|_g|jD]}t|^qT|_dS(s 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.N(R*R R,R-(RR9((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytencode_stringss%%cCs]t|s!ttj|n||jkrC|jj|nttjd|dS(Ns!Command "%s" already in whitelist(R R R R5R*tappendtALREADY_ENABLED(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyRs   cCs<||jkr"|jj|nttjd|dS(NsCommand "%s" not in whitelist.(R*tremoveR R t NOT_ENABLED(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytremove_commands cCs ||jkS(N(R*(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt has_commandscCsQxJ|jD]?}|jdr9|j|d rItSq ||kr tSq WtS(Nt*i(R*tendswitht startswithRR(RRt_command((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_commands cCs|jS(N(R*(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt get_commandsscCsct|s'ttjt|n||jkrI|jj|nttjd|dS(NsUid "%s" already in whitelist(RR R R8tstrR.R<R=(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR"s   cCs<||jkr"|jj|nttjd|dS(NsUid "%s" not in whitelist.(R.R>R R R?(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt remove_uids cCs ||jkS(N(R.(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pythas_uidscCs ||jkS(N(R.(RR&((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_uidscCs|jS(N(R.(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytget_uidsscCs]t|s!ttj|n||jkrC|jj|nttjd|dS(NsUser "%s" already in whitelist(RR R R7R-R<R=(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR#s   cCs<||jkr"|jj|nttjd|dS(NsUser "%s" not in whitelist.(R-R>R R R?(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt remove_users cCs ||jkS(N(R-(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pythas_userscCs ||jkS(N(R-(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_userscCs|jS(N(R-(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt get_usersscCs]t|s!ttj|n||jkrC|jj|nttjd|dS(Ns!Context "%s" already in whitelist(R R R R6R,R<R=(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR$"s   cCs<||jkr"|jj|nttjd|dS(NsContext "%s" not in whitelist.(R,R>R R R?(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytremove_context,s cCs ||jkS(N(R,(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt has_context3scCs ||jkS(N(R,(RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt match_context6scCs|jS(N(R,(R((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyt get_contexts9scCs|j|jjds8ttjd|jnt|}tj}|j |y|j |jWn2tj k r}ttj d|j nX~~tr|jndS(Ns.xmls'%s' is missing .xml suffixsNot a valid file: %s(R:R1RCR R t INVALID_NAMERtsaxt make_parsertsetContentHandlertparsetSAXParseExceptiont INVALID_TYPEt getExceptionRR;(RthandlerR3tmsg((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytread>s"      cCsHtjj|jreytj|jd|jWqetk ra}td|j|fqeXntjjtj stj tj dnt j |jdddd}t |}|j|jdi|jd xHt|jD]7}|jd |jd i|d 6|jd qWxNt|jD]=}|jd |jd it|d6|jd q<WxHt|jD]7}|jd |jd i|d 6|jd qWxHt|jD]7}|jd |jdi|d6|jd qW|jd|jd |j|j~dS(Ns%s.oldsBackup of '%s' failed: %sitmodetwttencodingsUTF-8Rs s RRRRRR(tostpathtexistsR1tshutiltcopy2t ExceptiontIOErrorRt ETC_FIREWALLDtmkdirtiotopenRt startDocumentRtignorableWhitespaceRR*t simpleElementR.RHR-R,t endElementt endDocumenttclose(RR^tfR]RR&RR((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pytwriteQsB             N(#R'R(t__doc__tIMPORT_EXPORT_STRUCTUREtDBUS_SIGNATUREtADDITIONAL_ALNUM_CHARSR2tPARSER_REQUIRED_ELEMENT_ATTRStPARSER_OPTIONAL_ELEMENT_ATTRSRR4R:R;RR@RARFRGR"RIRJRKRLR#RMRNRORPR$RQRRRSRTR_Ru(((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyR)WsP                   1     (txml.saxRVRcRlRftfirewallRtfirewall.core.io.io_objectRRRRtfirewall.core.loggerRtfirewall.functionsRRRR R R R tfirewall.errorsR RR)(((sG/usr/lib/python2.7/site-packages/firewall/core/io/lockdown_whitelist.pyts   ".3PK! L\44io/io_object.pycnu[ c`c@sadZddddddddgZd d ljZd d ljjZd d lZd d lZd d lm Z d d l m Z d d lm Z d dl mZejdkZdefdYZdefdYZdefdYZdefdYZdejjfdYZdejfdYZdZdZdZdZd S(s5Generic io_object handler, io specific check methods.tPY2t IO_ObjecttIO_Object_ContentHandlertIO_Object_XMLGeneratort check_portt check_tcpudptcheck_protocolt check_addressiN(t functions(tb2u(terrors(t FirewallErrort3cBsteZdZd ZdZgZiZiZdZdZ dZ dZ dZ dZ dZd ZRS( s; Abstract IO_Object as base for icmptype, service and zone s()cCs1d|_d|_d|_t|_t|_dS(Nt(tfilenametpathtnametFalsetdefaulttbuiltin(tself((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt__init__1s     cCsGg}x4|jD])}|jtjt||dqWt|S(Ni(tIMPORT_EXPORT_STRUCTUREtappendtcopytdeepcopytgetattrttuple(Rtrettx((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt export_config8s'cCs|j|xt|jD]\}\}}t||trg}t}x;||D]/}||kr\|j||j|q\q\W~t||t j |qt||t j ||qWdS(N( t check_configt enumerateRt isinstancetlisttsetRtaddtsetattrRR(Rtconftitelementtdummyt_conft_setR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt import_config>s "   cCst|ts=ttjd|tdt|fnt|dkrdttjdnxI|D]A}|j rk||j krkttjd||fqkqkWdS(Ns'%s' not of type %s, but %sR isname can't be emptys'%s' is not allowed in '%s'( R!tstrR R t INVALID_TYPEttypetlent INVALID_NAMEtisalnumtADDITIONAL_ALNUM_CHARS(RRtchar((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt check_nameNs  cCst|t|jkrIttjdt|t|jfnxKt|jD]:\}\}}|j||||j|||qYWdS(Ns structure size mismatch %d != %d(R0RR R R.R t_check_config_structuret _check_config(RR&R'R(tvalue((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR[s""cCsdS(N((Rtdummy1tdummy2((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR7esc Cst|t|ksFttjd|t|t|fnt|trt|dkrttjd|nx||D]}|j||dqWnWt|tr(t|t|krttjd|t|fnxt |D] \}}|j|||qWnt|t rt|j d\}}x|j D]\}}t|t|krttjd|t|t|fnt|t|kr`ttjd|t|t|fq`q`WndS(Ns'%s' not of type %s, but %sislen('%s') != 1islen('%s') != %d( R/R R R.R!R"R0R6RR tdicttitems( RR&t structureRR'R8tskeytsvaluetkey((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR6is8 "    " cCs,|j}t}||jkrt}|j|dk rxP|j|D]>}||krj|j|qHttjd||fqHWqn||j krt}x4|j |D]"}||kr|j|qqWn|sttjd|nx*|D]"}ttjd||fqWdS(NsMissing attribute %s for %ssUnexpected element %ss%s: Unexpected attribute %s( tgetNamesRtPARSER_REQUIRED_ELEMENT_ATTRStTruetNonetremoveR R t PARSE_ERRORtPARSER_OPTIONAL_ELEMENT_ATTRS(RRtattrst_attrstfoundR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pytparser_check_element_attrss,      ((t__name__t __module__t__doc__RtDBUS_SIGNATURER3RBRGRRR,R5RR7R6RK(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR(s     !tUnexpectedElementErrorcBseZdZdZRS(cCs tt|j||_dS(N(tsuperRPRR(RR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRscCs d|jS(NsUnexpected element '%s'(R(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt__str__s(RLRMRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRPs tMissingAttributeErrorcBseZdZdZRS(cCs)tt|j||_||_dS(N(RQRSRRt attribute(RRRT((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs cCsd|j|jfS(Ns$Element '%s': missing '%s' attribute(RRT(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRRs(RLRMRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRSs tUnexpectedAttributeErrorcBseZdZdZRS(cCs)tt|j||_||_dS(N(RQRURRRT(RRRT((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs cCsd|j|jfS(Ns'Element '%s': unexpected attribute '%s'(RRT(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRRs(RLRMRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRUs cBs5eZdZdZdZdZdZRS(cCs||_d|_dS(NR (titemt_element(RRV((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs cCs d|_dS(NR (RW(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt startDocumentscCs d|_dS(NR (RW(RRRH((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt startElementscCs@|dkr|j|j_n|dkr<|j|j_ndS(Ntshortt description(RWRVRZR[(RR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt endElements  cCs|j|jdd7_dS(Ns t (RWtreplace(Rtcontent((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt characterss(RLRMRRXRYR\R`(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs     cBs>eZdZdZdZdZdZdZRS(cCsotjjj||j|_|j|_ig|_|jd|_ g|_ d|_ t |_ t |_dS(Nisutf-8(tsaxthandlertContentHandlerRtwritet_writetflusht_flusht _ns_contextst_current_contextt_undeclared_ns_mapst _encodingRt_pending_start_elementt_short_empty_elements(Rtout((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs      cCs9trd|jD}ntjj|||dS(s 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. cSs+i|]!\}}t|t|qS((R (t.0RR8((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pys s N(RR<tsaxutilst XMLGeneratorRY(RRRH((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRYscCstrv|jdt|xF|jD]8\}}|jdt|tjt|fq*W|jdn[|jd|x:|jD],\}}|jd|tj|fqW|jddS(s* slightly modified startElement() utN(RReR R<Rpt quoteattr(RRRHR8((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyt simpleElements$cCstjj|t|dS(s 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(RpRqR\R (RR((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR\scCstjj|t|dS(s 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(RpRqR`R (RR_((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR`scCstjj|t|dS(s 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(RpRqtignorableWhitespaceR (RR_((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRus(RLRMRRYRtR\R`Ru(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs     cCstj|}|dkr4ttjd|n|dkrYttjd|nd|dkr~ttjd|n?t|dkr|d|dkrttjd|ndS( Nisport number in '%s' is too bigis'%s' is invalid port rangesport range '%s' is ambiguousiii(Rt getPortRangeR R t INVALID_PORTRDR0(tportt port_range((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyRs      & cCs)|dkr%ttjd|ndS(Nttcptudptsctptdccps)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'}(RzR{R|R}(R R tINVALID_PROTOCOL(tprotocol((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR&s  cCs(tj|s$ttj|ndS(N(Rt checkProtocolR R R~(R((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR,scCs5tj||s1ttjd||fndS(Ns'%s' is not valid %s address(RRR R t INVALID_ADDR(tipvtaddr((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyR0s ( RNt__all__txml.saxRatxml.sax.saxutilsRpRtsystfirewallRtfirewall.functionsR R tfirewall.errorsR tversionRtobjectRt ExceptionRPRSRURbRcRRqRRRRR(((s>/usr/lib/python2.7/site-packages/firewall/core/io/io_object.pyts,     C   PK!g{f,f,io/firewalld_conf.pynu[# -*- 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", "Lockdown", "IPv6_rpfilter", "IndividualCalls", "LogDenied", "AutomaticHelpers", "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("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("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: 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 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("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 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) PK!{5`.`. io/service.pynu[# -*- 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", "" ), # s ( "short", "" ), # s ( "description", "" ), # s ( "ports", [ ( "", "" ), ], ), # a(ss) ( "modules", [ "", ], ), # as ( "destination", { "": "", }, ), # a{ss} ( "protocols", [ "", ], ), # as ( "source_ports", [ ( "", "" ), ], ), # a(ss) ) DBUS_SIGNATURE = '(sssa(ss)asa{ss}asa(ss))' 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" ], } def __init__(self): super(Service, self).__init__() self.version = "" self.short = "" self.description = "" self.ports = [ ] self.protocols = [ ] self.modules = [ ] self.destination = { } self.source_ports = [ ] 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[:] 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] def _check_config(self, config, item): 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) 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") # end service element handler.endElement('service') handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PK!A io/ifcfg.pyonu[ c`c@sdZdgZddlZddlZddlZddlZddlmZddl m Z m Z m Z de fdYZdS(sifcfg file parsertifcfgiN(tlog(tb2utu2btPY2cBsPeZdZdZdZdZdZdZdZdZ RS(cCs)i|_g|_||_|jdS(N(t_configt_deletedtfilenametclear(tselfR((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyt__init__#s   cCsi|_g|_dS(N(RR(R ((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyR)s cCs|jjdS(N(RR(R ((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pytcleanup-scCs|jj|jS(N(Rtgettstrip(R tkey((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyR 0scCsQt|j}t|j|j|<||jkrM|jj|ndS(N(RR RRtremove(R Rtvaluet_key((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pytset3scCsad}xD|jjD]3\}}|r5|d7}n|d||f7}qWtr]t|S|S(Nts s%s=%s(RtitemsRR(R tsRR((s:/usr/lib/python2.7/site-packages/firewall/core/io/ifcfg.pyt__str__9s  cCs|jyt|jd}Wn,tk rN}tjd|j|nXxL|D]D}|sfPn|j}t|dksV|dd krqVng|jddD]}|j^q}t|dkrqVnt|ddkr1|dj d r1|dj d r1|ddd !|d|j j |ddk rtjd |j|jqVn|d|j |ds     PK!) io/functions.pyonu[ c`c@sddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd ZdS( iN(tconfig(t FirewallError(t zone_reader(tservice_reader(t ipset_reader(ticmptype_reader(t helper_reader(tDirect(tLockdownWhitelist(tfirewalld_confcCsittjtjgfd6ttjtjgfd6ttjtj gfd6t tj tj gfd6t tjtjgfd6}x#|jD]}x ||dD]}tjj|sqnxttj|D]}|jdryO||d||}|r)|dkr)|j|_n|j|jWqtk rq}t|jd ||jfqtk r}td ||fqXqqWqWqWtjjtjrTy0t tj}|j!|j|jWqTtk r%}t|jd tj|jfqTtk rP}td tj|fqTXntjjtj"ry0t#tj"}|j!|j|jWqtk r}t|jd tj"|jfqtk r}td tj"|fqXntjjtj$ryt%tj$}|j!Wqtk rh}t|jd tj$|jfqtk r}td tj$|fqXndS( Ntipsetthelperticmptypetservicetzoneis.xmlis'%s': %s(&RRtFIREWALLD_IPSETStETC_FIREWALLD_IPSETSRtFIREWALLD_HELPERStETC_FIREWALLD_HELPERSRtFIREWALLD_ICMPTYPEStETC_FIREWALLD_ICMPTYPESRtFIREWALLD_SERVICEStETC_FIREWALLD_SERVICESRtFIREWALLD_ZONEStETC_FIREWALLD_ZONEStkeystostpathtisdirtsortedtlistdirtendswitht fw_configt check_configt export_configRtcodetmsgt ExceptiontisfiletFIREWALLD_DIRECTRtreadtLOCKDOWN_WHITELISTRtFIREWALLD_CONFR (tfwtreaderstreadertdirtfiletobjterrorR$((s>/usr/lib/python2.7/site-packages/firewall/core/io/functions.pyR!$s^") %  % %(RtfirewallRtfirewall.errorsRtfirewall.core.io.zoneRtfirewall.core.io.serviceRtfirewall.core.io.ipsetRtfirewall.core.io.icmptypeRtfirewall.core.io.helperRtfirewall.core.io.directRt#firewall.core.io.lockdown_whitelistRtfirewall.core.io.firewalld_confR tNoneR!(((s>/usr/lib/python2.7/site-packages/firewall/core/io/functions.pyts PK!'^ icmp.pyonu[ c`c@sddddgZi"dd6dd6dd6d d 6d d 6d d6dd6dd6dd6dd6dd6dd6dd6dd6dd 6d!d"6d#d$6d%d&6d'd(6d)d*6d+d,6d-d.6d/d06d/d16d2d36d4d56d6d76d8d96d:d;6d<d=6d>d?6d@dA6dBdC6dDdE6ZidFdG6dHd 6dIdJ6dKd6dLdM6dd76d d96d%dN6dOdP6dQdR6dSd06dSd16dTd6dTd6dUd56dVd36dWdX6dWdY6dZd[6dZd\6d]d^6Zd_Zd`ZdaZdbZdcS(dt ICMP_TYPESt ICMPV6_TYPEStcheck_icmp_typetcheck_icmpv6_types0/0s echo-replytpongs3/0snetwork-unreachables3/1shost-unreachables3/2sprotocol-unreachables3/3sport-unreachables3/4sfragmentation-neededs3/5ssource-route-faileds3/6snetwork-unknowns3/7s host-unknowns3/9snetwork-prohibiteds3/10shost-prohibiteds3/11sTOS-network-unreachables3/12sTOS-host-unreachables3/13scommunication-prohibiteds3/14shost-precedence-violations3/15sprecedence-cutoffs4/0s source-quenchs5/0snetwork-redirects5/1s host-redirects5/2sTOS-network-redirects5/3sTOS-host-redirects8/0s echo-requesttpings9/0srouter-advertisements10/0srouter-solicitations11/0sttl-zero-during-transits11/1sttl-zero-during-reassemblys12/0s ip-header-bads12/1srequired-option-missings13/0stimestamp-requests14/0stimestamp-replys17/0saddress-mask-requests18/0saddress-mask-replys1/0sno-routes1/1s1/3saddress-unreachables1/4s2/0spacket-too-bigs bad-headers4/1sunknown-header-types4/2sunknown-options128/0s129/0s133/0s134/0s135/0sneighbour-solicitationsneigbour-solicitations136/0sneighbour-advertisementsneigbour-advertisements137/0tredirectcCs|tkrtStS(N(RtTruetFalse(t_name((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pytcheck_icmp_nameVs cCs|tjkrtStS(N(RtvaluesRR(t_type((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pyR[scCs|tkrtStS(N(RRR(R ((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pytcheck_icmpv6_name`s cCs|tjkrtStS(N(RR RR(R ((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pyResN(t__all__RRR RR R(((s6/usr/lib/python2.7/site-packages/firewall/core/icmp.pyts|      PK!Dv 66snd-rawmidi.ko.xznu[PK! 7snd-pcm.ko.xznu[PK!mgDDsnd-seq-device.ko.xznu[PK!P:HHbseq/snd-seq-midi-event.ko.xznu[PK!6`D`Dseq/oss/snd-seq-oss.ko.xznu[PK!S7ިBseq/snd-seq-midi.ko.xznu[PK!vRcWseq/snd-seq-midi-emul.ko.xznu[PK!#QY` ` kseq/snd-seq-dummy.ko.xznu[PK!^3vseq/snd-seq-virmidi.ko.xznu[PK! n nTseq/snd-seq.ko.xznu[PK!m?DD snd.ko.xznu[PK!x' 2xsnd-hrtimer.ko.xznu[PK!#0!0!;snd-compress.ko.xznu[PK!wd(00snd-hwdep.ko.xznu[PK!sih:h:snd-timer.ko.xznu[PK!wuO ledtrig-usbport.ko.xznu[PK!^ܪ>y>y logger.pynu[PK!͙22 |nftables.pynu[PK!@@ nmodules.pyonu[PK! |__init__.pynu[PK!H H 6}fw_helper.pyonu[PK!H H fw_helper.pycnu[PK!n%?-@fw_service.pyonu[PK!S>R(*(*fw_transaction.pynu[PK!}w@ {helper.pycnu[PK! Z? fw_config.pynu[PK!`3Vfw_nm.pynu[PK!e&$$ pipset.pyonu[PK!㏷ ʕfw_nm.pycnu[PK!CIR%$%$ ebtables.pycnu[PK!a  fw_icmptype.pynu[PK!Cnƒ$$ qebtables.pynu[PK![Domm /logger.pycnu[PK!8^^ prich.pycnu[PK!Ɵ8C$$ Dhelper.pynu[PK!*<< fw_zone.pyonu[PK!ө= __init__.pycnu[PK!'^ icmp.pycnu[PK!*<< fw_zone.pycnu[PK!Ы99 'nftables.pyonu[PK!/>EE D fw_test.pyonu[PK!%77  ipXtables.pyonu[PK!YL;;  fw_direct.pycnu[PK![Domm gQ logger.pyonu[PK!²]22 X watcher.pycnu[PK!  prog.pycnu[PK!Er##  fw_ipset.pynu[PK!@@  modules.pycnu[PK!V_P)) f fw_helper.pynu[PK!²]22  watcher.pyonu[PK!D8 prog.pynu[PK!%77 U ipXtables.pycnu[PK!Y++ɫ fw_transaction.pycnu[PK!n%?- fw_service.pycnu[PK!4Hzz  fw_config.pycnu[PK!ф$$ [ fw_ipset.pyonu[PK!ф$$  fw_ipset.pycnu[PK!YL;; I fw_direct.pyonu[PK!nF"]9X9X  fw_test.pynu[PK!|:vPvP 8 fw_direct.pynu[PK!i֑ ˆ fw_icmptype.pycnu[PK!e&$$  ipset.pycnu[PK!zzϹ fw.pyonu[PK!  4icmp.pynu[PK!H  Amodules.pynu[PK!xObase.pynu[PK!\ }XuXuWrich.pynu[PK!1 Jfw_policies.pynu[PK!Uu)){base.pycnu[PK!|QӮӮfw.pynu[PK! prog.pyonu[PK!Uu))base.pyonu[PK!~N Yfw_policies.pyonu[PK!ө= \__init__.pyonu[PK!f$f$)ipset.pynu[PK!4Hzz fw_config.pyonu[PK!}w@ Bhelper.pyonu[PK!i֑ Cfw_icmptype.pyonu[PK!ZZ Pfw_ifcfg.pyonu[PK!Ы99 Wnftables.pycnu[PK!~N fw_policies.pycnu[PK!CIR%$%$ "ebtables.pyonu[PK!ZZ "fw_ifcfg.pycnu[PK!8^^*rich.pyonu[PK!~ =watcher.pynu[PK!َ:  fw_ifcfg.pynu[PK!zzPfw.pycnu[PK! 7ipXtables.pynu[PK!Y++*fw_transaction.pyonu[PK!㏷ Afw_nm.pyonu[PK!gnbk.k. 1fw_zone.pynu[PK!/>EE Lfw_test.pycnu[PK!gg ْfw_service.pynu[PK!99 }io/direct.pyonu[PK!m io/ifcfg.pynu[PK!,:<<io/__init__.pynu[PK!Bq^^ io/zone.pyonu[PK!!  1Rio/helper.pycnu[PK!oyr66 ?oio/ipset.pyonu[PK!) io/functions.pycnu[PK!@>>io/firewalld_conf.pycnu[PK!H˨io/functions.pynu[PK!%yUUio/icmptype.pyonu[PK!Bq^^ wio/zone.pycnu[PK!,== Vio/direct.pynu[PK! io/helper.pynu[PK!ʱ/~io/__init__.pycnu[PK!hΘoio/icmptype.pynu[PK!@>>Eio/firewalld_conf.pyonu[PK! Ɵ//io/io_object.pynu[PK!DܳU###io/service.pycnu[PK!oyr66 Gio/ipset.pycnu[PK!99 }io/direct.pycnu[PK!%yUUio/icmptype.pycnu[PK! L\44io/io_object.pyonu[PK!ʱ/Lio/__init__.pyonu[PK!DܳU##= io/service.pyonu[PK!C11-io/lockdown_whitelist.pynu[PK!yRyR ^io/ipset.pynu[PK!!  io/helper.pyonu[PK!A io/ifcfg.pycnu[PK!ߓM}.}.io/lockdown_whitelist.pyonu[PK!"" io/zone.pynu[PK!ߓM}.}. io/lockdown_whitelist.pycnu[PK! L\44io/io_object.pycnu[PK!g{f,f,io/firewalld_conf.pynu[PK!{5`.`. T=io/service.pynu[PK!A kio/ifcfg.pyonu[PK!) @io/functions.pyonu[PK!'^ Bicmp.pyonu[PK)'