e2dZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlmZddlmZmZdZdZgdZgdZd d gZd Zd Zd ZdZdZd9dZdZ dZ!dZ"dZ#d:dZ$dZ%dZ&dZ'd:dZ(dZ)ejTdfdZ+dZ,dZ-dZ.d Z/e j`fd!Z1e j`fd"Z2d#Z3d$Z4d%Z5d&Z6d'Z7d(Z8d)Z9d*Z:d;d+Z;dd/Z?d0Z@d1ZAd2ZBd3ZCd4ZDd5ZEd6ZFd>d7ZGd8ZHy)?z"util.py: utility functions for ufw)print_functionN)reduce)mkstempmktempF)tcpudpipv6espahigmpgrevrrp)r r r r r rr r cd} tj| tj|dd} tj|d|dk(rd}|Sd} |S#t$rwxYw#t$rY>wxYw#t$rY|SwxYw)z8Get the protocol for a specified port from /etc/servicesrrany)socket getservbyname Exception)portprotos */usr/lib/python3/dist-packages/ufw/util.pyget_services_protor.s ET" T5) T5) E>E L E L%         L s3AA%A4A4 A"% A10A14 BBcd}d}|jd}t|dk(r |d}d}||fSt|dk(r/|d}|d}|tvrtd|z}t |||fStd}t |) zParse port or port and protocolr/rrzInvalid port with protocol '%s'zBad port)splitlenportless_protocols_ ValueError)p_strrrtmperr_msgs rparse_port_protor%Hs D E ++c C 3x1}1v %= SQ1vA & &9EABGW% % %=J-!!cptjs tdyt|dkDst j d|sy|j d} tjtj|dt|dkDryt|dk(rt|dd syy #t$rYywxYw) zVerifies if valid IPv6 addressz"python does not have IPv6 support.F+z^[a-fA-F0-9:\./]+$rrrrT) rhas_ipv6warnrrematchr inet_ptonAF_INET6r_valid_cidr_netmaskaddrnets rvalid_address6r3\s ?? 12 4y2~RXX&;TB **S/C#a&1 3x!| SQ"3q640  s'B)) B54B5cZt|dkDstjd|sy|jd} t j tj |dt|ddsy t|dkDryt|dk(rt|ddsyy#t$rYywxYw) zVerifies if valid IPv4 addressz ^[0-9\./]+$FrrrrT) rr+r,rrr-AF_INET_valid_dotted_quadsr valid_netmaskr0s rvalid_address4r9vs 4y2~RXXnd; **S/CQ0"3q6512  3x!| SQSVU+  s6B B*)B*c6t||xs t||S)z(Verifies if valid cidr or dotted netmask)r/r7)nmv6s rr8r8s r2 & E*=b"*EEr&c|dk(r t|S|dk(r t|S|dk(rt|xs t|St)zValidate IP addresses64r)r3r9r!)r1versions r valid_addressrAsI#~d## Cd## E d#;~d';; r&cg}d}d}tj}|rd}tj}d|vr5|jd}|r |ddk(r|d=n'|s%|ddk(s|ddk(r|d=n|j ||s0t |d k(r"t |d|r t|d||d<|d }tj|tj||}||d k7rd }t |d k(r5|d|dzz }|s(t|}||k7rd |d |d}t||}d }t||sd|z}t|t||fS#t$rYwxYw)zConvert address to standard form. Use no netmask for IP addresses. If netmask is specified and not all 1's, for IPv4 use cidr if possible, otherwise dotted netmask and for IPv6, use cidr. Fr?r>rr12832z255.255.255.255rrTzUsing 'z' for address ''zInvalid address '%s')rr6r.rappendrr7_dotted_netmask_to_cidrr inet_ntopr-_address4_to_networkdebugrAr!) origr<r2changedr@s_typer1networkdbg_msgs rnormalize_addressrPs| CGG ^^F  d{jjo #a&E/AQ43q65F+FA 4 #c(a-$7A$C ,SVR8CF q6D   FF$4$4VT$B CD s1v~ 3x1} c!f *40G$;BDIg w '(D1 g '?5   sE EEct|dS)z"Opens the specified file read-onlyr)open)fns ropen_file_readrUs C=r&c~t|} t\}}||||dS#t$r|jwxYw)z=Opens the specified file read-only and a tempfile read-write.)rKorignamer#tmpname)rUrrclose)rTrKr#rXs r open_filesrZsJ " D g r#' KK   s !<c|dk(ry|sttjdtr7|tj j k(rtj|yd}tjddk\r!tj|t|d}ntj||}|dkrttjdy) z~Write to the file descriptor and error out of 0 bytes written. Intended to be used with open_files() and close_files().rNzNot a valid file descriptorrasciiz"Could not write to file descriptor) OSErrorerrnoENOENT msg_outputsysstdoutfilenowrite version_infoosbytesEIO)fdoutrcs r write_to_filerns by ell$ABBbCJJ--// B a XXb%W- . XXb#  Qweii!EFFr&Tc|djtj|d|r8tj|d|dtj|d|dtj |dy)zuCloses the specified files (as returned by open_files), and update original file with the temporary file. rKr#rWrXN)rYrhshutilcopystatcopyunlink)fnsupdates r close_filesrvscKHHSZ JY8 C NC O4IIc)nr&ct| tj|tjtjd}|jd}|jt |gS#t $r}dt |gcYd}~Sd}~wwxYw)z!Try to execute the given command.T)rdstderruniversal_newlinesNr) rJ subprocessPopenPIPESTDOUTr_str communicate returncode)commandspexrls rcmdrsx 'N   gjoo%/%6%6157 .. 1 C MM3s8 $$ SW~s5A,, B 5 BB B c* tj|tj}tj||j}|j d}|jt |gS#t$r}dt |gcYd}~Sd}~wwxYw)z#Try to pipe command1 into command2.)rd)stdinrzNr)r{r|r}rdr_rrr)command1command2sp1sp2rrls rcmd_piper$syx @xszz: // A C NNCH %% SW~sAA22 B; B B BcR |j} |jdd}tr5t j t jr|j|n|jt||jy#t$r|}YwxYw#t$r|}YwxYw)zQImplement our own print statement that will output utf-8 when appropriate.utf-8ignoreN) bufferrencoderbinspectisclassioStringIOrfriflush)outputswriterrls r_printr2shhw) goobkk2 Q U3Z  LLN  s" BB BB B&%B&c ttjd|z|rtjdyy#t$rY$wxYw)zPrint error message and exitz ERROR: %s rN)rrcrxIOErrorexit)rldo_exits rerrorrGsC szz=3./      s8 AAc^ ttjd|zy#t$rYywxYw)zPrint warning messagez WARN: %s N)rrcrxrrls rr*r*Rs, szz<#-.    s  ,,ctr|tjk(rt} |rt|d|zyt|d|zy#t$rYywxYw)z Print messagez%s %sN)rbrcrdrr)rlrnewlines rmsgrZsKf *  66C< ( 64#: &    sAA AAcltr ttjd|zyy#t$rYywxYw)zPrint debug messagez DEBUG: %s N) DEBUGGINGrrcrxrrs rrJrJhs6  3::}s2 3   s ' 33c>t|fd|jdS)z A word-wrap function that preserves existing line breaks and most spaces in the text. Expects that existing line breaks are posix newlines ( ). c |dt||jdz dz t|jdddz|k\|S)Nz  rr)rrfindr)linewordwidths rzword_wrap..wsV#d)DJJt$44q8djjq1!4569>?A 3r& )rr)textrs r word_wraprqs% 5 **S/  r&ct|dS)zWord wrap to a specific widthK)r)rs r wrap_textrs T2 r&c6d|jfdy)a$Sorts list of strings into numeric order, with text case-insensitive. Modifies list in place. Eg: [ '80', 'a222', 'a32', 'a2', 'b1', '443', 'telnet', '3', 'http', 'ZZZ'] sorts to: ['3', '80', '443', 'a2', 'a32', 'a222', 'b1', 'http', 'telnet', 'ZZZ'] cX|jr t|S|jSN)isdigitintlower)ts rrzhuman_sort..sqyy{SV r&cbtjd|Dcgc] }| c}Scc}w)Nz([0-9]+))r+r)kcnorms rrzhuman_sort..s$bhhz1.EFT!WFFs,)keyN)sort)lstrs @r human_sortrs :DHHFHGr&c t|}tjj dt |d}tjj|std|zt|jdjdddjd}t|S#t$r tdwxYw)zdFinds parent process id for pid based on /proc//stat. See 'man 5 proc' for details. zpid must be an integer/procstatCouldn't find '%s'r)r) rrr!rhpathjoinrisfilerrS readlinesrsplitr)mypidpidnameppids rget_ppidrs3%j 77<<S6 2D 77>>$ *d344 :   !! $ + +C 3A 6 < < >q AD t9 31223s B//Ccx t|}|dk(s|dkrytjjdt |d}tjj|std|z}t | t|jdjd}td |z|d k(ry t|S#t$rtd}t|Yyt$r#tdt |z}t |wxYw#t$rtd |z}t |wxYw) z1Determine if current process is running under sshz%Couldn't find pid (is /proc mounted?)Fz!Couldn't find parent pid for '%s'rrrrrz"Could not find executable for '%s'zunder_ssh: exe is '%s'z(sshd)T)rrr r*rrr!rhrrrrSrrrJ under_ssh)rrwarn_msgr$rexes rrrs/"} ax419 77<<TF 3D 77>>$ ()T2!!"4j""$Q'--/2 "c *+ h; <= X "78CHE!!" "89TB!!"s C;-DD(+D#D9cvd}|rd}tjd|rt|dkst||kDryy)zVerifies cidr netmasks ^[0-9]+$rFT)r+r,r)r;r<nums rr/r/s7 C  88K $B! s2w} r&c|rytjd|rH|jd}t|dk7ry|D]"}|rt |dkst |dkDs"yyy)z.Verifies dotted quad ip addresses and netmasksFz^[0-9]+\.[0-9\.]+$.rT)r+r,rrr)r;r<quadsqs rr7r7se  88)2 .HHSME5zQ !CFQJ#a&3,  ! r&c d}|rtt||std} ttjdt j |d}d}tdD]}||z dzdk(rd}|rd}n|dz }|dk\r|dkrtd|z }t||st|S#t$r8ttjdt j |d}YwxYw) z@Convert netmask to cidr. IPv6 dotted netmasks are not supported.rr>LFrrTr\) r!r7longstructunpackr inet_aton NameErrorrrangerr/)r;r<cidrmbitsbits found_onens rrGrGs D "2r*   E dF,<,C-,C-cBd}|rtt||st td}t dD]}|t |ks|dd|z zz}t jtjd|}t||st|S#t$rd}YtwxYw)z q6D!fG B2u% $R /DtV-=-=d-CDQGH v}}T6+;+;B+?@CD w&Lv{{4>?Gw '' D dF,<,?BCDs+A*D A3F?Fcd}d|vr td|S|jd}t|dk7st|ddst|d}|d}t j dtjtj|} td}td D]>}|||d }td D]"} |dt|| zd | z |d zz zz}$@ td} td D]}|t|ks| dd |z zz} || z} g} td D]0}| jt|| d |d z|d zd zd2tjtjt j d| d| d| d| d | d| d| d| d } | d|S#t$rd}Y3wxYw#t$rd} YwxYw)z8Convert an IPv6 address and netmask to a network addressc djt|dz ddDcgc]}t||z dzc}Scc}w)zDecimal to binaryrrr\)rrr)rcountys rdec2binz%_address6_to_network..dec2binfs9wwU57B5KLSAXN+LMMLs=rz8_address6_to_network: skipping address without a netmaskrrTrz>8Hrzrr]r)rJrrr8r!rrrr-r.rrrrrFrHr)r1rr# orig_hostnetmaskunpackedrirjrr2rrNs r_address6_to_networkr dsN $ HI **S/C 3x1}M#a&$7AI!fG}}UF$4$4V__5>%@AHG 1X9 HQK $r 9A !c!A$i-SU1R4Z8 8I 99 q'3Z* s7|  qWM) )G* g C C 1X< 3wsC(2ad2g6:;<v%{{5#a&#a&+.q63q63q6+.q63q63q6 CDG w ''A   s$ F<$ G< G  G  GGc|jd}t|dk7st|d|st|d}|d}|dk(s|dk(ry|}d|vr9|jd}t|dk7st|d|st|d}|dk(s|dk(ry|rt |r t |s"tt |r t |stt ||r|s t||}|rIt|d|jdd}t|d|jdd}||k(St|d|jdd}t|d|jdd}||k(S)z&Determine if address x is in network yrrrrz0.0.0.0z::T) rrr8r!r3r9r/rr rI) tested_add tested_netr<r#rraddress orig_networkrNs r in_networkrs   3 C 3x1}M#a&"5AI!fGId!2G g~mmC  s8q= c!fb 9 a&)w$ g&nY.G g&nY.G 7B')'26 +-6-ABBG%*QP &(/(:;;@5:aI l "" ,-6-ABBG%*QP &(/(:;;@5:aI l ""r&cd}dD]E}tjj|d}tjj|rnd}G|dk(rt t j d|S)Nr)z/sbinz/binz /usr/sbinz/usr/binz/usr/local/sbinz/usr/local/biniptableszCould not find iptables)rhrrexistsr_r`ra)rds r_find_system_iptablesrsf C3ggll1j) 77>>#  C byell$=>> Jr&c| t}t|dg\}}|dk7rttjd|z|j }t jdd|dS)zReturn iptables versionz-VrzError running '%s'z^vrr)rrr_r`rarr+sub)rrmrlr#s rget_iptables_versionrsa {#%S$K IR Qwell$8C$@AA ))+C 66$CF ##r&c(d}|r1tjdk7rttjd| t }g}d}|j drd}|tddz }t|d |g\}}|dk7rttj||||gd r|jd |||gd r|jd t|d|gt|d|g\}}|dk7rttj||S)z[Return capabilities set for netfilter to support new features. Callers must be root.c<|d|g}t||z\}}|dk(ryy)Nz-ArTF)r)rchainruleargsrmrls rtest_capz,get_netfilter_capabilities..test_caps-T5!t $ S 7r&rz Must be rootz ufw-caps-test ip6tableszufw6-caps-testr)prefixdirz-N)-m conntrack --ctstateNEWr!recentz--setz recent-set) r!r"r#r$r!r%z--updatez --seconds30z --hitcountr>z recent-updatez-Fz-X) rhgetuidr_r`EPERMrendswithrrrarF)r do_checksrcapsrrmrls rget_netfilter_capabilitiesr,sRYY[A%ekk>22 {#% D E ||K    V22 &&ES$&'IR QwellC(( U67 L!U01 O$dES$&'IR QwellC(( Kr&c|t|}t}|jD]}|jds|jds'|j }|d}|dj dd}t}dj |dj ddd|d<|d |d <|d j d d|d <|d dk(r |d |d<n|d j d d|d<||vrt||<g|||<n|||vrg|||<|||j ||S)z:Get and parse netstat the output from get_netstat_output()rrrr:r\Nladdrr]uidrrr-r)get_netstat_outputdict splitlines startswithrrrF)r<netstat_outputrrr#rritems rparse_netstat_outputr8'sP (+N A))+$u%dooe.D jjlA1v||C $vQc!23B!78W !fU !fll3'*U ;# u+DKa&,,s+A.DK >vAeHAeHTN1U8#!#% %d#1$4 Hr&c d}|r d}tjj|sttj d|zt |jD]}|j}||dk(sdjtdt|ddDcgc] }|d||dzc}}|djd k7sr|d t|djd }|dk(rttjd t!j t j"t j$} t!j&t)j*|j-d t/j0d|dddd}t5||dScc}w#t2$rttjd wxYw)zGet IP address for interfacer/proc/net/if_inet6'%s' does not existrr.rrr80rrNo such devicei256sN)rhrrr_r`rarSrrrrrrrrENODEVrr6 SOCK_DGRAMrfcntlioctlrerrrrP)ifnamer<r1procrr#rrs rget_ip_from_ifrHMs D #ww~~d#%,,(=(DE EJ((* ED**,CQxx38CAK3KLaCF1QqSMLNq6<<>T)&*CA ,CDD E 2:%,,(89 9 MM&..&*;*; < :##EKK F$*KKs $D%FFH%MND T2 &q ))M :%,,(89 9 :sF& AF++$Gc d}d}t|rd}d}n%t|sttjdt j j|sttjd|zd}|rt|jD]}|j}|dj}d jtd t!|d d Dcgc] }|d ||d zc}}|d j#d k7r"|dt%|d j#d}||k(sd|vst'||ds|}|S|St|jD]@}d |vr|jd d j} t)|d} | |k(s=|}|S|Scc}w#t$rYUwxYw)zGet interface for IP addressFz /proc/net/devTr:r=r;rrr.rrrr<rr)r3r9rr`rBrhrrr_rarSrrstriprrrrrrrH) r1r<rGmatchedrr#rFrtmp_addrips rget_if_from_iprNms B Dd # D !ell$455 77>>$ ell$9D$@AAG J((* D**,CV\\^Fxx38CAK3KLaCF1QqSMLNH1v||~%&.CFLLNB0GHxxJtXt$D  N9 8 NJ((* D$ZZ_Q'--/F #FE2Tz  N  N/M   sF.  F33 F?>F?c2tjd}|jtjd}t }|D]}|j |stjjd|d}tj|tjtjzsmd} tjtjjd|d} tj|}|D]`} tjtjj||d}|dtjj|||<b!|S#t$rYwxYw#t$rY?wxYw#t$rYwxYw)zGet inodes of files in /procrrrkr1rrr)rhlistdirrr+compiler3r,rraccessF_OKR_OKreadlinkrrbasename) proc_filespatinodesrfd_pathexe_pathdirsrinodes r_get_proc_inodesr^sZG$JOO **[ !C VF Fyy| '',,w40yy"''BGG"34  {{277<<E#BCH ::g&D FA  Wa 89!<()"''*:*:8*DEF5M  F+F8 M          s674E+,E:6F + E76E7: FF FFc lddddddddd d d d }d dddd}tjjd|}tj|tjtj zst g}d}t|j}|D]}|j}|sd}|t||dd} |jdrd} n|jdr| d k7rX||djd\} } ||d} ||d} |j| t| d| | | f|S)z=Read /proc/net/(tcp|udp)[6] file and return a list of tuples ESTABLISHEDSYN_SENTSYN_RECV FIN_WAIT1 FIN_WAIT2 TIME_WAITCLOSE CLOSE_WAITLAST_ACKLISTENCLOSING) rrr]rrrrr rr]rrk) local_addrstater0r]z /proc/netFTrorrNArrnr.r0r]) rhrrrRrSrTr!rSrrrr5rF)protocol tcp_statesproc_net_fieldsrTr skipped_firstlinesrfieldsror/rr0r]s r_read_proc_net_protocolrws]#  !!!"   J'(!" !"O k8 ,B 99R277* + CM H   E > M 3vog&>?DE   u %E   'EX,= _\:;AA#F t_U+,w/0 E3tR=#ue<= > Jr&c Xd}t|dkDrd}tdddD]8}|djt|dz|dDcgc] }||dz | c}z }:tdjtdt|dDcgc]}|||dzj c}d d}|Sg}tdddDcgc] }||dz | c}D]&}|j t t|d (td j|d d}|Scc}wcc}wcc}w) zDConvert an address from /proc/net/(tcp|udp)* to a normalized addressrrrrrr.rTrrF)rrrrPrrFrr)paddr convertedr#rrs rconvert_proc_addressr|s2I 5zA~q"a HA 27751a3DFaU1Q3q\FG GC H%chh,1!SXq,ABqAac   "B'D   ).q!R:A51Q<: (A JJs3q": ' (%chhsmU;A> GB;sD D" D'ct}ddg}|r|ddgz }|D]} t|||<t }t |j}|jd}|D][}||D]Q\}} } } } t|} d}t| |vr|t| }||dd | d | d d | d d | dd | d d |d z }S]|S#t$rtd|z}t |YwxYw)z5netstat-style output, without IPv6 address truncationrrtcp6udp6z!Could not get statistics for '%s'rr15rr.4611r) r3rwrr r*r^listkeysrr|r)r< proc_net_datarprrY protocolsrr/rr0r]ror1rs rr2r2s$FM ENE  &&!!  6q9M!  F]'')*I NN A  O0=a0@ O ,UD#ue'.DC5zV#SZ( qBF7M7 ? F Fw OOr&ctjddkr!|jdjdStjdt |dzr|dd n|zjdd S) z,Take a hex string and convert it to a stringrr]r)encodingrrrNr\backslashreplace)rcrgrr unhexlifyr)hs r hex_decoder=sn Qxxx'..w77   dA afB C J J# r&cnd}|s0t|d}tj|tj|S)zCreate a blocking lockfileNw)rSrDlockfLOCK_EX)lockfiledryrunlocks r create_lockrLs- D Hc" D%--( Kr&c|y tj|tj|jy#t$rYywxYw)z(Free lockfile created with create_lock()N)rDrLOCK_UNrYr!)rs r release_lockrUs> |  D%--(    s4: AA)r)Tr)NT)F)z /run/ufw.lockF)I__doc__ __future__rrrr`rDrrrhr+rprrr{rc functoolsrtempfilerrrrbsupported_protocolsripv4_only_protocolsrr%r3r9r8rArPrUrZrnrvrrrrr*rdrrJrrrgetpidrrr/r7rGrrIr rrrr,r8rHrNr^rwr|r2rrrrrr&rrsv("&   $   QAv&4(42F 4n LG2  % &* JJ    H299;."))+!N 2$\: (F7(t,#h  $6r# L*@,^"J,^&  F P   r&