o MHd%~@sFdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlmZddlmZmZdZdZgdZgdZd d gZd d Zd dZddZddZddZdhddZddZ ddZ!ddZ"ddZ#did!d"Z$d#d$Z%d%d&Z&d'd(Z'did)d*Z(d+d,Z)ej*d fd-d.Z+d/d0Z,d1d2Z-d3d4Z.d5d6Z/e 0fd7d8Z1e 0fd9d:Z2d;d<Z3d=d>Z4d?d@Z5dAdBZ6dCdDZ7dEdFZ8dGdHZ9dIdJZ:djdKdLZ;dkdMdNZdSdTZ?dUdVZ@dWdXZAdYdZZBd[d\ZCd]d^ZDd_d`ZEdadbZFdmdddeZGdfdgZHdS)nz"util.py: utility functions for ufw)print_functionN)reduce)mkstempmktempF)tcpudpipv6espahigmpgre)rr r r r rr cCsd}zt|Wntywz t|dd}Wn ty%Ynwzt|d|dkr6d}W|Sd}W|StyDY|Sw)z8Get the protocol for a specified port from /etc/servicesrrany)socket getservbyname Exception)portprotor*/usr/lib/python3/dist-packages/ufw/util.pyget_services_proto.s.     rcCsd}d}|d}t|dkr|d}d}||fSt|dkr9|d}|d}|tvr5td|}t|||fStd}t|) zParse port or port and protocolr /rrzInvalid port with protocol '%s'zBad port)splitlenportless_protocols_ ValueError)p_strrrtmperr_msgrrrparse_port_protoHs     r"cCstjs tddSt|dkstd|sdS|d}z ttj|dWn t y1YdSwt|dkr:dSt|dkrIt |dd sIdSd S) 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_netmaskaddrnetrrrvalid_address6\s"    r.cCst|dks td|sdS|d}zttj|dt|dds'WdSWn ty2YdSwt|dkr;dSt|dkrJt |ddsJdSdS) zVerifies if valid IPv4 addressz ^[0-9\./]+$FrrrrT) rr&r'rrr(AF_INET_valid_dotted_quadsr valid_netmaskr+rrrvalid_address4vs"    r3cCst||p t||S)z(Verifies if valid cidr or dotted netmask)r*r1)nmv6rrrr2sr2rcCs<|dkrt|S|dkrt|S|dkrt|pt|St)zValidate IP addresses64r)r.r3r)r,versionrrr valid_addresssr9c Cs^g}d}d}tj}|rd}tj}d|vr7|d}|r%|ddkr%|d=n|s6|ddks3|ddkr6|d=n|||s`t|d kr`t|d|r`z t|d||d<Wn ty_Ynw|d }t |t ||}||d krvd }t|d kr|d|d7}|st |}||krd ||f}t ||}d }t ||sd |}t |t||fS)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. Fr7r6rr12832z255.255.255.255rrTzUsing '%s' for address '%s'zInvalid address '%s')rr0r)rappendrr1_dotted_netmask_to_cidrr inet_ntopr(_address4_to_networkdebugr9r) origr5r-changedr8s_typer,networkdbg_msgrrrnormalize_addresssN       rFcC t|dS)z"Opens the specified file read-onlyr)open)fnrrropen_file_read rKcCs>t|}zt\}}Wn ty|w||||dS)z=Opens the specified file read-only and a tempfile read-write.)rAorignamer tmpname)rKrrclose)rJrAr rNrrr open_filess rPcCs|dkrdS|sttjdtr|tjkrt|dSd}tjddkr1t |t |d}nt ||}|dkrAttj ddS) z~Write to the file descriptor and error out of 0 bytes written. Intended to be used with open_files() and close_files().r NzNot a valid file descriptorrasciiz"Could not write to file descriptor) OSErrorerrnoENOENT msg_outputsysstdoutfilenowrite version_infoosbytesEIO)fdoutrcrrr write_to_files    rcTcCsX|dt|d|r#t|d|dt|d|dt|ddS)zuCloses the specified files (as returned by open_files), and update original file with the temporary file. rAr rMrNN)rOr]shutilcopystatcopyunlink)fnsupdaterrr close_filess rjc Csnt|z tj|tjtjdd}Wnty)}z dt|gWYd}~Sd}~ww|d}|jt|gS)z!Try to execute the given command.T)rYstderruniversal_newlinesNr) r@ subprocessPopenPIPESTDOUTrTstr communicate returncode)commandspexrarrrcmds   rxc Cspztj|tjd}tj||jd}Wnty*}z dt|gWYd}~Sd}~ww|d}|jt|gS)z#Try to pipe command1 into command2.)rY)stdinrmNr)rnrorprYrTrrrsrt)command1command2sp1sp2rwrarrrcmd_pipe$s r~cCsz|j}Wn ty|}Ynwz|dd}Wn ty$|}Ynwtr3ttjr3||n|t || dS)zQImplement our own print statement that will output utf-8 when appropriate.utf-8ignoreN) bufferrencoderWinspectisclassioStringIOr[r^flush)outputswriterrarrr_print2s     rcCs>z ttjd|Wn tyYnw|rtddSdS)zPrint error message and exitz ERROR: %s rN)rrXrkIOErrorexit)rado_exitrrrerrorGs rcCs,z ttjd|WdStyYdSw)zPrint warning messagez WARN: %s N)rrXrkrrarrrr%Rs  r%cCsTtr |tjkr t}z|rt|d|WdSt|d|WdSty)YdSw)z Print messagez%s z%sN)rWrXrYrr)rarnewlinerrrmsgZs rcCs4trz ttjd|WdStyYdSwdS)zPrint debug messagez DEBUG: %s N) DEBUGGINGrrXrkrrrrrr@hs r@cCst|fdd|dS)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 Ss<d|dt||ddt|ddd|k|fS)Nz%s%s%sz  rr)rrfindr)linewordwidthrrrwszword_wrap.. )rr)textrrrr word_wrapqs rcCrG)zWord wrap to a specific widthK)r)rrrr wrap_textrLrcs dd|jfddddS)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'] cSs|rt|S|SN)isdigitintlower)trrrrszhuman_sort..csfddtd|DS)Ncsg|]}|qSrr).0cnormrr sz0human_sort....z([0-9]+))r&r)krrrrs)keyN)sort)lstrrr human_sorts rcCs|zt|}Wn tytdwtjdt|d}tj|s(td|t | d ddd d}t|S)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) rrrr]pathjoinrrisfilerrI readlinesrsplitr)mypidpidnameppidrrrget_ppids    $rcCszt|}Wn$tytd}t|YdSty*tdt|}t|w|dks3|dkr5dStj dt|d}tj |sOtd|}t|zt | d d}Wntyntd |}t|wtd ||d kr{d St|S) 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)rrrr%rrrrr]rrrrIrrr@ under_ssh)rrwarn_msgr!rexerrrrs4        rcCs8d}|rd}td|rt|dkst||krdSdS)zVerifies cidr netmasks ^[0-9]+$rFT)r&r'r)r4r5numrrrr*s $r*cCsd|rdStd|r0td|}t|dkrdS|D]}|r*t|dks*t|dkr-dSqdSdS)z.Verifies dotted quad ip addresses and netmasksFz^[0-9]+\.[0-9\.]+$z\.rT)r&r'rrr)r4r5quadsqrrrr1s   r1c Csd}|rtt||s td}zttdt|d}Wnty4ttdt|d}Ynwd}t dD]}||?d@dkrHd}q;|rNd}n|d7}q;|dkra|dkrat d|}t ||sht|S) z@Convert netmask to cidr. IPv6 dotted netmasks are not supported.r r>LFrrTrQ) rr1longstructunpackr inet_aton NameErrorrrangerrr*)r4r5cidrmbitsbits found_onenrrrr=s0      r=cCsd}|rtt||s tztd}Wn tyd}YnwtdD]}|t|kr3|dd|>O}q#tt d|}t ||sDt|S)zO}qXqKzt d} Wn t yd} Ynwt d D]}|t |kr| dd |>O} q|| @} g} t d D]}| t || d |d |d d dqttj td | d| d| d| d| d| d| d| d } d| |fS)z8Convert an IPv6 address and netmask to a network addresscs$dfddt|dddDS)zDecimal to binaryr csg|] }t|?d@qS)r)rr)ryrrrrhz9_address6_to_network..dec2bin..rrQ)rr)rcountrrrdec2binfs$z%_address6_to_network..dec2binrz8_address6_to_network: skipping address without a netmaskrrTrz>8HrmrrRrr)r@rrr2rrrrr(r)rrrrr<r>r)r,rr orig_hostnetmaskunpackedrirjrr-rrDrrr_address6_to_networkdsT     &     , rc Cs^|d}t|dkst|d|st|d}|d}|dks$|dkr&dS|}d|vrD|d}t|dks>t|d|s@t|d}|dksL|dkrNdS|r[t|rXt|sZtn t|rct|sett||rq|sqt||}|rtd||fdd}td||fdd}||kSt d||fdd}t d||fdd}||kS) z&Determine if address x is in network yrrrrz0.0.0.0z::Tr) rrr2rr.r3r*rrr?) tested_add tested_netr5r rraddress orig_networkrDrrr in_networks\   rcCsHd}dD]}tj|d}tj|rnd}q|dkr"ttjd|S)Nr )z/sbinz/binz /usr/sbinz/usr/binz/usr/local/sbinz/usr/local/biniptableszCould not find iptables)r]rrexistsrTrUrV)rdrrr_find_system_iptabless  rcCsT|durt}t|dg\}}|dkrttjd|td|}tdd|dS) zReturn iptables versionNz-VrzError running '%s'z\sz^vr r)rrxrTrUrVr&rsub)rrbrar rrrget_iptables_versions rcCsdd}|rtdkrttjd|durt}g}d}|dr$d}|td d d 7}t|d |g\}}|dkr?ttj ||||gd rL| d |||gdrY| dt|d|gt|d|g\}}|dkrsttj ||S)z[Return capabilities set for netfilter to support new features. Callers must be root.cSs*|d|g}t||\}}|dkrdSdS)Nz-ArTF)rx)rchainruleargsrbrarrrtest_caps z,get_netfilter_capabilities..test_caprz Must be rootNz ufw-caps-test ip6tableszufw6-caps-testr )prefixdirz-N)-m conntrack --ctstateNEWrrecentz--setz recent-set) rrrrrrz--updatez --seconds30z --hitcountr6z recent-updatez-Fz-X) r]getuidrTrUEPERMrendswithrrxrVr<)r do_checksrcapsrrbrarrrget_netfilter_capabilitiess,      r cCst|}t}|D]}|ds|dsq |}|d}|ddd}t}d|dddd|d<|d |d <|d d d|d <|d dkrZ|d |d<n |d d d|d<||vrut||<g|||<n |||vrg|||<||||q |S)z:Get and parse netstat the output from get_netstat_output()rrrr:rQNladdrrRuidrrr-r)get_netstat_outputdict splitlines startswithrrr<)r5netstat_outputrrr rritemrrrparse_netstat_output's,       rc s$d}|r[d}tj|sttjd|t|D]5}||dkrOd fddt dt dd D}d  d krOd |t d  d f}q|dkrZttjdn0ttjtj}ztt|dtd|dddd}Wn tyttjdwt||dS)zGet IP address for interfacer /proc/net/if_inet6'%s' does not existrr c g|] }d||dqSrrrrrr rrr[ z"get_ip_from_if..rrr80rrNo such devicei256sN)r]rrrTrUrVrIrrrrrrrrENODEVrr0 SOCK_DGRAMrfcntlioctlrZrrrrF)ifnamer5r,procrrrrrget_ip_from_ifMs8      r(c sZd}d}t|r d}d}n t|sttjdtj|s%ttj d|d}|rzt | D]H}| d }d fd d td td d D}ddkrdd|tddf}||ksrd|vrwt||drw|}|Sq/|St | D]*}d |vrq| d d  }zt|d}Wn tyYqw||kr|}|Sq|S)zGet interface for IP addressFz /proc/net/devTrrrr rr crrrrrrrrrz"get_if_from_ip..rrrrrrr)r.r3rrUr"r]rrrTrVrIrrstriprrrrrrr()r,r5r'matchedrr&tmp_addriprrrget_if_from_ipmsR     r-c Cstd}|td}t}|D]n}||sqtjd|d}t |tj tj Bs.qd}z t tjd|d}Wn t yFYnwzt|}Wn t yWYqw|D]&}zttj||d}Wn t ysYqZwd|tj|f||<qZq|S)zGet inodes of files in /procrrr`r rrr)r]listdirrr&compilerr'rraccessF_OKR_OKreadlinkrrbasename) proc_filespatinodesrfd_pathexe_pathdirsrinoderrr_get_proc_inodess<      r<c Csddddddddd d d d }d dddd}tjd|}t|tjtjBs(tg}d}t|}|D]L}| }|s?d}q4|t ||dd} | drRd} n | dr\| d kr\q4||d d\} } ||d} ||d} | | t | d| | | fq4|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) rrrRrrrrr rrRrrH) local_addrstater r;z /proc/netFTrLrrNArrKr r r;) r]rrr0r1r2rrIrrrrr<)protocol tcp_statesproc_net_fieldsrJr skipped_firstlinesrfieldsrLr rr r;rrr_read_proc_net_protocolsL     rTc sd}tdkr@dtdddD]}dfddt|d|dD7qtdfd dtdtd Dd d}|Sgfd dtdddDD] }tt|d qOtddd}|S)zDConvert an address from /proc/net/(tcp|udp)* to a normalized addressr rrrcg|] }|d|qSrrrrpaddrrrrrz(convert_proc_address..r cs g|] }||dqS)r)rrWrrrrrrTcrUrVrrWrXrrrrr.F)rrrrFr<rrr)rY convertedrr)rYr rconvert_proc_addresss$ * r]c Cst}ddg}|r|ddg7}|D]}zt|||<Wqty.td|}t|Yqwt}t|}|d}|D]0}||D])\}} } } } t |} d}t | |vr_|t | }|d|d | | f| | | |f7}qFq@|S) z5netstat-style output, without IPv6 address truncationrrtcp6udp6z!Could not get statistics for '%s'r r z%-5s %-46s %-11s %-5s %-11s %s z%s:%s) rrTrrr%r<listkeysrr]r)r5 proc_net_datarprr7 protocolsrr rr r;rLr,rrrrrs8         rcCsV|dur|S|dr"t|dkr|}|Stj||dd}|Stj||}|S)zAdd prefix to dirNrrr)rrr]rr)rrnewdirrrr _findpath&s  rfcCs4tjddkr t|dSt|jddddS)z,Take a string and convert it to a hex stringrrRhexrr)errorsrS)rXr\codecsrbinasciihexlifydecode)rrrr hex_encode4s rmcCs0tjddkr|jdddSt|dS)z,Take a hex string and convert it to a stringrrRrg)encodingr)rXr\rlrj unhexlify)hrrr hex_decode=srq /run/ufw.lockcCs$d}|st|d}t|tj|S)zCreate a blocking lockfileNw)rIr$lockfLOCK_EX)lockfiledryrunlockrrr create_lockDs  rycCs>|durdSzt|tj|WdStyYdSw)z(Free lockfile created with create_lock()N)r$rtLOCK_UNrOr)rxrrr release_lockMs r{)r)Tr)NT)F)rrF)I__doc__ __future__rrjrirUr$rrr]r&rdrrrnrX functoolsrtempfilerrrrWsupported_protocolsripv4_only_protocolsrr"r.r3r2r9rFrKrPrcrjrxr~rrr%rYrr@rrrgetpidrrr*r1r=rr?rrrrr rr(r-r<rTr]rrfrmrqryr{rrrrs    7    ' .#:4  9 & /%/#