o
    2c_"                     @   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randomrandintidflagsmax_sizeorigincompressQUESTIONsectioncountswritemac)selfr   r   r   r    r   B/var/www/html/gps/gps/lib/python3.10/site-packages/dns/renderer.py__init__M   s   


zRenderer.__init__c                 C   sV   | j | | j   g }| j D ]\}}||kr|| q|D ]}| j|= q"dS )zTruncate 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   where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 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	exception	FormError)r   r   r   r   r   _set_sectionm   s
   



zRenderer._set_sectionc                 c   s8    | j  }|V  | j  | jkr| | tjjd S N)r
   tellr   r#   r$   r%   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 s)w   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   qnamerdtyperdclassr   r   r   add_question   s   

zRenderer.add_questionc                 K   sd   |  | |   |j| j| j| jfi |}W d   n1 s"w   Y  | j|  |7  < dS )zAdd 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   rrsetkwnr   r   r   	add_rrset   s
   

zRenderer.add_rrsetc                 K   sf   |  | |   |j|| j| j| jfi |}W d   n1 s#w   Y  | j|  |7  < dS )zAdd 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.
        Nr4   )r   r   namerdatasetr6   r7   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Message	_make_optr8   
ADDITIONAL)r   edns	ednsflagspayloadoptions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$   tsigKeyr=   r>   
_make_tsigsigninttime_write_tsig)r   keynamesecretfudger   
tsig_error
other_datarequest_mac	algorithmskeyrK   _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   rG   TrH   )r   ctxrR   rS   rT   r   rU   rV   rW   rX   rY   rZ   rK   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 s:w   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'   r@   r,   r-   r
   r   r   r   r.   r/   r$   	rdatatypeTSIG
rdataclassANYr)   r   r   r   SEEK_END)r   rK   rR   rdata_startafterr   r   r   rQ      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 )zWrite 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   rd   r   r   r   r   write_header   s   zRenderer.write_headerc                 C   s
   | j  S )zReturn the wire format message.)r
   rI   rg   r   r   r   get_wire   s   
zRenderer.get_wire)Nr   r   Nr(   )__name__
__module____qualname____doc__r   r#   r'   
contextlibcontextmanagerr,   r$   rb   INr3   r8   r;   rF   rK   default_algorithmr\   r^   rQ   rh   ri   r   r   r   r   r   $   s$    
(
	



r   )rm   rn   r   r.   r   rP   dns.exceptionr$   dns.tsigr   ANSWER	AUTHORITYr@   r   r   r   r   r   <module>   s   