a
    sd__"  ã                   @   s^   d Z ddlZddlZddlZddlZddlZddlZddlZdZ	dZ
dZdZG dd„ dƒZdS )z*Help for building DNS wire format messagesé    Né   é   é   c                   @   sš   e Zd ZdZddd„Zdd„ Zd	d
„ Zejdd„ ƒZ	e
jjfdd„Zdd„ Zdd„ Zd dd„Ze
jjfdd„Ze
jjfdd„Zdd„ Zdd„ Zdd„ ZdS )!ÚRendereraù  Helper class for building DNS wire-format messages.

    Most applications can use the higher-level L{dns.message.Message}
    class and its to_wire() method to generate wire-format messages.
    This class is for those applications which need finer control
    over the generation of messages.

    Typical use::

        r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512)
        r.add_question(qname, qtype, qclass)
        r.add_rrset(dns.renderer.ANSWER, rrset_1)
        r.add_rrset(dns.renderer.ANSWER, rrset_2)
        r.add_rrset(dns.renderer.AUTHORITY, ns_rrset)
        r.add_edns(0, 0, 4096)
        r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_1)
        r.add_rrset(dns.renderer.ADDTIONAL, ad_rrset_2)
        r.write_header()
        r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac)
        wire = r.get_wire()

    output, an io.BytesIO, where rendering is written

    id: the message id

    flags: the message flags

    max_size: the maximum size of the message

    origin: the origin to use when rendering relative names

    compress: the compression table

    section: an int, the section currently being rendered

    counts: list of the number of RRs in each section

    mac: the MAC of the rendered message (if TSIG was used)
    Nr   éÿÿ  c                 C   sf   t  ¡ | _|du r"t dd¡| _n|| _|| _|| _|| _i | _	t
| _g d¢| _| j d¡ d| _dS )zInitialize a new renderer.Nr   r   )r   r   r   r   s               Ú )ÚioÚBytesIOÚoutputÚrandomZrandintÚidÚflagsÚmax_sizeÚoriginÚcompressÚQUESTIONÚsectionÚcountsÚwriteZmac)Úselfr   r   r   r   © r   ú./usr/lib/python3/dist-packages/dns/renderer.pyÚ__init__M   s    

zRenderer.__init__c                 C   sV   | j  |¡ | j  ¡  g }| j ¡ D ]\}}||kr$| |¡ q$|D ]}| j|= qDdS )z™Truncate the output buffer at offset *where*, and remove any
        compression table entries that pointed beyond the truncation
        point.
        N)r
   ÚseekÚtruncater   ÚitemsÚappend)r   ÚwhereZkeys_to_deleteÚkÚvr   r   r   Ú	_rollback^   s    
zRenderer._rollbackc                 C   s&   | j |kr"| j |krtjj‚|| _ dS )a  Set the renderer's current section.

        Sections must be rendered order: QUESTION, ANSWER, AUTHORITY,
        ADDITIONAL.  Sections may be empty.

        Raises dns.exception.FormError if an attempt was made to set
        a section value less than the current section.
        N)r   ÚdnsÚ	exceptionZ	FormError)r   r   r   r   r   Ú_set_sectionm   s    


zRenderer._set_sectionc                 c   s6   | j  ¡ }|V  | j  ¡ | jkr2|  |¡ tjj‚d S )N)r
   Útellr   r    r!   r"   ZTooBig)r   Ústartr   r   r   Ú_track_size|   s
    

zRenderer._track_sizec                 C   sr   |   t¡ |  ¡ : | | j| j| j¡ | j t 	d||¡¡ W d  ƒ n1 sR0    Y  | j
t  d7  < dS )zAdd a question to the message.z!HHNr   )r#   r   r&   Úto_wirer
   r   r   r   ÚstructÚpackr   )r   ZqnameZrdtypeZrdclassr   r   r   Úadd_question„   s
    

4zRenderer.add_questionc                 K   sd   |   |¡ |  ¡ , |j| j| j| jfi |¤Ž}W d  ƒ n1 sD0    Y  | j|  |7  < dS )zŠAdd the rrset to the specified section.

        Any keyword arguments are passed on to the rdataset's to_wire()
        routine.
        N©r#   r&   r'   r
   r   r   r   )r   r   ZrrsetÚkwÚnr   r   r   Ú	add_rrset   s    

