
    J*                     n    d Z ddlmZ ddlZddlZddlZddlZddlZddl	m
Z
 dZdZdZdZ G d d	e      Zy)
z*Help for building DNS wire format messages    )BytesION   )long      c                       e Zd ZdZddZd Zd Zej                  j                  fdZ
d Zd Zdd	Zej                  j                  fd
Zej                  j                  fdZd Zd Zd Zy)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, a 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)
    Nc                    t               | _        |t        j                  dd      | _        n|| _        || _        || _        || _        i | _        t        | _
        g d| _        | j                  j                  d       d| _        y)zInitialize a new renderer.Nr     )r   r   r   r   s                )r   outputrandomrandintidflagsmax_sizeorigincompressQUESTIONsectioncountswritemac)selfr   r   r   r   s        lib/third_party/dns/renderer.py__init__zRenderer.__init__M   sn     i:nnQ.DGDG
 ",'    c                    | j                   j                  |       | j                   j                          g }| j                  j	                         D ]  \  }}||k\  s|j                  |        |D ]  }| j                  |=  y)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vs        r   	_rollbackzRenderer._rollback^   ss     	MM'')DAqEz%%a( *  Aa   r   c                     | j                   |k7  r1| j                   |kD  rt        j                  j                  || _         yy)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   s     r   _set_sectionzRenderer._set_sectionm   s8     <<7"||g%mm---"DL #r   c                    | j                  t               | j                  j                         }|j	                  | j                  | j
                  | j                         | j                  j                  t        j                  d||             | j                  j                         }|| j                  k\  r+| j                  |       t        j                  j                  | j                  t        xx   dz  cc<   y)zAdd a question to the message.!HHr   N)r,   r   r   tellto_wirer   r   r   structpackr   r'   r)   r*   TooBigr   )r   qnamerdtyperdclassbeforeafters         r   add_questionzRenderer.add_question|   s     	(#!!#dkk4==$++>&++eVW=>  "DMM!NN6"--&&&H"r   c                    | j                  |       | j                  j                         } |j                  | j                  | j                  | j
                  fi |}| j                  j                         }|| j                  k\  r+| j                  |       t        j                  j                  | j                  |xx   |z  cc<   y)zAdd the rrset to the specified section.

        Any keyword arguments are passed on to the rdataset's to_wire()
        routine.
        Nr,   r   r/   r0   r   r   r   r'   r)   r*   r3   r   )r   r   rrsetkwr7   nr8   s          r   	add_rrsetzRenderer.add_rrset   s     	'"!!#EMM$++t}}dkkHRH  "DMM!NN6"--&&&G!r   c                    | j                  |       | j                  j                         } |j                  || j                  | j                  | j
                  fi |}| j                  j                         }|| j                  k\  r+| j                  |       t        j                  j                  | j                  |xx   |z  cc<   y)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.
        Nr;   )r   r   namerdatasetr=   r7   r>   r8   s           r   add_rdatasetzRenderer.add_rdataset   s     	'"!!#HT4;;t{{ #!#  "DMM!NN6"--&&&G!r   c           
      x   |t        d      z  }||dz  z  }| j                  t               | j                  j	                         }| j                  j                  t        j                  ddt        j                  j                  ||d             || j                  j	                         }|D ]  }t        j                  d|j                  d      }| j                  j                  |       | j                  j	                         }	|j                  | j                         | j                  j	                         }
|
|	z
  dk  sJ | j                  j                  |	dz
         t        j                  d	|
|	z
        }| j                  j                  |       | j                  j                  dd       	 | j                  j	                         }||z
  dk  sJ | j                  j                  |dz
         t        j                  d	||z
        }| j                  j                  |       | j                  j                  dd       | j                  j	                         }|| j                  k\  r+| j                  |       t        j                   j"                  | j$                  t        xx   d
