Strangle libbind API Reference

(Up to Strangle summary)

Strangle.libbind is as similar as possible to the standard libbind approach. The primary difference is that the two primary data structures, ns_msg and ns_rr, have become new types and that ns_name_uncompress has a different interface since it requires lots of pointers which are unavailable in Python.

Usage

Most of libbind will seem the same as the BIND API. For example, you have most of the constants and enums:

>>> from Strangle import libbind
>>> libbind.ns_t_mx
15
>>> libbind.ns_c_in
1

(Note: although most enums just map to integers, it is wiser to use the named values, as that is closer to the API and it will make the code more readable.)

The ns_msg Type

In the C API, ns_msg is a data structure, and BIND provides the ns_initparse() function to fill it from the raw message data. In Python, ns_msg is a new type. This means that to make an ns_msg object, just instantiate it like any other object, and pass it the message data. (The example uses test data shipped with the source.)

>>> rawData = file(“test/data/oreilly.com-response”).read()
>>> myMsg = libbind.ns_msg(rawData)
>>> myMsg

When that is done, you can do pretty much anything from the library:

>>> libbind.ns_msg_id(myMsg)
45753
>>> libbind.ns_msg_getflag(myMsg, libbind.ns_f_ra) # recursion available?
1
>>> libbind.ns_msg_getflag(myMsg, libbind.ns_f_aa) # answer authoritative?
1
>>> libbind.ns_msg_count(myMsg, libbind.ns_s_an) # how many returned?
2

The ns_rr Type

Similarly, ns_rr is a new type and must be instantiated by passing it the main ns_msg message, the message section, and which record in the section. For example, the following code will build an ns_rr object for the second (offset #1) authoritative name server record in the message:

>>> myRecord = libbind.ns_rr(myMsg, libbind.ns_s_ns, 1)
>>> myRecord

Again, from here you can get all of the information available from the record.

>>> libbind.ns_rr_name(myRecord)
‘oreilly.com’
>>> libbind.ns_rr_ttl(myRecord)
21600
>>> libbind.ns_rr_rdata(myRecord)
’\x03ns2\xc0Y’

You can see that the data field looks wrong, while it should say “ns2.sonic.net” in this case. That is because the DNS messages are compressed and we are still programming at the lowest level. So all that BIND gave us was the string from the actual message data. To see how to get a useful host name, see the next section.

ns_name_uncompress

The ns_name_uncompress() function is typically used to derive the full host name from the on-the-wire compressed version. However, it requires many pointers and buffers to work, and I see no obvious translation into Python. Therefore, the Python interface requires that you pass ns_name_uncompress your full ns_msg object, as well as the ns_rr record that you wish to expand.

>>> libbind.ns_name_uncompress(myMsg, myRecord)
‘ns2.sonic.net’

MX Exception

One deviation from the C usage is when uncompressing MX records. (Other records likely need this as well, but only MX is implemented.) The server preference is stored in the MX record data as the first two bytes, followed by the host name. In C, using ns_name_uncompress on MX records like this will result in an error. The Python ns_name_uncompress will instead skip over the data and return the value of the host name. To get the preference value, either extract it from the first 16 bits of the rdata value, or use the higher level Strangle library.