client-side DNS TCP

Dimitris Gravanis dimgrav at
Sat Jul 8 15:21:35 UTC 2017

Hi Stefan,

Thank you very much for your detailed input, it helped me significantly.

My main obstacle right now is to determine how are TCP/UDP headers 
implemented in Samba. I've figured out UDP, it's pretty straightforward 
for the client, but TCP is a bit more complicated and the libraries that 
include TCP definitions are a lot. I'm using source4/dns_server as my 
main guide, putting it together with talloc, tevent and tsocket. It's a 
bit of a maze :).

Regarding branches, is it ok, in terms of permissions/licensing, if I 
use a repo at my GitHub and move at at a later point?

Thanks again and enjoy your weekend,


On 07/07/2017 08:03 πμ, Stefan Metzmacher wrote:
> Hi Dimitris,
>> I'm trying to put together the standard for the client-side DNS TCP
>> calls in libcli/dns/dns.c, libdns.h and dns.h, so that I can then work
>> on switching from UDP for packages larger than 512 bytes. I'm using
>> source4/dns_server/dns_server.c and dns_server for cross-referencing and
>> to figure out how exactly should I make the client implementation.
> I'd say for dns updates we should only use tcp.
> Do you have some work in progress branch somewhere?
>> I've gone through RFC 1035/768/793/2548/7766, but I'm still getting a
>> bit overwhelmed from the custom headers and APIs that are used in Samba.
>> To my understanding, dns_server.c/.h cover the stream, socket and
>> binding over TCP and most functions from dns_server.c that handle the
>> above, could be directly implemented to libcli/dns.c, am I correct? Do I
>> use the same memory and tevent context that is used for UDP requests?
>> Both talloc and tevent have given me a bit of a hard time, information
>> overload!
> But once you get around it you'll never want to use something else:-)
>> I've also looked into PIDL and found the definition for TSIG records,
>> along with a "fake" TSIG definition, could you tell me what exactly this
>> is, since I didn't come across it in RFC 284
> dns_fake_tsig_rec is what RFC 2845 3.4.2. "TSIG Variables" is about:
> Source       Field Name       Notes
> -----------------------------------------------------------------------
> TSIG RR      NAME             Key name, in canonical wire format
> TSIG RR      CLASS            (Always ANY in the current specification)
> TSIG RR      TTL              (Always 0 in the current specification)
> TSIG RDATA   Algorithm Name   in canonical wire format
> TSIG RDATA   Time Signed      in network byte order
> TSIG RDATA   Fudge            in network byte order
> TSIG RDATA   Error            in network byte order
> TSIG RDATA   Other Len        in network byte order
> TSIG RDATA   Other Data       exactly as transmitted
> While dns_tsig_record is "RDATA" from RFC 2845 2.3. Record Format:
>        Field Name       Data Type      Notes
>        --------------------------------------------------------------
>        Algorithm Name   domain-name    Name of the algorithm
>                                        in domain name syntax.
>        Time Signed      u_int48_t      seconds since 1-Jan-70 UTC.
>        Fudge            u_int16_t      seconds of error permitted
>                                        in Time Signed.
>        MAC Size         u_int16_t      number of octets in MAC.
>        MAC              octet stream   defined by Algorithm Name.
>        Original ID      u_int16_t      original message ID
>        Error            u_int16_t      expanded RCODE covering
>                                        TSIG processing.
>        Other Len        u_int16_t      length, in octets, of
>                                        Other Data.
>        Other Data       octet stream   empty unless Error == BADTIME
> Basically the signature generation needs to use the original
> dns packet and:
> - remove the bytes from dns_tsig_record
> - count down the arcount field in the buffer
> - construct a blob using dns_fake_tsig_rec and append that
> - pass the constructed buffer to gensec_sign_packet()
> - rebuild the dns packet buffer with the signature (MAC) field of
>    dns_tsig_record filled with the signature from gensec_sign_packet().
> See dns_verify_tsig() in source4/dns_server/dns_crypto.c
> for the checking function that verifies the client request
> and dns_sign_tsig() and dns_tsig_compute_mac() for the
> MAC generated in the server response, which should be validated
> by the client.
>> I checked this
>> <>
>> tutorial as well (it's from a Greek University), though it uses Sockets,
>> it helped me put all those RFCs in perspective.
> It's good have some low level understanding, but our high level code
> should deal with all these nasty details.
> That's why we have the tdgram (for udp) and tstream (for tcp) abstractions.
> I guess for one DNS "transaction/call" (request and response) you'll
> need to have a call chain like:
> 1. prepare the request buffer:
> 2. submit the buffer with tstream_writev_send() or tdgram_sendto_send()
> 3. register a callback, which uses tstream_writev_recv() or
>    tdgram_sendto_recv() to get the result.
> 4. use tstream_read_pdu_blob_send() (similar to dns_tcp_call_loop())
>    or tdgram_recvfrom_send() (similar to dns_udp_call_loop()) to
>    wait for the servers response.
> 5. register a callback, which uses tstream_read_pdu_blob_recv() or
>    tdgram_recvfrom_recv() to get the response buffer.
> 6. parse the response buffer.
> I guess you want to implement a low level
> dns_client_call_send/recv() which takes the
> request buffer and returns the response buffer,
> it will basically cover steps 2-5.
> And then you have multiple wrapper on top
> of it, e.g. dns_client_update_send/recv()
> or dns_client_query_send/recv(), which hide
> the preparation of the request buffer (including a
> signature generation).
> metze

More information about the samba-technical mailing list