z  cc<   y)z&Add an EDNS OPT record to the message.l   ~    z!BHHIHr   Nr.      r   !Hr   )r   r,   
ADDITIONALr   r/   r   r1   r2   r)   	rdatatypeOPTotyper0   r   r   r'   r*   r3   r   )r   edns	ednsflagspayloadoptionsr7   lstartoptstuffstartendlendr8   s                r   add_ednszRenderer.add_edns   s    	T*%%	dbj!	*%!!#&++h3==3D3Dg&/4 	5[[%%'FE399a8!!%(((*DKK(kk&&(U{U***  +D#+6!!%(  A&  ;;##%D&=5(((KKVaZ(KKdVm4EKKe$KKQ"  "DMM!NN6"--&&&J1$r   c	                     | j                   j                         }	t        j                  j	                  |	||t        t        j                               ||||||
      \  }
| _        }| j                  |
|       y)z$Add a TSIG signature to the message.)	algorithmN	r   getvaluer)   tsigsigninttimer   _write_tsig)r   keynamesecretfudger   
tsig_error
other_datarequest_macrX   s
tsig_rdatactxs               r   add_tsigzRenderer.add_tsig   sq     KK  "&)hhmmA4;4:47		4D49464>4>4?>G '4 	'I#TXs 	W-r   c
                    | j                   j                         }
t        j                  j	                  |
||t        t        j                               |||||||du d|	      \  }| _        }| j                  ||       |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.NT)rh   firstmultirX   rY   )r   rh   r`   ra   rb   r   rc   rd   re   rX   rf   rg   s               r   add_multi_tsigzRenderer.add_multi_tsig   s     KK  "&)hhmmA4;4:47		4D49464>4>4?8;:=+:>>G '4 'I#TXs 	W-
r   c           	      r   | j                  t               | j                  j                         }|j	                  | j                  | j
                  | j                         | j                  j                  t        j                  dt        j                  j                  t        j                  j                  dd             | j                  j                         }| j                  j                  |       | j                  j                         }||z
  dk  sJ || j                  k\  r+| j!                  |       t        j"                  j$                  | j                  j'                  |dz
         | j                  j                  t        j                  d||z
               | j(                  t        xx   dz  cc<   | j                  j'                  d       | j                  j                  t        j                  d| j(                  t                        | j                  j'                  dd       y )Nz!HHIHr   rF   r   rG   r   
   )r,   rH   r   r/   r0   r   r   r   r1   r2   r)   rI   TSIG
rdataclassANYr   r'   r*   r3   r   r   )r   rg   r`   r7   rdata_startr8   s         r   r_   zRenderer._write_tsig   s   *%!!#T]]DKK@&++gs}}/A/A&)nn&8&8!Q@ 	Akk&&(*%  "{"U***DMM!NN6"--&&&q)&++dEK,?@AJ1$&++dDKK
,CDEAr   c                 j   | j                   j                  d       | j                   j                  t        j                  d| j
                  | j                  | j                  d   | j                  d   | j                  d   | j                  d                | j                   j                  dd       y)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   r1   r2   r   r   r   r   s    r   write_headerzRenderer.write_header  s     	&++i$**&*kk!ndkk!n&*kk!ndkk!nF 	G 	Ar   c                 6    | j                   j                         S )zReturn the wire format message.)r   rZ   ru   s    r   get_wirezRenderer.get_wire   s     {{##%%r   )Nr   r   N)N)__name__
__module____qualname____doc__r   r'   r,   r)   rq   INr9   r?   rC   rV   r[   default_algorithmri   rm   r_   rv   rx    r   r   r	   r	   $   sr    &P"!# 36..2C2C #" "$!%H ),(B(B.& "%!;!;8.&r   r	   )r|   ior   r1   r   r^   dns.exceptionr)   dns.tsig_compatr   r   ANSWER	AUTHORITYrH   objectr	   r   r   r   <module>r      sC   $ 1        	
	
&v &r   