:zRenderer.add_rrsetc                 K   sf   |   |¡ |  ¡ . |j|| j| j| jfi |¤Ž}W d  ƒ n1 sF0    Y  | j|  |7  < dS )zÁAdd the rdataset to the specified section, using the specified
        name as the owner name.

        Any keyword arguments are passed on to the rdataset's to_wire()
        routine.
        Nr+   )r   r   ÚnameZrdatasetr,   r-   r   r   r   Úadd_rdataset™   s    

ÿ$zRenderer.add_rdatasetc                 C   s6   |dM }||d> O }t jj |||¡}|  t|¡ dS )z&Add an EDNS OPT record to the message.l   ÿ~ é   N)r!   ÚmessageÚMessageZ	_make_optr.   Ú
ADDITIONAL)r   ZednsZ	ednsflagsZpayloadZoptionsZoptr   r   r   Úadd_edns§   s    zRenderer.add_ednsc	              
   C   s~   | j  ¡ }	t|tjjƒr|}
ntj |||¡}
tjj ||d|d|||¡}tj 	|	|
|d t
t ¡ ƒ|¡\}}|  ||¡ dS )z$Add a TSIG signature to the message.r   ó    N©r
   ÚgetvalueÚ
isinstancer!   ÚtsigZKeyr2   r3   Z
_make_tsigZsignÚintÚtimeÚ_write_tsig)r   ÚkeynameÚsecretÚfudger   Ú
tsig_errorÚ
other_dataÚrequest_macÚ	algorithmÚsÚkeyr:   Ú_r   r   r   Úadd_tsig°   s    
ÿÿzRenderer.add_tsigc
              
   C   s‚   | j  ¡ }
t|tjjƒr|}ntj |||	¡}tjj ||	d|d|||¡}tj 	|
||d t
t ¡ ƒ||d¡\}}|  ||¡ |S )ay  Add a TSIG signature to the message. Unlike add_tsig(), this can be
        used for a series of consecutive DNS envelopes, e.g. for a zone
        transfer over TCP [RFC2845, 4.4].

        For the first message in the sequence, give ctx=None. For each
        subsequent message, give the ctx that was returned from the
        add_multi_tsig() call for the previous message.r   r6   Tr7   )r   Úctxr>   r?   r@   r   rA   rB   rC   rD   rE   rF   r:   r   r   r   Úadd_multi_tsigÀ   s    
ÿÿzRenderer.add_multi_tsigc              
   C   sü   |   t¡ |  ¡ \ | | j| j| j¡ | j t 	dt
jjt
jjdd¡¡ | j ¡ }| | j¡ W d   ƒ n1 st0    Y  | j ¡ }| j |d ¡ | j t 	d|| ¡¡ | jt  d7  < | j d¡ | j t 	d| jt ¡¡ | j dtj¡ d S )Nz!HHIHr   r   z!Hr   é
   )r#   r4   r&   r'   r
   r   r   r   r(   r)   r!   Z	rdatatypeZTSIGÚ
rdataclassÚANYr$   r   r   r   ÚSEEK_END)r   r:   r>   Zrdata_startZafterr   r   r   r=   Ø   s    


ÿ
*
zRenderer._write_tsigc                 C   sZ   | j  d¡ | j  t d| j| j| jd | jd | jd | jd ¡¡ | j  dtj	¡ dS )z¾Write the DNS message header.

        Writing the DNS message header is done after all sections
        have been rendered, but before the optional TSIG signature
        is added.
        r   z!HHHHHHr   r   r   N)
r
   r   r   r(   r)   r   r   r   r   rN   ©r   r   r   r   Úwrite_headeré   s    þzRenderer.write_headerc                 C   s
   | j  ¡ S )zReturn the wire format message.)r
   r8   rO   r   r   r   Úget_wire÷   s    zRenderer.get_wire)Nr   r   N)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r    r#   Ú
contextlibÚcontextmanagerr&   r!   rL   ÚINr*   r.   r0   r5   r:   Zdefault_algorithmrH   rJ   r=   rP   rQ   r   r   r   r   r   $   s"   (

	

ÿ
þ
r   )rU   rV   r   r(   r   r<   Zdns.exceptionr!   Zdns.tsigr   ZANSWERZ	AUTHORITYr4   r   r   r   r   r   Ú<module>   s   