pax_global_header00006660000000000000000000000064126772553620014531gustar00rootroot0000000000000052 comment=8460237f21d10c889aaf0700a618c05546b0504b getdns-python-bindings-1.0.0b1/000077500000000000000000000000001267725536200163505ustar00rootroot00000000000000getdns-python-bindings-1.0.0b1/.gitignore000066400000000000000000000001671267725536200203440ustar00rootroot00000000000000build/ _build/ *~ *.pyc getdns.so getdns.cpython-34m.so *.save doc/_build/ doc/_build/* TAGS dist MANIFEST .pypirc \#* getdns-python-bindings-1.0.0b1/ChangeLog000066400000000000000000000017121267725536200201230ustar00rootroot00000000000000Changes in version 0.3.1 (10 April 2015) * implemented asynchronous queries, bound to Context() objects, and introduced Context.run() method. See getdns.readthedocs.org * queries now return a Result() object, with attributes. See getdns.readthedocs.org * removed leading GETDNS_ in all constants (i.e. getdns.GETDNS_RRTYPE_AAAA is now getdns.RRTYPE_AAAA) * added getdns.get_errorstr_by_id() method, making it easier to provide user-friendly error messages * prettied up printing of canonical names in Result object * str and repr printing has been added to both Context and Result objects * dead code removed * replaced instances of getdns_strerror() with getdns_get_errorstr_by_id() * fixed incorrect error return from Result construction * moved __version__ attribute from Context to top-level getdns module * made exception handling within the module more consistent * added documentation describing getdns.error * broke out query types getdns-python-bindings-1.0.0b1/Dockerfile000066400000000000000000000021621267725536200203430ustar00rootroot00000000000000FROM python:2.7 RUN set -ex \ && apt-get update && curl -fOSL "https://unbound.net/downloads/unbound-1.5.8.tar.gz" \ && curl -fOSL "https://github.com/getdnsapi/getdns/archive/v0.9.0.tar.gz" \ && mkdir -p /usr/src/unbound \ && tar -xzC /usr/src/unbound --strip-components=1 -f unbound-1.5.8.tar.gz \ && rm unbound-1.5.8.tar.gz \ && mkdir /usr/src/libgetdns \ && tar -xzC /usr/src/libgetdns --strip-components=1 -f v0.9.0.tar.gz \ && apt-get -y install libidn11-dev \ && apt-get -y install python-dev \ && cd /usr/src/unbound \ && ./configure \ && make \ && make install \ && ldconfig \ && cd /usr/src/libgetdns \ && libtoolize -ci \ && autoreconf -fi \ && ./configure \ && make \ && make install \ && ldconfig \ && mkdir -p /etc/unbound \ && unbound-anchor -a /etc/unbound/getdns-root.key \ && cd /usr/src \ && git clone https://github.com/getdnsapi/getdns-python-bindings.git \ && cd /usr/src/getdns-python-bindings \ && git checkout develop \ && python setup.py build \ && python setup.py install CMD ["python2"] getdns-python-bindings-1.0.0b1/LICENSE000066400000000000000000000027111267725536200173560ustar00rootroot00000000000000Copyright (c) 2014, Verisign, Inc., NLnet Labs All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. getdns-python-bindings-1.0.0b1/MANIFEST.in000066400000000000000000000001431267725536200201040ustar00rootroot00000000000000# file GENERATED by distutils, do NOT edit include *.c include *.h recursive-include examples *.py getdns-python-bindings-1.0.0b1/README.md000066400000000000000000000070361267725536200176350ustar00rootroot00000000000000getdns-python-bindings ====================== Python bindings for getdns * Date: 2016-03-29 * Github: https://github.com/getdnsapi/getdns-python-bindings * Current version: v1.0.0b1 External dependencies ===================== Built and tested against Python 2.7 and Python 3.4. You will need to install the Python headers and libraries - this is usually a package called "python-dev" Currently building against the getdns v1.0.0b release. getdns external dependencies include: * [libunbound from NLnet Labs](http://www.nlnetlabs.nl/projects/unbound/) version 1.4.16 or later * [libidn from the FSF](http://www.gnu.org/software/libidn/) version 1. * [libssl and libcrypto from the OpenSSL project](https://www.openssl.org/) version 0.9.7 or later. (Note: version 1.0.1 or later is required for TLS support, version 1.0.2 or later is required for TLS hostname authentication) Building ======== To build, ``` python setup.py build ```` During the development process and before the module is installed, I find it convenient to have a symlink in the current directory pointing to the library in the build directory. For example: ``` getdns.so -> build/lib.linux-i686-2.7/getdns.so ``` This is only useful if you're working on the actual bindings code; people who are using the bindings should go ahead and install. To install, ``` python setup.py install ```` We recently added Python 3 support. To build, just invoke the Python 3 interpreter rather the Python 2 interpreter (on most systems this will be "python3"). ``` python3 setup.py build ``` You will need the Python 3 development environment ("python3-dev" or "python3-devel", most often). Documentation ============= Documentation is formatted using the [sphinx](http://sphinx-doc.org/) documentation system. The html-formatted output is under the pygetdns source tree in doc/_build/html. It is also available online at [readthedocs.org] (https://getdns.readthedocs.org/) Changes from the earlier release ================================ * A number of performance improvements. * Installable via PyPi. * Removed libevent dependency * For consistency with Python 3, the Python 2 bindings now return Context() attributes as longs * TSIG support * GETDNS_AUTHENTICATION_HOSTNAME is replaced by GETDNS_AUTHENTICATION_REQUIRED (but remains available as an alias). Upstreams can now be configured with either a hostname or a SPKI pinset for TLS authentication (or both). If the GETDNS_AUTHENTICATION_REQUIRED option is used at least one piece of authentication information must be configured for each upstream, and all the configured authentication information for an upstream must validate. Older changes ============= In addition to adding Python 3 support, we've changed the callback argument to the asynchronous methods to accept a callable by name, rather than as a literal string. We're also now supporting a new transport_list attribute, an ordered (by preference) list of transport options, including TCP, UDP, TLS, and STARTTLS. There are also a number of bugfixes, including cleaning up after unbound zombies (this has been fixed in unbound as well but the code is not yet included in a distribution) and correct handling of strings encoded as getdns bindatas. Examples have been updated to work with both Python 2.x and Python 3. Please see the documentation for details on new attributes extensions, and methods. Examples ======== There are several sample scripts in the examples directory, showing how to issue different kinds of queries, how to verify the answer status and DNSSEC status, and so on. getdns-python-bindings-1.0.0b1/context.c000066400000000000000000001660641267725536200202150ustar00rootroot00000000000000/* * Copyright (c) 2014, Versign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Include. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "pygetdns.h" int context_init(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "set_from_os", 0 }; struct getdns_context *context = 0; int set_from_os = 1; /* default to True */ getdns_return_t ret; PyObject *py_context; if (!PyArg_ParseTupleAndKeywords(args, keywds, "|i", kwlist, &set_from_os)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((set_from_os > 1) || (set_from_os < 0)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_create(&context, set_from_os)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } py_context = PyCapsule_New(context, "context", 0); Py_INCREF(py_context); self->py_context = py_context; return 0; } void context_dealloc(getdns_ContextObject *self) { getdns_context *context; int status; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { return; } Py_XDECREF(self->py_context); getdns_context_destroy(context); (void)wait(&status); /* reap the process spun off by unbound */ return; } int context_set_timeout(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint64_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long)(value = PyLong_AsLong(py_value)) < 0) { #else if ((long)(value = PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_timeout(context, value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_idle_timeout(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint64_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long)(value = PyLong_AsLong(py_value)) < 0) { #else if ((long)(value = PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_idle_timeout(context, value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_resolution_type(getdns_context *context, PyObject *py_value) { getdns_return_t ret; getdns_resolution_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long long)(value = (getdns_resolution_t)PyLong_AsLong(py_value)) < 0) { #else if ((long long)(value = (getdns_resolution_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if (!((value == GETDNS_RESOLUTION_RECURSING) || (value == GETDNS_RESOLUTION_STUB))) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_resolution_type(context, value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_limit_outstanding_queries(getdns_context *context, PyObject *py_value) { getdns_return_t ret; long value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((value = PyLong_AsLong(py_value)) < 0) { #else if ((value = PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_limit_outstanding_queries(context, (uint16_t) value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_follow_redirects(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint64_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long)(value = PyLong_AsLong(py_value)) < 0) { #else if ((long)(value = PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if (!((value == GETDNS_REDIRECTS_FOLLOW) || (value == GETDNS_REDIRECTS_DO_NOT_FOLLOW))) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_follow_redirects(context, (getdns_redirects_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_append_name(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint64_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long)(value = PyLong_AsLong(py_value)) < 0) { #else if ((long)(value = PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if (!((value == GETDNS_APPEND_NAME_ALWAYS) || (value == GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE) || (value == GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE) || (value == GETDNS_APPEND_NAME_NEVER))) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_append_name(context, (getdns_append_name_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_suffix(getdns_context *context, PyObject *py_value) { getdns_list *values; getdns_return_t ret; Py_ssize_t len; PyObject *a_value; int i; if (!PyList_Check(py_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } len = PyList_Size(py_value); values = getdns_list_create(); for (i = 0 ; i < len ; i++) { getdns_bindata value; if ((a_value = PyList_GetItem(py_value, (Py_ssize_t)i)) != NULL) { #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(a_value)) { #else if (!PyString_Check(a_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 value.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(a_value), "ascii", NULL))); #else value.data = (uint8_t *)strdup(PyString_AsString(a_value)); #endif value.size = strlen((char *)value.data); getdns_list_set_bindata(values, (size_t)i, &value); } else { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } } if ((ret = getdns_context_set_suffix(context, values)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_dnssec_allowed_skew(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint32_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long)(value = (uint32_t)PyLong_AsLong(py_value)) < 0) { #else if ((long)(value = (uint32_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_dnssec_allowed_skew(context, (uint32_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_edns_maximum_udp_payload_size(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint16_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((long)(value = PyLong_AsLong(py_value)) < 0) { #else if ((long)(value = PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_edns_maximum_udp_payload_size(context, (uint16_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_edns_extended_rcode(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint8_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((value = (uint8_t)PyLong_AsLong(py_value)) < 0) { #else if ((value = (uint8_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_edns_extended_rcode(context, (uint8_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_tls_authentication(getdns_context *context, PyObject *py_value) { getdns_return_t ret; getdns_tls_authentication_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((int)(value = (getdns_tls_authentication_t)PyLong_AsLong(py_value)) < 0) { #else if ((int)(value = (getdns_tls_authentication_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_tls_authentication(context, value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } #if GETDNS_NUMERIC_VERSION > 0x00050000 int context_set_tls_query_padding_blocksize(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint16_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((value = (uint16_t)PyLong_AsLong(py_value)) < 0) { #else if ((value = (uint16_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_tls_query_padding_blocksize(context, value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } #endif #if GETDNS_NUMERIC_VERSION > 0x00050000 int context_set_edns_client_subnet_private(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint8_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((value = (uint8_t)PyLong_AsLong(py_value)) < 0) { #else if ((value = (uint8_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if (! ((value == 0) || (value == 1)) ) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_edns_client_subnet_private(context, (uint8_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } #endif int context_set_edns_version(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint8_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((value = (uint8_t)PyLong_AsLong(py_value)) < 0) { #else if ((value = (uint8_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_edns_version(context, (uint8_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_edns_do_bit(getdns_context *context, PyObject *py_value) { getdns_return_t ret; uint8_t value; #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(py_value)) { #else if (!PyInt_Check(py_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if ((value = (uint8_t)PyLong_AsLong(py_value)) < 0) { #else if ((value = (uint8_t)PyInt_AsLong(py_value)) < 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if (!((value == 0) || (value == 1))) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((ret = getdns_context_set_edns_do_bit(context, (uint8_t)value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_namespaces(getdns_context *context, PyObject *py_value) { size_t count; getdns_namespace_t *namespaces; getdns_return_t ret; int i; if (!PyList_Check(py_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((count = (int)PyList_Size(py_value)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((namespaces = malloc(sizeof(getdns_namespace_t) * count)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_MEMORY_ERROR_TEXT); return -1; } for (i = 0 ; i < count ; i++) { #if PY_MAJOR_VERSION >= 3 namespaces[i] = (getdns_namespace_t)PyLong_AsLong(PyList_GetItem(py_value, (Py_ssize_t)i)); #else namespaces[i] = (getdns_namespace_t)PyInt_AsLong(PyList_GetItem(py_value, (Py_ssize_t)i)); #endif if ((namespaces[i] < GETDNS_NAMESPACE_DNS) || (namespaces[i] > GETDNS_NAMESPACE_NIS)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } } if ((ret = getdns_context_set_namespaces(context, count, namespaces)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_dns_root_servers(getdns_context *context, PyObject *py_value) { getdns_return_t ret; getdns_list *addresses; Py_ssize_t len; int i; PyObject *an_address; PyObject *str; getdns_dict *addr_dict; int domain; unsigned char buf[sizeof(struct in6_addr)]; if (!PyList_Check(py_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } len = PyList_Size(py_value); addresses = getdns_list_create(); for (i = 0 ; i < len ; i++) { getdns_bindata addr_data; getdns_bindata addr_type; if ((an_address = PyList_GetItem(py_value, (Py_ssize_t)i)) != NULL) { if (PyDict_Size(an_address) != 2) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } addr_dict = getdns_dict_create(); if ((str = PyDict_GetItemString(an_address, "address_type")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(str)) { #else if (!PyString_Check(str)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 addr_type.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(str), "ascii", NULL))); #else addr_type.data = (uint8_t *)strdup(PyString_AsString(str)); #endif addr_type.size = strlen((char *)addr_type.data); if (strlen((char *)addr_type.data) != 4) { PyErr_SetString(getdns_error, GETDNS_RETURN_WRONG_TYPE_REQUESTED_TEXT); return -1; } if (!strncasecmp((char *)addr_type.data, "IPv4", 4)) domain = AF_INET; else if (!strncasecmp((char *)addr_type.data, "IPv6", 4)) domain = AF_INET6; else { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } getdns_dict_set_bindata(addr_dict, "address_type", &addr_type); if ((str = PyDict_GetItemString(an_address, "address_data")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(str)) { #else if (!PyString_Check(str)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 if (inet_pton(domain, PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(str), "ascii", NULL)), buf) <= 0) { #else if (inet_pton(domain, PyString_AsString(str), buf) <= 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } addr_data.data = (uint8_t *)buf; addr_data.size = (domain == AF_INET ? 4 : 16); getdns_dict_set_bindata(addr_dict, "address_data", &addr_data); getdns_list_set_dict(addresses, (size_t)i, addr_dict); } } if ((ret = getdns_context_set_dns_root_servers(context, addresses)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_dnssec_trust_anchors(getdns_context *context, PyObject *py_value) { getdns_return_t ret; getdns_list *addresses; Py_ssize_t len; int i; PyObject *an_address; if (!PyList_Check(py_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } len = PyList_Size(py_value); addresses = getdns_list_create(); for (i = 0 ; i < len ; i++) { getdns_bindata *value = 0; if ((an_address = PyList_GetItem(py_value, (Py_ssize_t)i)) != NULL) { #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(an_address)) { #else if (!PyString_Check(an_address)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } #if PY_MAJOR_VERSION >= 3 value->data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(py_value), "ascii", NULL))); #else value->data = (uint8_t *)strdup(PyString_AsString(py_value)); #endif value->size = strlen((char *)value->data); getdns_list_set_bindata(addresses, (size_t)i, value); } else { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } } if ((ret = getdns_context_set_dnssec_trust_anchors(context, addresses)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_upstream_recursive_servers(getdns_context *context, PyObject *py_value) { int len; PyObject *py_upstream; struct getdns_list *upstream_list; int i; getdns_return_t ret; if (!PyList_Check(py_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((len = (int)PyList_Size(py_value)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } upstream_list = getdns_list_create(); for (i = 0 ; i < len ; i++) { getdns_dict *a_upstream; if ((py_upstream = PyList_GetItem(py_value, (Py_ssize_t)i)) != NULL) { if ((a_upstream = getdnsify_addressdict(py_upstream)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if (getdns_list_set_dict(upstream_list, i, a_upstream) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } } else { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } } if ((ret = getdns_context_set_upstream_recursive_servers(context, upstream_list)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } int context_set_dns_transport_list(getdns_context *context, PyObject *py_value) { getdns_return_t ret; Py_ssize_t len; getdns_transport_list_t *transports; int i; if (!PyList_Check(py_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } len = PyList_Size(py_value); if ((transports = (getdns_transport_list_t *)malloc(sizeof(getdns_transport_list_t)*(int)len)) == (getdns_transport_list_t *)0) { PyErr_SetString(getdns_error, "memory allocation error"); return -1; } for ( i = 0 ; i < (int)len ; i++ ) { PyObject *py_transport; long transport; if ((py_transport = PyList_GetItem(py_value, (Py_ssize_t)i)) != NULL) { transport = PyLong_AsLong(py_transport); if ((transport < GETDNS_TRANSPORT_UDP) || (transport > GETDNS_TRANSPORT_TLS)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } transports[i] = (getdns_transport_list_t)transport; } else { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } } if ((ret = getdns_context_set_dns_transport_list(context, (size_t)len, transports)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return -1; } return 0; } PyObject * context_getattro(PyObject *self, PyObject *nameobj) { getdns_ContextObject *myself = (getdns_ContextObject *)self; struct getdns_context *context; getdns_dict *api_info; getdns_dict *all_context; getdns_return_t ret; char *attrname; #if PY_MAJOR_VERSION >= 3 attrname = PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(nameobj), "ascii", NULL)); #else attrname = PyString_AsString(nameobj); #endif context = PyCapsule_GetPointer(myself->py_context, "context"); if (!strncmp(attrname, "append_name", strlen("append_name"))) { getdns_append_name_t value; if ((ret = getdns_context_get_append_name(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "dns_root_servers", strlen("dns_root_servers"))) { PyObject *py_rootservers; getdns_list *dns_root_servers; if ((ret = getdns_context_get_dns_root_servers(context, &dns_root_servers)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (dns_root_servers == (getdns_list *)0) { Py_RETURN_NONE; } else { if ((py_rootservers = glist_to_plist(dns_root_servers)) == NULL) { PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return NULL; } return py_rootservers; } } if (!strncmp(attrname, "suffix", strlen("suffix"))) { PyObject *py_suffix; getdns_list *suffix; if ((ret = getdns_context_get_suffix(context, &suffix)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_suffix = glist_to_plist(suffix)) == NULL) PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return py_suffix; } api_info = getdns_context_get_api_information(context); if (!strncmp(attrname, "resolution_type", strlen("resolution_type"))) { getdns_resolution_t value; if ((ret = getdns_context_get_resolution_type(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if ((ret = getdns_dict_get_dict(api_info, "all_context", &all_context)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (!strncmp(attrname, "implementation_string", strlen("implementation_string"))) { getdns_bindata *implementation_string; if ((ret = getdns_dict_get_bindata(api_info, "implementation_string", &implementation_string)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromStringAndSize((char *)implementation_string->data, (Py_ssize_t)implementation_string->size); #else return PyString_FromStringAndSize((char *)implementation_string->data, (Py_ssize_t)implementation_string->size); #endif } if (!strncmp(attrname, "version_string", strlen("version_string"))) { getdns_bindata *version_string; if ((ret = getdns_dict_get_bindata(api_info, "version_string", &version_string)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromStringAndSize((char *)version_string->data, (Py_ssize_t)version_string->size); #else return PyString_FromStringAndSize((char *)version_string->data, (Py_ssize_t)version_string->size); #endif } if (!strncmp(attrname, "timeout", strlen("timeout"))) { uint64_t value; if ((ret = getdns_context_get_timeout(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "idle_timeout", strlen("idle_timeout"))) { uint64_t timeout; if ((ret = getdns_context_get_idle_timeout(context, &timeout)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)timeout); } if (!strncmp(attrname, "dns_transport_list", strlen("dns_transport_list"))) { getdns_transport_list_t *transports; PyObject *py_transports; size_t transport_count; int i; if ((ret = getdns_context_get_dns_transport_list(context, &transport_count, &transports)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_transports = PyList_New((Py_ssize_t)transport_count)) == NULL) { PyErr_SetString(getdns_error, "Could not create PyList"); return NULL; } for ( i = 0 ; i < transport_count ; i++ ) { PyList_SetItem(py_transports, (Py_ssize_t)i, PyLong_FromLong((long)transports[i])); } return py_transports; } if (!strncmp(attrname, "limit_outstanding_queries", strlen("limit_outstanding_queries"))) { uint16_t value; if ((ret = getdns_context_get_limit_outstanding_queries(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong(value); } if (!strncmp(attrname, "tls_query_padding_blocksize", strlen("tls_query_padding_blocksize"))) { uint16_t tls_query_padding_blocksize; if ((ret = getdns_context_get_tls_query_padding_blocksize(context, &tls_query_padding_blocksize)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)tls_query_padding_blocksize); } if (!strncmp(attrname, "edns_client_subnet_private", strlen("edns_client_subnet_private"))) { uint8_t edns_client_subnet_private; if ((ret = getdns_context_get_edns_client_subnet_private(context, &edns_client_subnet_private)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)edns_client_subnet_private); } if (!strncmp(attrname, "tls_authentication", strlen("tls_authentication"))) { getdns_tls_authentication_t value; if ((ret = getdns_context_get_tls_authentication(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "follow_redirects", strlen("follow_redirects"))) { getdns_redirects_t value; if ((ret = getdns_context_get_follow_redirects(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "dnssec_trust_anchors", strlen("dnssec_trust_anchors"))) { getdns_list *value; PyObject *py_trust_anchors; if ((ret = getdns_context_get_dnssec_trust_anchors(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } py_trust_anchors = glist_to_plist(value); return(py_trust_anchors); } if (!strncmp(attrname, "dnssec_allowed_skew", strlen("dnssec_allowed_skew"))) { uint32_t value; if ((ret = getdns_context_get_dnssec_allowed_skew(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "edns_maximum_udp_payload_size", strlen("edns_maximum_udp_payload_size"))) { uint16_t value; if ((ret = getdns_context_get_edns_maximum_udp_payload_size(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "edns_extended_rcode", strlen("edns_extended_rcode"))) { uint8_t value; if ((ret = getdns_context_get_edns_extended_rcode(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "edns_version", strlen("edns_version"))) { uint8_t value; if ((ret = getdns_context_get_edns_version(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "edns_do_bit", strlen("edns_do_bit"))) { uint8_t value; if ((ret = getdns_context_get_edns_do_bit(context, &value)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return PyLong_FromLong((long)value); } if (!strncmp(attrname, "namespaces", strlen("namespaces"))) { PyObject *py_namespaces; getdns_namespace_t *namespaces; getdns_return_t ret; size_t count; int i; if ((ret = getdns_context_get_namespaces(context, &count, &namespaces)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (count) { py_namespaces = PyList_New(count); for (i = 0 ; i < count ; i++) PyList_SetItem(py_namespaces, i, PyLong_FromLong((long)namespaces[i])); return py_namespaces; } else Py_RETURN_NONE; } if (!strncmp(attrname, "upstream_recursive_servers", strlen("upstream_recursive_servers"))) { PyObject *py_upstream_servers; getdns_list *upstream_list; getdns_return_t ret; if ((ret = getdns_context_get_upstream_recursive_servers(context, &upstream_list)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_upstream_servers = glist_to_plist(upstream_list)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } return py_upstream_servers; } if (!strncmp(attrname, "num_pending_requests", strlen("num_pending_requests"))) { uint32_t num_pending_requests; num_pending_requests = getdns_context_get_num_pending_requests(context, 0); return PyLong_FromLong((long)num_pending_requests); } return PyObject_GenericGetAttr((PyObject *)self, nameobj); } /* * must be in alphabetical order by attribute name. attribute name and the * name of its setter function */ struct setter_table setters[] = { { "append_name", context_set_append_name }, { "dnssec_allowed_skew", context_set_dnssec_allowed_skew }, { "dns_root_servers", context_set_dns_root_servers }, { "dns_transport_list", context_set_dns_transport_list }, { "edns_client_subnet_private", context_set_edns_client_subnet_private }, { "edns_do_bit", context_set_edns_do_bit }, { "edns_extended_rcode", context_set_edns_extended_rcode }, { "edns_maximum_udp_payload_size", context_set_edns_maximum_udp_payload_size }, { "edns_version", context_set_edns_version }, { "idle_timeout", context_set_idle_timeout }, { "follow_redirects", context_set_follow_redirects }, { "limit_outstanding_queries", context_set_limit_outstanding_queries }, { "namespaces", context_set_namespaces }, { "resolution_type", context_set_resolution_type }, { "suffix", context_set_suffix }, { "timeout", context_set_timeout }, { "tls_authentication", context_set_tls_authentication }, { "tls_query_padding_blocksize", context_set_tls_query_padding_blocksize }, { "upstream_recursive_servers", context_set_upstream_recursive_servers }, }; #define NSETTERS (sizeof(setters) / sizeof(setters[0])) static int compare_setters(const void *key, const void *entry) { struct setter_table *s1 = (struct setter_table *)key; struct setter_table *s2 = (struct setter_table *)entry; return strcmp(s1->name, s2->name); } int context_setattro(PyObject *self, PyObject *attrname, PyObject *py_value) { getdns_ContextObject *myself = (getdns_ContextObject *)self; struct getdns_context *context; char *name; struct setter_table key; struct setter_table *setter; #if PY_MAJOR_VERSION >= 3 name = PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(attrname), "ascii", NULL)); #else name = PyString_AsString(attrname); #endif key.name = name; if ((context = PyCapsule_GetPointer(myself->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return -1; } if ((setter = bsearch(&key, setters, NSETTERS, sizeof(struct setter_table), compare_setters)) != NULL) return setter->setter(context, py_value); /* * if it's not an attribute we define, throw an error. The * tradeoff is between ease of use and extensibility, and * given that people are getting attribute names wrong this * is worth trying. Back it out if there are complaints */ PyErr_SetString(PyExc_AttributeError, "No such attribute"); return -1; } PyObject * context_get_attributes(getdns_ContextObject *self, PyObject *unused) { int i; PyObject *py_attr_list = PyList_New(NSETTERS); for (i = 0 ; i < NSETTERS ; i++) { #if PY_MAJOR_VERSION >= 3 (void)PyList_SetItem(py_attr_list, (Py_ssize_t) i, PyUnicode_FromString(setters[i].name)); #else (void)PyList_SetItem(py_attr_list, (Py_ssize_t) i, PyString_FromString(setters[i].name)); #endif } return py_attr_list; } PyObject * context_run(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { getdns_context *context; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } getdns_context_run(context); Py_RETURN_NONE; } PyObject * context_cancel_callback(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "transaction_id", 0 }; getdns_context *context; getdns_transaction_t tid = 0; getdns_return_t ret; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } if (!PyArg_ParseTupleAndKeywords(args, keywds, "L", kwlist, &tid)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if ((ret = getdns_cancel_callback(context, tid)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } Py_RETURN_NONE; } PyObject * context_str(PyObject *self) { getdns_ContextObject *myself = (getdns_ContextObject *)self; struct getdns_context *context; getdns_dict *api_info; char *str_api_dict; context = PyCapsule_GetPointer(myself->py_context, "context"); api_info = getdns_context_get_api_information(context); if ((str_api_dict = getdns_print_json_dict(api_info, 0)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 return(PyUnicode_FromString(str_api_dict)); #else return(PyString_FromString(str_api_dict)); #endif } PyObject * context_general(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "name", "request_type", "extensions", "userarg", "transaction_id", "callback", 0 }; getdns_context *context; char *name; uint16_t request_type; PyDictObject *extensions_obj = 0; struct getdns_dict *extensions_dict = 0; getdns_return_t ret; void *userarg = 0; getdns_transaction_t tid = 0; PyObject *callback = 0; struct getdns_dict *resp; PyObject *callback_func; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } if (!PyArg_ParseTupleAndKeywords(args, keywds, "sH|OsLO", kwlist, &name, &request_type, &extensions_obj, &userarg, &tid, &callback)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if (extensions_obj) { if ((extensions_dict = extensions_to_getdnsdict(extensions_obj)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } } if (callback) { userarg_blob *blob; if ((blob = (userarg_blob *)malloc(sizeof(userarg_blob))) == (userarg_blob *)0) { PyErr_SetString(getdns_error, "Memory allocation failed"); return NULL; } if (userarg) strncpy(blob->userarg, userarg, BUFSIZ-1); #if PY_MAJOR_VERSION >= 3 if (PyUnicode_Check(callback)) { if ((callback_func = get_callback("__main__", PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(callback), "ascii", NULL)))) == (PyObject *)NULL) { #else if (PyString_Check(callback)) { if ((callback_func = get_callback("__main__", PyString_AsString(callback))) == (PyObject *)NULL) { #endif PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return NULL; } blob->callback_func = callback_func; } else if (PyCallable_Check(callback)) { blob->callback_func = callback; } else { PyErr_SetString(getdns_error, "Invalid callback value"); return NULL; } if ((ret = getdns_general(context, name, request_type, extensions_dict, (void *)blob, &tid, callback_shim)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 return(PyLong_FromUnsignedLong((long)tid)); #else return(PyInt_FromLong((long)tid)); #endif } else { if ((ret = getdns_general_sync(context, name, request_type, extensions_dict, &resp)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return result_create(resp); } } PyObject * context_address(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "name", "extensions", "userarg", "transaction_id", "callback", 0 }; getdns_return_t ret; getdns_context *context; char *name; PyObject *callback_func; PyDictObject *extensions_obj = 0; struct getdns_dict *extensions_dict = 0; char *userarg = 0; getdns_transaction_t tid; PyObject *callback = 0; struct getdns_dict *resp; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|OsLO", kwlist, &name, &extensions_obj, &userarg, &tid, &callback)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if (extensions_obj) { if ((extensions_dict = extensions_to_getdnsdict(extensions_obj)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } } if (callback) { userarg_blob *blob; if ((blob = (userarg_blob *)malloc(sizeof(userarg_blob))) == (userarg_blob *)0) { PyErr_SetString(getdns_error, "Memory allocation failed"); return NULL; } if (userarg) { strncpy(blob->userarg, userarg, BUFSIZ-1); } else { blob->userarg[0] = 0; } #if PY_MAJOR_VERSION >= 3 if (PyUnicode_Check(callback)) { if ((callback_func = get_callback("__main__", PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(callback), "ascii", NULL)))) == (PyObject *)NULL) { #else if (PyString_Check(callback)) { if ((callback_func = get_callback("__main__", PyString_AsString(callback))) == (PyObject *)NULL) { #endif PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return NULL; } blob->callback_func = callback_func; } else if (PyCallable_Check(callback)) { blob->callback_func = callback; } else { PyErr_SetString(getdns_error, "Invalid callback value"); return NULL; } if ((ret = getdns_address(context, name, extensions_dict, (void *)blob, &tid, callback_shim)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 return(PyLong_FromUnsignedLong((long)tid)); #else return(PyInt_FromLong((long)tid)); #endif } else { if ((ret = getdns_address_sync(context, name, extensions_dict, &resp)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return result_create(resp); } } PyObject * context_hostname(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "address", "extensions", "userarg", "transaction_id", "callback", 0 }; void *address; PyDictObject *extensions_obj = 0; struct getdns_dict *extensions_dict = 0; void *userarg = 0; getdns_transaction_t tid; PyObject* callback = 0; struct getdns_dict *resp; getdns_context *context; struct getdns_dict *addr_dict; getdns_return_t ret; PyObject *callback_func; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OsLO", kwlist, &address, &extensions_obj, &userarg, &tid, &callback)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if (extensions_obj) { if ((extensions_dict = extensions_to_getdnsdict(extensions_obj)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } } if ((addr_dict = getdnsify_addressdict((PyObject *)address)) == NULL) { PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return NULL; } if (callback) { userarg_blob *blob; if ((blob = (userarg_blob *)malloc(sizeof(userarg_blob))) == (userarg_blob *)0) { PyErr_SetString(getdns_error, "Memory allocation failed"); return NULL; } if (userarg) { strncpy(blob->userarg, userarg, BUFSIZ-1); } else { blob->userarg[0] = 0; } #if PY_MAJOR_VERSION >= 3 if (PyUnicode_Check(callback)) { if ((callback_func = get_callback("__main__", PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(callback), "ascii", NULL)))) == (PyObject *)NULL) { #else if (PyString_Check(callback)) { if ((callback_func = get_callback("__main__", PyString_AsString(callback))) == (PyObject *)NULL) { #endif PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return NULL; } blob->callback_func = callback_func; } else if (PyCallable_Check(callback)) { blob->callback_func = callback; } else { PyErr_SetString(getdns_error, "Invalid callback value"); return NULL; } if ((ret = getdns_hostname(context, addr_dict, extensions_dict, (void *)blob, &tid, callback_shim)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 return(PyLong_FromUnsignedLong((long)tid)); #else return(PyInt_FromLong((long)tid)); #endif } else { if ((ret = getdns_hostname_sync(context, addr_dict, extensions_dict, &resp)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return result_create(resp); } } PyObject * context_service(getdns_ContextObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "name", "extensions", "userarg", "transaction_id", "callback", 0 }; char *name; PyDictObject *extensions_obj = 0; struct getdns_dict *extensions_dict = 0; getdns_return_t ret; void *userarg; getdns_transaction_t tid; PyObject *callback = 0; struct getdns_dict *resp; getdns_context *context; PyObject *callback_func; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|OsLO", kwlist, &name, &extensions_obj, &userarg, &tid, &callback)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if (extensions_obj) { if ((extensions_dict = extensions_to_getdnsdict(extensions_obj)) == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } } if (callback) { userarg_blob *blob; if ((blob = (userarg_blob *)malloc(sizeof(userarg_blob))) == (userarg_blob *)0) { PyErr_SetString(getdns_error, "Memory allocation failed"); return NULL; } if (userarg) { strncpy(blob->userarg, userarg, BUFSIZ-1); } else { blob->userarg[0] = 0; } #if PY_MAJOR_VERSION >= 3 if (PyUnicode_Check(callback)) { if ((callback_func = get_callback("__main__", PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(callback), "ascii", NULL)))) == (PyObject *)NULL) { #else if (PyString_Check(callback)) { if ((callback_func = get_callback("__main__", PyString_AsString(callback))) == (PyObject *)NULL) { #endif PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return NULL; } blob->callback_func = callback_func; } else if (PyCallable_Check(callback)) { blob->callback_func = callback; } else { PyErr_SetString(getdns_error, "Invalid callback value"); return NULL; } if ((ret = getdns_service(context, name, extensions_dict, (void *)blob, &tid, callback_shim)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 return(PyLong_FromUnsignedLong((long)tid)); #else return(PyInt_FromLong((long)tid)); #endif } else { if ((ret = getdns_service_sync(context, name, extensions_dict, &resp)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } return result_create(resp); } } PyObject * context_get_api_information(getdns_ContextObject *self, PyObject *unused) { getdns_context *context; getdns_dict *api_info; PyObject *py_api; getdns_bindata *version_string; getdns_bindata *imp_string; uint32_t resolution_type; getdns_dict *all_context; PyObject *py_all_context; getdns_return_t ret; if ((context = PyCapsule_GetPointer(self->py_context, "context")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_BAD_CONTEXT_TEXT); return NULL; } py_api = PyDict_New(); api_info = getdns_context_get_api_information(context); if ((ret = getdns_dict_get_bindata(api_info, "version_string", &version_string)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 if (PyDict_SetItemString(py_api, "version_string", PyUnicode_FromStringAndSize((char *)version_string->data, (Py_ssize_t)version_string->size))) { #else if (PyDict_SetItemString(py_api, "version_string", PyString_FromStringAndSize((char *)version_string->data, (Py_ssize_t)version_string->size))) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((ret = getdns_dict_get_bindata(api_info, "implementation_string", &imp_string)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 if (PyDict_SetItemString(py_api, "implementation_string", PyUnicode_FromStringAndSize((char *)imp_string->data, (Py_ssize_t)imp_string->size))) { #else if (PyDict_SetItemString(py_api, "implementation_string", PyString_FromStringAndSize((char *)imp_string->data, (Py_ssize_t)imp_string->size))) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((ret = getdns_dict_get_int(api_info, "resolution_type", &resolution_type)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 if (PyDict_SetItemString(py_api, "resolution_type", PyLong_FromLong((long)resolution_type))) { #else if (PyDict_SetItemString(py_api, "resolution_type", PyInt_FromLong((long)resolution_type))) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((ret = getdns_dict_get_dict(api_info, "all_context", &all_context)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_all_context = gdict_to_pdict(all_context)) == NULL) { PyErr_SetString(getdns_error, "Unable to convert all_context dict"); return NULL; } PyDict_SetItemString(py_api, "all_context", py_all_context); return(py_api); } getdns-python-bindings-1.0.0b1/context_util.c000066400000000000000000000073621267725536200212450ustar00rootroot00000000000000/* * Copyright (c) 2015, Versign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Include. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "pygetdns.h" /* * Get the address of the Python function object * being passed in by name to the context * query methods */ PyObject * get_callback(char *py_main, char *callback) { PyObject *main_module; PyObject *main_dict; PyObject *callback_func; if ((main_module = PyImport_AddModule(py_main)) == 0) { PyErr_SetString(getdns_error, "No 'main'"); return NULL; } main_dict = PyModule_GetDict(main_module); if ((callback_func = PyDict_GetItemString(main_dict, callback)) == 0) { PyErr_SetString(getdns_error, "callback not found\n"); return NULL; } if (!PyCallable_Check(callback_func)) { PyErr_SetString(getdns_error, "The callback function is not runnable"); return NULL; } return callback_func; } void callback_shim(struct getdns_context *context, getdns_callback_type_t type, struct getdns_dict *response, void *userarg, getdns_transaction_t tid) { PyObject *py_callback_type; PyObject *py_result; PyObject *py_tid; PyObject *py_userarg; userarg_blob *u = (userarg_blob *)userarg; #if PY_MAJOR_VERSION >= 3 if ((py_callback_type = PyLong_FromLong((long)type)) == NULL) { #else if ((py_callback_type = PyInt_FromLong((long)type)) == NULL) { #endif PyObject *err_type, *err_value, *err_traceback; PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Restore(err_type, err_value, err_traceback); return; } if (type == GETDNS_CALLBACK_CANCEL) { py_result = Py_None; py_tid = Py_None; py_userarg = Py_None; } else { py_result = result_create(response); #if PY_MAJOR_VERSION >= 3 py_tid = PyLong_FromLong((long)tid); #else py_tid = PyInt_FromLong((long)tid); #endif if (u->userarg) #if PY_MAJOR_VERSION >= 3 py_userarg = PyUnicode_FromString(u->userarg); #else py_userarg = PyString_FromString(u->userarg); #endif else py_userarg = Py_None; } PyObject_CallFunctionObjArgs(u->callback_func, py_callback_type, py_result, py_userarg, py_tid, NULL); } getdns-python-bindings-1.0.0b1/doc/000077500000000000000000000000001267725536200171155ustar00rootroot00000000000000getdns-python-bindings-1.0.0b1/doc/Makefile000066400000000000000000000127041267725536200205610ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pygetdns.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pygetdns.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/pygetdns" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pygetdns" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." getdns-python-bindings-1.0.0b1/doc/conf.py000066400000000000000000000171621267725536200204230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # getdns documentation build configuration file, created by # sphinx-quickstart on Mon Apr 7 17:05:52 2014. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'getdns' copyright = u'2014, Verisign Labs, NLnet Labs' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = 'v1.0beta' # The full version, including alpha/beta/rc tags. release = 'v1.0.0b1 # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'getdnsdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'getdns.tex', u'getdns Documentation', u'Melinda Shore, Gowri Visweswaran', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'getdns', u'getdns Documentation', [u'Melinda Shore, Gowri Visweswaran'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'getdns', u'getdns Documentation', u'Melinda Shore, Gowri Visweswaran', 'getdns', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' getdns-python-bindings-1.0.0b1/doc/exceptions.rst000066400000000000000000000025501267725536200220320ustar00rootroot00000000000000:mod:`getdns` exceptions ============================= .. module:: getdns :synopsis: getdns exception description and explanation .. sectionauthor:: Melinda Shore getdns exceptions ----------------- .. py:exception:: getdns.error getdns will throw an exception, ``getdns.error``, under certain conditions. Those conditions include: * a required parameter having a bad value * a badly-formed domain name in the query * a bad ``Context()`` object * a failed ``Context()`` update * an out-of-bounds error for a getdns data structure * requesting an extension that doesn't exist * requesting DNSSEC validation while using stub resolution Please note that a successful return from a getdns method does `not` indicate that the query returned the records being requested, but rather that the query is formed correctly and has been submitted to the DNS. A getdns exception is typically the result of a coding error. getdns will set the exception message to a diagnostic string, which may be examined for help in resolving the error. Example ------- :: import getdns, sys c = getdns.Context() try: results = c.address('www.example.com', foo='bar') except getdns.error, e: print(str(e)) sys.exit(1) This will result in "A required parameter had an invalid value" being printed to the screen. getdns-python-bindings-1.0.0b1/doc/functions.rst000066400000000000000000000522211267725536200216610ustar00rootroot00000000000000:mod:`getdns` reference ================================== .. module:: getdns :synopsis: getdns objects, methods, and attributes .. sectionauthor:: Melinda Shore getdns contexts --------------- This section describes the *getdns* Context object, as well as its as its methods and attributes. .. py:class:: Context([set_from_os]) Creates a *context*, an opaque object which describes the environment within which a DNS query executes. This includes namespaces, root servers, resolution types, and so on. These are accessed programmatically through the attributes described below. Context() takes one optional constructor argument. ``set_from_os`` is an integer and may take the value either 0 or 1. If 1, which most developers will want, getdns will populate the context with default values for the platform on which it's running. The :class:`Context` class has the following public read/write attributes: .. py:attribute:: append_name Specifies whether to append a suffix to the query string before the API starts resolving a name. Its value must be one of ``getdns.APPEND_NAME_ALWAYS``, ``getdns.APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE``, ``getdns.APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE``, or ``getdns.APPEND_NAME_NEVER``. This controls whether or not to append the suffix given by :attr:`suffix`. .. py:attribute:: dns_root_servers The value of `dns_root_servers` is a list of dictionaries containing addresses to be used for looking up top-level domains. Each dict in the list contains two key-value pairs: * address_data: a string representation of an IPv4 or IPv6 address * address_type: either the string "IPv4" or "IPv6" For example, the addresses list could look like >>> addrs = [ { 'address_data': '2001:7b8:206:1::4:53', 'address_type': 'IPv6' }, ... { 'address_data': '65.22.9.1', 'address_type': 'IPv4' } ] >>> mycontext.dns_root_servers = addrs .. py:attribute:: dns_transport_list An ordered list of transport options to be used for DNS lookups, ordered by preference (first choice as list element 0, second as list element 1, and so on). The possible values are ``getdns.TRANSPORT_UDP``, ``getdns.TRANSPORT_TCP``, and ``getdns.TRANSPORT_TLS``. .. py:attribute:: dnssec_allowed_skew Its value is the number of seconds of skew that is allowed in either direction when checking an RRSIG's Expiration and Inception fields. The default is 0. .. py:attribute:: dnssec_trust_anchors Its value is a list of DNSSEC trust anchors, expressed as RDATAs from DNSKEY resource records. .. py:attribute:: edns_client_subnet_private May be set to 0 or 1. When 1, requests upstreams not to reveal query's originating network. .. py:attribute:: edns_do_bit Its value must be an integer valued either 0 or 1. The default is 0. .. py:attribute:: edns_extended_rcode Its value must be an integer between 0 and 255, inclusive. The default is 0. .. py:attribute:: edns_maximum_udp_payload_size Its value must be an integer between 512 and 65535, inclusive. The default is 512. .. py:attribute:: edns_version Its value must be an integer between 0 and 255, inclusive. The default is 0. .. py:attribute:: follow_redirects Specifies whether or not DNS queries follow redirects. The value must be one of ``getdns.REDIRECTS_FOLLOW`` for normal following of redirects though CNAME and DNAME; or ``getdns.REDIRECTS_DO_NOT_FOLLOW`` to cause any lookups that would have gone through CNAME and DNAME to return the CNAME or DNAME, not the eventual target. .. py:attribute:: idle_timeout The idle timeout for TCP connections. .. py:attribute:: implementation_string A string describing the implementation of the underlying getdns library, retrieved from libgetdns. Currently "https://getdnsapi.net" .. py:attribute:: limit_outstanding_queries Specifies `limit` (an integer value) on the number of outstanding DNS queries. The API will block itself from sending more queries if it is about to exceed this value, and instead keep those queries in an internal queue. The a value of 0 indicates that the number of outstanding DNS queries is unlimited. .. py:attribute:: namespaces The `namespaces` attribute takes an ordered list of namespaces that will be queried. (*Important: this context setting is ignored for the getdns.general() function; it is used for the other functions.*) The allowed values are ``getdns.NAMESPACE_DNS``, ``getdns.NAMESPACE_LOCALNAMES``, ``getdns.NAMESPACE_NETBIOS``, ``getdns.NAMESPACE_MDNS``, and ``getdns.NAMESPACE_NIS``. When a normal lookup is done, the API does the lookups in the order given and stops when it gets the first result; a different method with the same result would be to run the queries in parallel and return when it gets the first result. Because lookups might be done over different mechanisms because of the different namespaces, there can be information leakage that is similar to that seen with POSIX *getaddrinfo()*. The default is determined by the OS. .. py:attribute:: resolution_type Specifies whether DNS queries are performed with nonrecursive lookups or as a stub resolver. The value is either ``getdns.RESOLUTION_RECURSING`` or ``getdns.RESOLUTION_STUB``. If an implementation of this API is only able to act as a recursive resolver, setting `resolution_type` to ``getdns.RESOLUTION_STUB`` will throw an exception. .. py:attribute:: suffix Its value is a list of strings to be appended based on :attr:`append_name`. The list elements must follow the rules in :rfc:`4343#section-2.1` .. py:attribute:: timeout Its value must be an integer specifying a timeout for a query, expressed in milliseconds. .. py:attribute:: tls_authentication The mechanism to be used for authenticating the TLS server when using a TLS transport. May be ``getdns.AUTHENTICATION_REQUIRED`` or ``getdns.AUTHENTICATION_NONE``. (getdns.AUTHENTICATION_HOSTNAME remains as an alias for getdns.AUTHENTICATION_REQUIRED but is deprecated and will be removed in a future release) .. py:attribute:: tls_query_padding_blocksize Optional padding blocksize for queries when using TLS. Used to increase the difficulty for observers to guess traffic content. .. py:attribute:: upstream_recursive_servers A list of dicts defining where a stub resolver will send queries. Each dict in the list contains at least two names: address_type (whose value is a bindata; it is currently either "IPv4" or "IPv6") and address_data (whose value is a bindata). It might also contain port to specify which port to use to contact these DNS servers; the default is 53. If the stub and a recursive resolver both support TSIG (RFC 2845), the upstream_list entry can also contain tsig_algorithm (a bindata) that is the name of the TSIG hash algorithm, and tsig_secret (a bindata) that is the TSIG key. There is also now support for pinning an upstream's certificate's public keys, with pinsets (when using TLS for transport. Add an element to the upstream_recursive_server list entry, called 'tls_pubkey_pinset', which is a list of public key pins. (See the example code in our examples directory). .. py:attribute:: version_string The libgetdns version, retrieved from the underlying getdns library. The :class:`Context` class includes public methods to execute a DNS query, as well as a method to return the entire set of context attributes as a Python dictionary. :class:`Context` methods are described below: .. py:method:: general(name, request_type, [extensions], [userarg], [transaction_id], [callback]) ``Context.general()`` is used for looking up any type of DNS record. The keyword arguments are: * ``name``: a representation of the query term; usually a string but must be a dict (as described in ``Context.hostname()`` below) in the case of a PTR record lookup * ``request_type``: a DNS RR type as a getdns constant (listed here) * ``extensions``: optional. A dictionary containing attribute/value pairs, as described below * ``userarg``: optional. A string containing arbitrary user data; this is opaque to getdns * ``transaction_id``: optional. An integer. * ``callback``: optional. This is a function name. If it is present the query will be performed asynchronously (described below). .. py:method:: address(name, [extensions], [userarg], [transaction_id], [callback]) There are two critical differences between ``Context.address()`` and ``Context.general()`` beyond the missing *request_type* argument: * In ``Context.address()``, the name argument can only take a host name. * ``Context.address()`` always uses all of namespaces from the context (to better emulate getaddrinfo()), while ``Context.general()`` only uses the DNS namespace. .. py:method:: hostname(name [, extensions], [userarg], [transaction_id], [callback]) The address is given as a dictionary. The dictionary must have two names: * ``address_type``: must be a string matching either "IPv4" or "IPv6" * ``address_data``: a string representation of an IPv4 or IPv6 IP address .. py:method:: service(name [, extensions], [userarg], [transaction_id], [callback]) ``name`` must be a domain name for an SRV lookup. The call returns the relevant SRV information for the name .. py:method:: get_api_information() Retrieves context information. The information is returned as a Python dictionary with the following keys: * ``version_string`` * ``implementation_string`` * ``resolution_type`` * ``all_context`` ``all_context`` is a dictionary containing the following keys: * ``append_name`` * ``dns_transport`` * ``dnssec_allowed_skew`` * ``edns_do_bit`` * ``edns_extended_rcode`` * ``edns_version`` * ``follow_redirects`` * ``limit_outstanding_queries`` * ``namespaces`` * ``suffix`` * ``timeout`` * ``tls_authentication`` * ``upstream_recursive_servers`` .. py:method:: get_supported_attributes() Returns a list of the attributes supported by this Context object. The ``getdns`` module has the following read-only attribute: .. py:attribute:: __version__ Specifies the version string for the getdns python module Extensions ---------- Extensions are Python dictionaries, with the keys being the names of the extensions. The definition of each extension describes the values that may be assigned to that extension. For most extensions it is a Boolean, and since the default value is "False" it will most often take the value ``getdns.EXTENSION_TRUE``. The extensions currently supported by :py:mod:`getdns` are: * ``dnssec_return_status`` * ``dnssec_return_only_secure`` * ``dnssec_return_validation_chain`` * ``return_both_v4_and_v6`` * ``add_opt_parameters`` * ``add_warning_for_bad_dns`` * ``specify_class`` * ``return_call_reporting`` Extensions for DNSSEC ^^^^^^^^^^^^^^^^^^^^^ If an application wants the API to do DNSSEC validation for a request, it must set one or more DNSSEC-related extensions. Note that the default is for none of these extensions to be set and the API will not perform DNSSEC validation. Note that getting DNSSEC results can take longer in a few circumstances. To return the DNSSEC status for each DNS record in the ``replies_tree`` list, use the ``dnssec_return_status`` extension. Set the extension's value to ``getdns.EXTENSION_TRUE`` to cause the returned status to have the name ``dnssec_status`` added to the other names in the record's dictionary ("header", "question", and so on). The potential values for that name are ``getdns.DNSSEC_SECURE``, ``getdns.DNSSEC_BOGUS``, ``getdns.DNSSEC_INDETERMINATE``, and ``getdns.DNSSEC_INSECURE``. If instead of returning the status, you want to only see secure results, use the ``dnssec_return_only_secure`` extension. The extension's value is set to ``getdns.EXTENSION_TRUE`` to cause only records that the API can validate as secure with DNSSEC to be returned in the ``replies_tree`` and ``replies_full lists``. No additional names are added to the dict of the record; the change is that some records might not appear in the results. When this context option is set, if the API receives DNS replies but none are determined to be secure, the error code at the top level of the ``response`` object is ``getdns.RESPSTATUS_NO_SECURE_ANSWERS``. Applications that want to do their own validation will want to have the DNSSEC-related records for a particular response. Use the ``dnssec_return_validation_chain`` extension. Set the extension's value to ``getdns.EXTENSION_TRUE`` to cause a set of additional DNSSEC-related records needed for validation to be returned in the ``response object``. This set comes as ``validation_chain`` (a list) at the top level of the ``response`` object. This list includes all resource record dicts for all the resource records (DS, DNSKEY and their RRSIGs) that are needed to perform the validation from the root up. If a request is using a context in which stub resolution is set, and that request also has any of the ``dnssec_return_status``, ``dnssec_return_only_secure``, or ``dnssec_return_validation_chain`` extensions specified, the API will not perform the request and will instead return an error of ``getdns.RETURN_DNSSEC_WITH_STUB_DISALLOWED``. Returning both IPv4 and IPv6 responses ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Many applications want to get both IPv4 and IPv6 addresses in a single call so that the results can be processed together. The :meth:`address` method is able to do this automatically. If you are using the :meth:`general` method, you can enable this with the ``return_both_v4_and_v6`` extension. The extension's value must be set to ``getdns.EXTENSION_TRUE`` to cause the results to be the lookup of either A or AAAA records to include any A and AAAA records for the queried name (otherwise, the extension does nothing). These results are expected to be usable with Happy Eyeballs systems that will find the best socket for an application. Setting up OPT resource records ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For lookups that need an **OPT** resource record in the Additional Data section, use the ``add_opt_parameters`` extension. The extension's value (a dict) contains the parameters; these are described in more detail in :rfc:`2671`. They are: * ``maximum_udp_payload_size``: an integer between 512 and 65535 inclusive. If not specified it defaults to the value in the getdns context. * ``extended_rcode``: an integer between 0 and 255 inclusive. If not specified it defaults to the value in the getdns context. * ``version``: an integer betwen 0 and 255 inclusive. If not specified it defaults to 0. * ``do_bit``: must be either 0 or 1. If not specified it defaults to the value in the getdns context. * ``options``: a list containing dictionaries for each option to be specified. Each dictionary contains two keys: ``option_code`` (an integer) and ``option_data`` (in the form appropriate for that option code). It is very important to note that the OPT resource record specified in the ``add_opt_parameters extension`` might not be the same the one that the API sends in the query. For example, if the application also includes any of the DNSSEC extensions, the API will make sure that the OPT resource record sets the resource record appropriately, making the needed changes to the settings from the ``add_opt_parameters`` extension. The ``client_subnet.py`` program in our example directory shows how to pack and send an OPT record. Getting Warnings for Responses that Violate the DNS Standard ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To receive a warning if a particular response violates some parts of the DNS standard, use the ``add_warning_for_bad_dns`` extension. The extension's value is set to ``getdns.EXTENSION_TRUE`` to cause each reply in the ``replies_tree`` to contain an additional name, ``bad_dns`` (a list). The list is zero or more values that indicate types of bad DNS found in that reply. The list of values is: .. py:data:: BAD_DNS_CNAME_IN_TARGET A DNS query type that does not allow a target to be a CNAME pointed to a CNAME .. py:data:: BAD_DNS_ALL_NUMERIC_LABEL One or more labels in a returned domain name is all-numeric; this is not legal for a hostname .. py:data:: BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE A DNS query for a type other than CNAME returned a CNAME response Using other class types ^^^^^^^^^^^^^^^^^^^^^^^ The vast majority of DNS requests are made with the Internet (IN) class. To make a request in a different DNS class, use, the ``specify_class extension``. The extension's value (an int) contains the class number. Few applications will ever use this extension. Extensions relating to the API ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ An application might want to see debugging information for queries, such as the length of time it takes for each query to return to the API. Use the ``return_call_reporting`` extension. The extension's value is set to ``getdns.EXTENSION_TRUE`` to add the name ``call_reporting`` (a list) to the top level of the ``response`` object. Each member of the list is a dict that represents one call made for the call to the API. Each member has the following names: * ``query_name`` is the name that was sent * ``query_type`` is the type that was queried for * ``query_to`` is the address to which the query was sent * ``start_time`` is the time the query started in milliseconds since the epoch, represented as an integer * ``end_time`` is the time the query was received in milliseconds since the epoch, represented as an integer * ``entire_reply`` is the entire response received * ``dnssec_result`` is the DNSSEC status, or ``getdns.DNSSEC_NOT_PERFORMED`` if DNSSEC validation was not performed Asynchronous queries ^^^^^^^^^^^^^^^^^^^^ The getdns Python bindings support asynchronous queries, in which a query returns immediately and a callback function is invoked when the response data are returned. The query method interfaces are fundamentally the same, with a few differences: * The query returns a transaction id. That transaction id may be used to cancel future callbacks * The query invocation includes the name of a callback function. For example, if you'd like to call the function "my_callback" when the query returns, an address lookup could look like >>> c = getdns.Context() >>> tid = c.address('www.example.org', callback=my_callback) * We've introduced a new ``Context`` method, called ``run``. When your program is ready to check to see whether or not the query has returned, invoke the run() method on your context. Note that we use the libevent asynchronous event library and an event_base is associated with a context. So, if you have multiple outstanding events associated with a particular context, ``run`` will invoke all of those that are waiting and ready. * In previous releases the callback argument took the form of a literal string, but as of this release you may pass in the name of any Python runnable, without quotes. The newer form is preferred. The callback script takes four arguments: ``type``, ``result``, ``userarg``, and ``transaction_id. The ``type`` argument contains the callback type, which may have one of the following values: * ``getdns.CALLBACK_COMPLETE``: The query was successful and the results are contained in the ``result`` argument * ``getdns.CALLBACK_CANCEL``: The callback was cancelled before the results were processed * ``getdns.CALLBACK_TIMEOUT``: The query timed out before the results were processed * ``getdns.CALLBACK_ERROR``: An unspecified error occurred The ``result`` argument contains a result object, with the query response The ``userarg`` argument contains the optional user argument that was passed to the query at the time it was invoked. The ``transaction_id`` argument contains the transaction_id associated with a particular query; this is the same transaction id that was returned when the query was invoked. This is an example callback function: .. code-block:: python def cbk(type, result, userarg, tid): if type == getdns.CALLBACK_COMPLETE: status = result.status if status == getdns.RESPSTATUS_GOOD: for addr in result.just_address_answers: addr_type = addr['address_type'] addr_data = addr['address_data'] print '{0}: {1} {2}'.format(userarg, addr_type, addr_data) elif status == getdns.RESPSTATUS_NO_SECURE_ANSWERS: print "{0}: No DNSSEC secured responses found".format(hostname) else: print "{0}: getdns.address() returned error: {1}".format(hostname, status) elif type == getdns.CALLBACK_CANCEL: print 'Callback cancelled' elif type == getdns.CALLBACK_TIMEOUT: print 'Query timed out' else: print 'Unknown error' getdns-python-bindings-1.0.0b1/doc/index.rst000066400000000000000000000162031267725536200207600ustar00rootroot00000000000000.. getdns documentation master file, created by sphinx-quickstart on Mon Apr 7 17:05:52 2014. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. getdns: Python bindings for getdns #################################### "getdns" is an implementation of Python language bindings for the `getdns `_ API. getdns is a modern, asynchronous DNS API that simplifies access to advanced DNS features, including DNSSEC. The API `specification `_ was developed by Paul Hoffman. getdns is built on top of the getdns implementation developed as a joint project between `Verisign Labs `_ and `NLnet Labs `_. We have tried to keep this interface as Pythonic as we can while staying true to the getdns architecture, including trying to maintain consistency with Python object design. Dependencies ============ This version of getdns has been built and tested against Python 2.7 and Python 3.4. We also expect these other prerequisites to be installed: * `libgetdns `_, version 0.9.0 or later * `libunbound `_, version 1.4.16 or later * `libidn `_ version 1 This release has been tested against libgetdns 0.9.0. Building ======== The code repository for getdns is available at: ``_. If you are building from source you will need the Python development package for Python 2.7. On Linux systems this is typically something along the lines of "python-dev" or "python2.7-dev", available through your package system. On Mac OS we are building against the python.org release, available in source form `here `_. For the actual build, we are using the standard Python `distutils `_. To build and install: :: python setup.py build python setup.py install If you have installed getdns libraries and headers in other than the default location, build the Python bindings using the ``--with-getdns`` argument to setup.py, providing the getdns root directory as an argument. (Note that there should be a space between --with-getdns and the directory). For example, :: python setup.py build --with-getdns ~/build if you installed getdns into your home/build directory. We've added optional support for draft-ietf-dnsop-cookies. It is implemented as a getdns extension (see below). It is not built by default. To enable it, you must build libgetdns with cookies support and add the ``--with-edns-cookies`` to the Python module build (i.e. ``python setup.py build --with-edns-cookies``). Using getdns ============== Contexts -------- All getdns queries happen within a resolution *context*, and among the first tasks you'll need to do before issuing a query is to acquire a Context object. A context is an opaque object with attributes describing the environment within which the query and replies will take place, including elements such as DNSSEC validation, whether the resolution should be performed as a recursive resolver or a stub resolver, and so on. Individual Context attributes may be examined directly, and the overall state of a given context can be queried with the Context.get_api_information() method. See section 8 of the `API specification `_ Examples -------- In this example, we do a simple address lookup and dump the results to the screen: .. code-block:: python import getdns, pprint, sys def main(): if len(sys.argv) != 2: print "Usage: {0} hostname".format(sys.argv[0]) sys.exit(1) ctx = getdns.Context() extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } results = ctx.address(name=sys.argv[1], extensions=extensions) if results.status == getdns.RESPSTATUS_GOOD: sys.stdout.write("Addresses: ") for addr in results.just_address_answers: print " {0}".format(addr["address_data"]) sys.stdout.write("\n\n") print "Entire results tree: " pprint.pprint(results.replies_tree) if results.status == getdns.RESPSTATUS_NO_NAME: print "{0} not found".format(sys.argv[1]) if __name__ == "__main__": main() In this example, we do a DNSSEC query and check the response: .. code-block:: python import getdns, sys dnssec_status = { "DNSSEC_SECURE" : 400, "DNSSEC_BOGUS" : 401, "DNSSEC_INDETERINATE" : 402, "DNSSEC_INSECURE" : 403, "DNSSEC_NOT_PERFORMED" : 404 } def dnssec_message(value): for message in dnssec_status.keys(): if dnssec_status[message] == value: return message def main(): if len(sys.argv) != 2: print "Usage: {0} hostname".format(sys.argv[0]) sys.exit(1) ctx = getdns.Context() extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE, "dnssec_return_status" : getdns.EXTENSION_TRUE } results = ctx.address(name=sys.argv[1], extensions=extensions) if results.status == getdns.RESPSTATUS_GOOD: sys.stdout.write("Addresses: ") for addr in results.just_address_answers: print " {0}".format(addr["address_data"]) sys.stdout.write("\n") for result in results.replies_tree: if "dnssec_status" in result.keys(): print "{0}: dnssec_status: {1}".format(result["canonical_name"], dnssec_message(result["dnssec_status"])) if results.status == getdns.RESPSTATUS_NO_NAME: print "{0} not found".format(sys.argv[1]) if __name__ == "__main__": main() Module-level attributes and methods =================================== .. py:attribute:: __version__ The ``getdns.__version__`` attribute contains the version string for the Python getdns module. Please note that this is independent of the version of the underlying getdns library, which may be retrieved through attributes associated with a Context. .. py:method:: get_errorstr_by_id() Returns a human-friendly string representation of an error ID. .. py:method:: ulabel_to_alabel() Converts a ulabel to an alabel. Takes one argument (the ulabel) .. py:method:: alabel_to_ulabel() Converts an alabel to a ulabel. Takes one argument (the alabel) .. py:method:: root_trust_anchor() Returns the default root trust anchor for DNSSEC. Known issues ============ * "userarg" currently only accepts a string. This will be changed in a future release, to take arbitrary data types Contents: .. toctree:: :maxdepth: 1 functions response exceptions Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` getdns-python-bindings-1.0.0b1/doc/response.rst000066400000000000000000000307641267725536200215170ustar00rootroot00000000000000:mod:`getdns` response data ============================= .. module:: getdns :synopsis: getdns response data description and explanation .. sectionauthor:: Melinda Shore Response data from queries -------------------------- .. py:class:: Result() A getdns query (``Context.address()``, ``Context.hostname()``, ``Context.service()``, and ``Context.general()``) returns a Result object. A Result object is only returned from a query and may not be instantiated by the programmer. It is a read-only object. Contents may not be overwritten or deleted. It has no methods but includes the following attributes: .. py:attribute:: status The ``status`` attribute contains the status code returned by the query. Note that it may be the case that the query can be successful but there are no data matching the query parameters. Programmers using this API will need to first check to see if the query itself was successful, then check for the records returned. The ``status`` attribute may have the following values: .. py:data:: getdns.RESPSTATUS_GOOD At least one response was returned .. py:data:: getdns.RESPSTATUS_NO_NAME Queries for the name yielded all negative responses .. py:data:: getdns.RESPSTATUS_ALL_TIMEOUT All queries for the name timed out .. py:data:: getdns.RESPSTATUS_NO_SECURE_ANSWERS The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC. .. py:data:: getdns.RESPSTATUS_ALL_BOGUS_ANSWERS The context setting for getting only secure responses was specified, and at least one DNS response was received, but all received responses for the requested name were bogus. .. py:attribute:: answer_type The ``answer_type`` attribute contains the type of data that are returned (i.e., the namespace). The ``answer_type`` attribute may have the following values: .. py:data:: getdns.NAMETYPE_DNS Normal DNS (:rfc:`1035`) .. py:data:: getdns.NAMETYPE_WINS The WINS name service (some reference needed) .. py:attribute:: canonical_name The value of ``canonical_name`` is the name that the API used for its lookup. It is in FQDN presentation format. .. py:attribute:: just_address_answers If the call was :meth:`address`, the attribute ``just_address_answers`` (a list) is non-null. The value of ``just_address_answers`` is a list that contains all of the A and AAAA records from the ``answer`` sections of any of the replies, in the order they appear in the replies. Each item in the list is a dict with at least two names: ``address_type`` (a string whose value is either "IPv4" or "IPv6") and ``address_data`` (whose value is a string representation of an IP address). Note that the ``dnssec_return_only_secure`` extension affects what will appear in the just_address_answers list. Also note if later versions of the DNS return other address types, those types will appear in this list as well. .. py:attribute:: replies_full The ``replies_full`` attribute is a Python dictionary containing the entire set of records returned by the query. The following lists the status codes for response objects. Note that, if the status is that there are no responses for the query, the lists in ``replies_full`` and ``replies_tree`` will have zero length. The top level of ``replies_tree`` can optionally have the following names: ``canonical_name``, ``intermediate_aliases`` (a list), ``answer_ipv4_address`` ``answer_ipv6_address``, and ``answer_type`` (an integer constant.). * The value of ``canonical_name`` is the name that the API used for its lookup. It is in FQDN presentation format. * The values in the ``intermediate_aliases`` list are domain names from any CNAME or unsynthesized DNAME found when resolving the original query. The list might have zero entries if there were no CNAMEs in the path. These may be useful, for example, for name comparisons when following the rules in RFC 6125. * The value of ``answer_ipv4_address`` and ``answer_ipv6_address`` are the addresses of the server from which the answer was received. * The value of ``answer_type`` is the type of name service that generated the response. The values are: If the call was :meth:`address`, the top level of ``replies_tree`` has an additional name, ``just_address_answers`` (a list). The value of ``just_address_answers`` is a list that contains all of the A and AAAA records from the ``answer`` sections of any of the replies, in the order they appear in the replies. Each item in the list is a dict with at least two names: ``address_type`` (a string whose value is either "IPv4" or "IPv6") and ``address_data`` (whose value is a string representation of an IP address). Note that the ``dnssec_return_only_secure`` extension affects what will appear in the just_address_answers list. Also note if later versions of the DNS return other address types, those types will appear in this list as well. The API can make service discovery through SRV records easier. If the call was :meth:`service`, the top level of ``replies_tree has`` an additional name, ``srv_addresses`` (a list). The list is ordered by priority and weight based on the weighting algorithm in :rfc:`2782`, lowest priority value first. Each element of the list is a dictionary that has at least two names: ``port`` and ``domain_name``. If the API was able to determine the address of the target domain name (such as from its cache or from the Additional section of responses), the dict for an element will also contain ``address_type`` (whose value is currently either "IPv4" or "IPv6") and ``address_data`` (whose value is a string representation of an IP address). Note that the ``dnssec_return_only_secure`` extension affects what will appear in the ``srv_addresses`` list. .. py:attribute:: validation_chain The ``validation_chain`` attribute is a Python list containing the set of DNSSEC-related records needed for validation of a particular response. This set comes as validation_chain (a list) at the top level of the response object. This list includes all resource record dicts for all the resource records (DS, DNSKEY and their RRSIGs) that are needed to perform the validation from the root up. .. py:attribute:: call_reporting A list of dictionaries containing call_debugging information, if requested in the query. .. py:attribute:: replies_tree The names in each entry in the the ``replies_tree`` list for DNS responses include ``header`` (a dict), ``question`` (a dict), ``answer`` (a list), ``authority`` (a list), and ``additional`` (a list), corresponding to the sections in the DNS message format. The ``answer``, ``authority``, and ``additional`` lists each contain zero or more dicts, with each dict in each list representing a resource record. The names in the ``header`` dict are all the fields from :rfc:`1035#section-4.1.1`. They are: ``id``, ``qr``, ``opcode``, ``aa``, ``tc``, ``rd``, ``ra``, ``z``, ``rcode``, ``qdcount``, ``ancount``, ``nscount``, and ``arcount``. All are integers. The names in the ``question`` dict are the three fields from :rfc:`1035#section-4.1.2`: ``qname``, ``qtype``, and ``qclass``. Resource records are a bit different than headers and question sections in that the RDATA portion often has its own structure. The other names in the resource record dictionaries are ``name``, ``type``, ``class``, ``ttl``, and ``rdata`` (which is a dict); there is no name equivalent to the RDLENGTH field. The OPT resource record does not have the ``class`` and the ``ttl`` name, but instead provides ``udp_payload_size``, ``extended_rcode``, ``version``, ``do``, and ``z``. The ``rdata`` dictionary has different names for each response type. There is a complete list of the types defined in the API. For names that end in "-obsolete" or "-unknown", the data are the entire RDATA field. For example, the ``rdata`` for an A record has a name ``ipv4_address``; the rdata for an SRV record has the names ``priority``, ``weight``, ``port``, and ``target``. Each rdata dict also has a ``rdata_raw`` element. This is useful for types not defined in this version of the API. It also might be of value if a later version of the API allows for additional parsers. Thus, doing a query for types not known by the API still will return a result: an ``rdata`` with just a ``rdata_raw``. It is expected that later extensions to the API will give some DNS types different names. It is also possible that later extensions will change the names for some of the DNS types listed above. For example, a response to a Context.address() call for www.example.com would look something like this: :: { # This is the response object "replies_full": [ , ], "just_address_answers": [ { "address_type": , "address_data": , }, { "address_type": , "address_data": } ], "canonical_name": , "answer_type": NAMETYPE_DNS, "intermediate_aliases": [], "replies_tree": [ { # This is the first reply "header": { "id": 23456, "qr": 1, "opcode": 0, ... }, "question": { "qname": , "qtype": 1, "qclass": 1 }, "answer": [ { "name": , "type": 1, "class": 1, "ttl": 33000, "rdata": { "ipv4_address": "rdata_raw": } } ], "authority": [ { "name": , "type": 1, "class": 1, "ttl": 600, "rdata": { "ipv4_address": "rdata_raw": } } ] "additional": [], "canonical_name": , "answer_type": NAMETYPE_DNS }, { # This is the second reply "header": { "id": 47809, "qr": 1, "opcode": 0, ... }, "question": { "qname": , "qtype": 28, "qclass": 1 }, "answer": [ { "name": , "type": 28, "class": 1, "ttl": 1000, "rdata": { "ipv6_address": "rdata_raw": } } ], "authority": [ # Same as for other record... ] "additional": [], }, ] } Return Codes ------------ The return codes for all the functions are: .. py:data:: RETURN_GOOD Good .. py:data:: RETURN_GENERIC_ERROR Generic error .. py:data:: RETURN_BAD_DOMAIN_NAME Badly-formed domain name in first argument .. py:data:: RETURN_BAD_CONTEXT The context has internal deficiencies .. py:data:: RETURN_CONTEXT_UPDATE_FAIL Did not update the context .. py:data:: RETURN_UNKNOWN_TRANSACTION An attempt was made to cancel a callback with a transaction_id that is not recognized .. py:data:: RETURN_NO_SUCH_LIST_ITEM A helper function for lists had an index argument that was too high. .. py:data:: RETURN_NO_SUCH_DICT_NAME A helper function for dicts had a name argument that for a name that is not in the dict. .. py:data:: RETURN_WRONG_TYPE_REQUESTED A helper function was supposed to return a certain type for an item, but the wrong type was given. .. py:data:: RETURN_NO_SUCH_EXTENSION A name in the extensions dict is not a valid extension. .. py:data:: RETURN_EXTENSION_MISFORMAT One or more of the extensions have a bad format. .. py:data:: RETURN_DNSSEC_WITH_STUB_DISALLOWED A query was made with a context that is using stub resolution and a DNSSEC extension specified. .. py:data:: RETURN_MEMORY_ERROR Unable to allocate the memory required. .. py:data:: RETURN_INVALID_PARAMETER A required parameter had an invalid value. .. py:data:: RETURN_NOT_IMPLEMENTED The requested API feature is not implemented. getdns-python-bindings-1.0.0b1/examples/000077500000000000000000000000001267725536200201665ustar00rootroot00000000000000getdns-python-bindings-1.0.0b1/examples/async-get-ip.py000077500000000000000000000044051267725536200230460ustar00rootroot00000000000000#!/usr/bin/env python # """ get-ip.py: resolve given DNS names into IP addresses. The -s switch constains answers to only ones secured by DNSSEC. The -4 switch only returns IPv4 addresses, the -6 switch only IPv6 addresses. An example run: $ python async-get-ip.py www.panix.com www.isoc.org www.verisignlabs.com submitted query for www.panix.com submitted query for www.isoc.org submitted query for www.verisignlabs.com www.panix.com: IPv4 166.84.62.125 www.panix.com: IPv4 166.84.62.253 www.verisignlabs.com: IPv4 72.13.58.64 www.verisignlabs.com: IPv6 2620:74:13:4400::201 www.isoc.org: IPv4 212.110.167.157 www.isoc.org: IPv6 2001:41c8:20::19 """ import getdns, sys, getopt def cbk(type, result, userarg, tid): if type == getdns.CALLBACK_COMPLETE: status = result.status if status == getdns.RESPSTATUS_GOOD: for addr in result.just_address_answers: addr_type = addr['address_type'] addr_data = addr['address_data'] print("{0}: {1} {2}".format(userarg, addr_type, addr_data)) elif status == getdns.RESPSTATUS_NO_SECURE_ANSWERS: print("{0}: No DNSSEC secured responses found".format(hostname)) else: print("{0}: getdns.address() returned error: {1}".format(hostname, status)) elif type == getdns.CALLBACK_CANCEL: print('Callback cancelled') elif type == getdns.CALLBACK_TIMEOUT: print('Query timed out') else: print('Unknown error') def usage(): print("""\ Usage: get-ip.py [-s] [-4|-6] ... -s: only return DNSSEC secured answers -4: only return IPv4 address answers -6: only return IPv6 address answers -4 and -6 are mutually exclusive. If both are specified, IPv6 wins. """) sys.exit(1) try: (options, args) = getopt.getopt(sys.argv[1:], 's46') except getopt.GetoptError: usage() else: if not args: usage() extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } ctx = getdns.Context() tids = [] for hostname in args: try: tids.append(ctx.address(name=hostname, extensions=extensions, callback='cbk', userarg=hostname)) print ('submitted query for {0}'.format(hostname)) except getdns.error as e: print(str(e)) break ctx.run() getdns-python-bindings-1.0.0b1/examples/checkdanecert.py000077500000000000000000000122641267725536200233330ustar00rootroot00000000000000#!/usr/bin/env python # # Validate a TLS certificate with DANE-EE usage. # Get a TLS certificate from a HTTP server and verify it with # DANE/DNSSEC. Only supports TLSA usage=3 (DANE-EE) # import os.path, sys, socket, hashlib from M2Crypto import SSL, X509 import getdns def usage(): print """\ Usage: %s [hostname] [port]\ """ % os.path.basename(sys.argv[0]) sys.exit(1) def compute_hash(func, string): """compute hash of string using given hash function""" h = func() h.update(string) return h.hexdigest() def get_addresses(hostname): extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } ctx = getdns.Context() try: results = ctx.address(name=hostname, extensions=extensions) except getdns.error, e: print(str(e)) sys.exit(1) status = results.status address_list = [] if status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: address_list.append((addr['address_type'], addr['address_data'])) else: print "getdns.address(): failed, return code: %d" % status return address_list def get_tlsa_rdata_set(replies, requested_usage=None): tlsa_rdata_set = [] for reply in replies: for rr in reply['answer']: if rr['type'] == getdns.RRTYPE_TLSA: rdata = rr['rdata'] usage = rdata['certificate_usage'] selector = rdata['selector'] matching_type = rdata['matching_type'] cadata = rdata['certificate_association_data'] cadata = str(cadata).encode('hex') if usage == requested_usage: tlsa_rdata_set.append( (usage, selector, matching_type, cadata) ) return tlsa_rdata_set def get_tlsa(port, proto, hostname): extensions = { "dnssec_return_only_secure" : getdns.EXTENSION_TRUE, } qname = "_%d._%s.%s" % (port, proto, hostname) ctx = getdns.Context() try: results = ctx.general(name=qname, request_type=getdns.RRTYPE_TLSA, extensions=extensions) except getdns.error, e: print(str(e)) sys.exit(1) status = results.status if status == getdns.RESPSTATUS_GOOD: return get_tlsa_rdata_set(results.replies_tree, requested_usage=3) else: print "getdns.general(): failed, return code: %d" % status return None def verify_tlsa(cert, usage, selector, matchtype, hexdata1): if selector == 0: certdata = cert.as_der() elif selector == 1: certdata = cert.get_pubkey().as_der() else: raise ValueError("selector type %d not recognized" % selector) if matchtype == 0: hexdata2 = hexdump(certdata) elif matchtype == 1: hexdata2 = compute_hash(hashlib.sha256, certdata) elif matchtype == 2: hexdata2 = compute_hash(hashlib.sha512, certdata) else: raise ValueError("matchtype %d not recognized" % matchtype) if hexdata1 == hexdata2: return True else: return False if __name__ == '__main__': try: hostname, port = sys.argv[1:] port = int(port) except: usage() tlsa_rdata_set = get_tlsa(port, "tcp", hostname) for (iptype, ipaddr) in get_addresses(hostname): print "Connecting to %s at address %s ..." % (hostname, ipaddr) ctx = SSL.Context() if iptype == "IPv4": sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) elif iptype == "IPv6": sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: raise ValueError, "Unknown address type: %s" % iptype sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) connection = SSL.Connection(ctx, sock=sock) # set TLS SNI extension if available in M2Crypto on this platform # Note: the official M2Crypto release does not yet (as of late 2014) # have support for SNI, sigh, but patches exist. try: connection.set_tlsext_host_name(hostname) except AttributeError: pass # Per https://tools.ietf.org/html/draft-ietf-dane-ops, for DANE-EE # usage, certificate identity checks are based solely on the TLSA # record, so we ignore name mismatch conditions in the certificate. try: connection.connect((ipaddr, port)) except SSL.Checker.WrongHost: pass chain = connection.get_peer_cert_chain() cert = chain[0] # find a matching TLSA record entry for the certificate tlsa_match = False for (usage, selector, matchtype, hexdata) in tlsa_rdata_set: if verify_tlsa(cert, usage, selector, matchtype, hexdata): tlsa_match = True print "Matched TLSA record %d %d %d %s" % \ (usage, selector, matchtype, hexdata) else: print "Didn't match TLSA record %d %d %d %s"% \ (usage, selector, matchtype, hexdata) if not tlsa_match: print "No Matching DANE-EE TLSA record found." connection.close() ctx.close() getdns-python-bindings-1.0.0b1/examples/client_subnet.py000077500000000000000000000016531267725536200234060ustar00rootroot00000000000000import getdns from struct import pack, unpack def main(): CLIENT_SUBNET_OPCODE = 8 address = '192.168.1.0' host = 'getdnsapi.net' source_len = 12 family = pack("!H", 1) # start building the edns option fields source_len = pack('!B', source_len) scope_len = pack('!B', 0) # # encoding the binary data in strings makes it really easy # to build packets by concatenating those strings # address = pack('!BBBB', 192, 168, 1, 0) payload = family + source_len + scope_len + address ext = { 'add_opt_parameters': {'options': [ {'option_code': CLIENT_SUBNET_OPCODE, 'option_data': payload} ] }} c = getdns.Context() c.resolution_type = getdns.RESOLUTION_STUB response = c.address(host, extensions=ext) # do things with response ... print response if __name__ == '__main__': main() getdns-python-bindings-1.0.0b1/examples/dane_encrypt.py000077500000000000000000000041651267725536200232240ustar00rootroot00000000000000 # an example of using getdns to pull out a TLSA record, # extract a certificate, extract the public key, and then # encrypt some text # # requires the following Python modules: # getdns # m2crypto # import getdns import M2Crypto as m2 from M2Crypto import RSA import sys # # I commented out the "return None" because this is demo code and you # should be able to play with it. But, in deployed applications you # MUST check that dnssec_status is DNSSEC_SECURE # def get_first_secure_response(results): replies_tree = results.replies_tree if (not replies_tree) or (not len(replies_tree)) or (not replies_tree[0]['answer']) or (not len(replies_tree[0]['answer'])): print 'empty answer list' return None else: reply = replies_tree[0] if reply['dnssec_status'] != getdns.DNSSEC_SECURE: print 'insecure reply' # return None answer = replies_tree[0]['answer'] record = [ x for x in answer if x['type'] is getdns.RRTYPE_TLSA ] if len(record) == 0: print 'no answers of type TLSA' return None return record[0] def main(): tls_name = '77fa5113ab6a532ce2e6901f3bd3351c0db5845e0b1b5fb09907808d._smimecert.getdnsapi.org' if len(sys.argv) == 2: tls_name = sys.argv[1] c = getdns.Context() extensions = { 'dnssec_return_status' : getdns.EXTENSION_TRUE } results = c.general(tls_name, request_type=getdns.RRTYPE_TLSA, extensions=extensions) if results.replies_full['status'] != getdns.RESPSTATUS_GOOD: print 'query status is {0}'.format(results.status) sys.exit(1) else: record = get_first_secure_response(results) cert = record['rdata']['certificate_association_data'] try: x509 = m2.X509.load_cert_der_string(cert) rsakey = x509.get_pubkey().get_rsa() encrypted = rsakey.public_encrypt("A chunk of text", RSA.pkcs1_oaep_padding) print encrypted.encode('base64') except: print 'Error: ', sys.exc_info()[0] sys.exit(1) if __name__ == '__main__': main() getdns-python-bindings-1.0.0b1/examples/get-general.py000077500000000000000000000027261267725536200227440ustar00rootroot00000000000000#!/usr/bin/env python # # Given a DNS name and type, return the records in the DNS answer # section only, excluding any RRSIG records. # import getdns, pprint, sys extensions = { "dnssec_return_status" : getdns.EXTENSION_TRUE } def get_rrtype(qtype): try: rrtype = eval("getdns.RRTYPE_%s" % qtype.upper()) except AttributeError: print("Unknown DNS record type: {0}".format(qtype)) sys.exit(1) else: return rrtype def print_answer(r): pprint.pprint(r.replies_tree[0]['answer']) return if __name__ == '__main__': qname, qtype = sys.argv[1:] rrtype = get_rrtype(qtype) ctx = getdns.Context() try: results = ctx.general(name=qname, request_type=rrtype, extensions=extensions) except getdns.error as e: print(str(e)) sys.exit(1) status = results.status if status == getdns.RESPSTATUS_GOOD: for reply in results.replies_tree: answers = reply['answer'] # list of 1 here for answer in answers: if answer['type'] != getdns.RRTYPE_RRSIG: pprint.pprint(answer) elif status == getdns.RESPSTATUS_NO_NAME: print("{0}, {1}: no such name".format(qname, qtype)) elif status == getdns.RESPSTATUS_ALL_TIMEOUT: print("{0}, {1}: query timed out".format(qname, qtype)) else: print("{0}, {1}: unknown return code: {2}".format(qname, qtype, results.status)) getdns-python-bindings-1.0.0b1/examples/get-ip.py000077500000000000000000000037331267725536200217360ustar00rootroot00000000000000#!/usr/bin/env python # """ get-ip.py: resolve given DNS names into IP addresses. The -s switch constains answers to only ones secured by DNSSEC. The -4 switch only returns IPv4 addresses, the -6 switch only IPv6 addresses. An example run: $ get-ip.py -s www.huque.com www.google.com www.huque.com: IPv4 50.116.63.23 www.huque.com: IPv6 2600:3c03:e000:81::a www.google.com: No DNSSEC secured responses found """ import getdns, sys, getopt def usage(): print("""\ Usage: get-ip.py [-s] [-4|-6] ... -s: only return DNSSEC secured answers -4: only return IPv4 address answers -6: only return IPv6 address answers -4 and -6 are mutually exclusive. If both are specified, IPv6 wins. """) sys.exit(1) try: (options, args) = getopt.getopt(sys.argv[1:], 's46') except getopt.GetoptError: usage() else: if not args: usage() extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } desired_addr_type = None for (opt, optval) in options: if opt == "-s": extensions["dnssec_return_only_secure"] = getdns.EXTENSION_TRUE elif opt == "-4": desired_addr_type = "IPv4" elif opt == "-6": desired_addr_type = "IPv6" ctx = getdns.Context() for hostname in args: try: results = ctx.address(name=hostname, extensions=extensions) except getdns.error as e: print(str(e)) break status = results.status if status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: addr_type = addr['address_type'] addr_data = addr['address_data'] if (desired_addr_type == None) or (addr_type == desired_addr_type): print("{0}: {1} {2}".format(hostname, addr_type, addr_data)) elif status == getdns.RESPSTATUS_NO_SECURE_ANSWERS: print("{0}: No DNSSEC secured responses found".format(hostname)) else: print("{0}: getdns.address() returned error: {1}".format(hostname, status)) getdns-python-bindings-1.0.0b1/examples/get-mx-ip.py000077500000000000000000000034531267725536200223570ustar00rootroot00000000000000#!/usr/bin/env python # """ Lookup an MX record and printout all the MX preference, target, and associated IP addresses of the targets. """ import getdns, pprint, sys extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } def get_ip(ctx, qname): iplist = [] try: results = ctx.address(name=qname, extensions=extensions) except getdns.error as e: print(str(e)) sys.exit(1) if results.status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: iplist.append(addr['address_data']) else: print("getdns.address() returned an error: {0}".format(results.status)) return iplist if __name__ == '__main__': qname = sys.argv[1] ctx = getdns.Context() try: results = ctx.general(name=qname, request_type=getdns.RRTYPE_MX) except getdns.error as e: print(str(e)) sys.exit(1) status = results.status hostlist = [] if status == getdns.RESPSTATUS_GOOD: for reply in results.replies_tree: answers = reply['answer'] for answer in answers: if answer['type'] == getdns.RRTYPE_MX: iplist = get_ip(ctx, answer['rdata']['exchange']) for ip in iplist: hostlist.append( (answer['rdata']['preference'], \ answer['rdata']['exchange'], ip) ) elif status == getdns.RESPSTATUS_NO_NAME: print("{0}, {1}: no such name".format(qname, qtype)) elif status == getdns.RESPSTATUS_ALL_TIMEOUT: print("{0}, {1}: query timed out".format(qname, qtype)) else: print("{0}, {1}: unknown return code: {2}".format(qname, qtype, results["status"])) for (pref, mx, addr) in sorted(hostlist): print(pref, mx, addr) getdns-python-bindings-1.0.0b1/examples/get-ns-ip.py000077500000000000000000000036251267725536200223540ustar00rootroot00000000000000#!/usr/bin/env python # """ Lookup an NS record and printout all the hostnames and associated IP addresses of the listed nameservers. """ import getdns, pprint, sys extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } def usage(): print("""Usage: get-ns-ip.py where is a DNS zone (domain). """) sys.exit(1) def get_ip(ctx, qname): iplist = [] try: results = ctx.address(name=qname, extensions=extensions) except getdns.error as e: print(str(e)) sys.exit(1) if results.status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: iplist.append(addr['address_data']) else: print("getdns.address() returned an error: {0}".format(results['status'])) return iplist if __name__ == '__main__': if len(sys.argv) != 2: usage() qname = sys.argv[1] ctx = getdns.Context() try: results = ctx.general(name=qname, request_type=getdns.RRTYPE_NS) except getdns.error as e: print(str(e)) sys.exit(1) status = results.status hostlist = [] if status == getdns.RESPSTATUS_GOOD: for reply in results.replies_tree: answers = reply['answer'] for answer in answers: if answer['type'] == getdns.RRTYPE_NS: iplist = get_ip(ctx, answer['rdata']['nsdname']) for ip in iplist: hostlist.append( (answer['rdata']['nsdname'], ip) ) elif status == getdns.RESPSTATUS_NO_NAME: print("{0}: no such DNS zone".format(qname)) elif status == getdns.RESPSTATUS_ALL_TIMEOUT: print("{0}, NS: query timed out".format(qname)) else: print("{0}, NS: unknown return code: {1}".format(qname, results["status"])) # Print out each NS server name and IP address for (nsdname, addr) in sorted(hostlist): print(nsdname, addr) getdns-python-bindings-1.0.0b1/examples/get-srv.py000077500000000000000000000015731267725536200221400ustar00rootroot00000000000000#!/usr/bin/env python # """ Lookup an SRV record and printout all the SRV priority, weight, targets, and associated IP addresses of the targets. """ import getdns, pprint, sys, time srvname = sys.argv[1] ctx = getdns.Context() try: results = ctx.service(name=srvname) except getdns.error as e: print(str(e)) sys.exit(1) if results.status == getdns.RESPSTATUS_GOOD: for reply in results.replies_tree: for a in reply["answer"]: rrname = a["name"] rrtype = a["type"] if rrtype == getdns.RRTYPE_SRV: rdata = a["rdata"] prio, weight, port, target = rdata['priority'], rdata['weight'], rdata['port'], rdata['target'] print("SRV {0} --> {1} {2} {3} {4}".format(rrname, prio, weight, port, target)) else: print("getdns.service() returned an error: {0}".format(results.status)) getdns-python-bindings-1.0.0b1/examples/idn.py000077500000000000000000000007511267725536200213200ustar00rootroot00000000000000#!/usr/bin/env python # coding=utf-8 import getdns, sys try: ulabel = getdns.alabel_to_ulabel('xn--p1acf') # Next line contains a utf-8 string alabel = getdns.ulabel_to_alabel('рус') ulabel1 = getdns.alabel_to_ulabel('xn--vermgensberatung-pwb') # Next line contains a utf-8 string alabel1 = getdns.ulabel_to_alabel('vermögensberatung') except getdns.error as e: print(str(e)) sys.exit(1) print (ulabel) print (alabel) print (ulabel1) print (alabel1) getdns-python-bindings-1.0.0b1/examples/pinset.py000077500000000000000000000011151267725536200220430ustar00rootroot00000000000000# # Note that we expect that each pin in the pinset list # must be prefaced with pin-= and the pin # itself must be base64-encoded and enclosed in double- # quotes. We may loosen this up in a future version # import getdns c = getdns.Context() u = [ { 'address_data': '185.49.141.37', 'address_type': 'IPv4', 'tls_pubkey_pinset': ['pin-sha256="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9S="'] }] c.resolution_type = getdns.RESOLUTION_STUB c.dns_transport_list = [ getdns.TRANSPORT_TLS ] c.upstream_recursive_servers = u f = c.address('getdnsapi.net') getdns-python-bindings-1.0.0b1/examples/print-context.py000077500000000000000000000002721267725536200233620ustar00rootroot00000000000000#!/usr/bin/env python # import getdns, sys, pprint ctx = getdns.Context() try: pprint.pprint(ctx.get_api_information()) except getdns.error as e: print(str(e)) sys.exit(1) getdns-python-bindings-1.0.0b1/examples/print-version.py000077500000000000000000000002651267725536200233650ustar00rootroot00000000000000#!/usr/bin/env python import getdns ctx = getdns.Context() try: print(ctx.get_api_information()['version_string']) except getdns.error as e: print(str(e)) sys.exit(1) getdns-python-bindings-1.0.0b1/examples/query-gdns.py000077500000000000000000000017371267725536200226510ustar00rootroot00000000000000#!/usr/bin/env python # # Use stub mode with google public DNS as recursive resolvers # to query addresses associated with a host. # import getdns, sys, pprint google_public_dns = [ {'address_data': '8.8.8.8', 'address_type': 'IPv4'}, {'address_data': '8.8.4.4', 'address_type': 'IPv4'}, {'address_data': '2001:4860:4860::8888', 'address_type': 'IPv6'}, {'address_data': '2001:4860:4860::8844', 'address_type': 'IPv6'}, ] hostname = sys.argv[1] ctx = getdns.Context() ctx.resolution_type = getdns.RESOLUTION_STUB ctx.upstream_recursive_servers = google_public_dns extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } try: results = ctx.address(name=hostname, extensions=extensions) except getdns.error as e: print(str(e)) sys.exit(1) if results.status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: print(addr["address_data"]) else: print("getdns.address() returned an error: %d".format(results.status)) getdns-python-bindings-1.0.0b1/examples/query-stubmode.py000077500000000000000000000011161267725536200235270ustar00rootroot00000000000000#!/usr/bin/env python import getdns, sys hostname = sys.argv[1] ctx = getdns.Context() ctx.resolution_type = getdns.RESOLUTION_STUB extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } ctx.resolution_type = getdns.RESOLUTION_STUB try: results = ctx.address(name=hostname, extensions=extensions) except getdns.error as e: print(str(e)) sys.exit(1) if results.status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: print(addr["address_data"]) else: print("getdns.address() returned an error: {0}".format(results["status"])) getdns-python-bindings-1.0.0b1/examples/simple.py000077500000000000000000000011711267725536200220340ustar00rootroot00000000000000#!/usr/bin/env python # """ simple.py A simple example to query a domain name and print out addresses associated with it. """ import sys, getdns hostname = sys.argv[1] ctx = getdns.Context() extensions = { 'return_both_v4_and_v6' : getdns.EXTENSION_TRUE } try: results = ctx.address(name=hostname, extensions=extensions) except: e = sys.exc.info()[0] print(str(e)) sys.exit(1) status = results.status if status == getdns.RESPSTATUS_GOOD: for addr in results.just_address_answers: print (addr['address_data']) else: print("{0}: getdns.address() returned error: {1}".format((hostname, status))) getdns-python-bindings-1.0.0b1/examples/tsig_demo.py000077500000000000000000000007751267725536200225260ustar00rootroot00000000000000import getdns import base64 u = [ { 'address_data': '185.49.141.37', 'address_type': 'IPv4', 'tsig_algorithm': 'hmac-md5.sig-alg.reg.int', 'tsig_name': 'hmac-md5.tsigs.getdnsapi.net', 'tsig_secret': base64.b64decode('16G69OTeXW6xSQ==') }] c = getdns.Context() c.resolution_type = getdns.RESOLUTION_STUB c.upstream_recursive_servers = u f = c.general('getdnsapi.net', request_type = getdns.RRTYPE_SOA) print('tsig_status is {0}'.format(f.replies_tree[0]['tsig_status'])) getdns-python-bindings-1.0.0b1/getdns.c000066400000000000000000000722321267725536200200060ustar00rootroot00000000000000/** * * \file getdns.c * @brief pygetdns core functions and classes * */ /* * Copyright (c) 2014, Verisign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Include. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "pygetdns.h" PyObject *getdns_error; static PyObject *get_errorstr_by_id(PyObject *self, PyObject *args, PyObject *keywds); static PyObject *root_trust_anchor(PyObject *self, PyObject *args, PyObject *keywds); static void add_getdns_constants(PyObject *g); static PyObject *ulabel_to_alabel(PyObject *self, PyObject *args, PyObject *keywds); static PyObject *alabel_to_ulabel(PyObject *self, PyObject *args, PyObject *keywds); static PyObject *wire_to_dict(PyObject *self, PyObject *args, PyObject *keywds); static struct PyMethodDef getdns_methods[] = { { "get_errorstr_by_id", (PyCFunction)get_errorstr_by_id, METH_VARARGS|METH_KEYWORDS, "return getdns error text by error id" }, { "root_trust_anchor", (PyCFunction)root_trust_anchor, METH_NOARGS, "retrieve default list of trust anchor records used to validate DNSSEC" }, { "alabel_to_ulabel", (PyCFunction)alabel_to_ulabel, METH_VARARGS|METH_KEYWORDS, "return ulabel from alabel" }, { "ulabel_to_alabel", (PyCFunction)ulabel_to_alabel, METH_VARARGS|METH_KEYWORDS, "return alabel from ulabel" }, { "wire_to_dict", (PyCFunction)wire_to_dict, METH_VARARGS, "convert a wire format buffer to a Python dictionary" }, { 0, 0, 0 } }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef getdnsdef = { PyModuleDef_HEAD_INIT, "getdns", /* m_name */ GETDNS_DOCSTRING, /* m_doc */ -1, /* m_size */ getdns_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; #endif PyMemberDef Result_members[] = { { "just_address_answers", T_OBJECT_EX, offsetof(getdns_ResultObject, just_address_answers), READONLY, "Only the query answers" }, { "replies_tree", T_OBJECT_EX, offsetof(getdns_ResultObject, replies_tree), READONLY, "The replies tree dictionary" }, { "replies_full", T_OBJECT_EX, offsetof(getdns_ResultObject, replies_full), READONLY, "The entire replies structure returned by getdns" }, { "status", T_OBJECT_EX, offsetof(getdns_ResultObject, status), READONLY, "Response status" }, { "answer_type", T_OBJECT_EX, offsetof(getdns_ResultObject, answer_type), READONLY, "Answer type" }, { "canonical_name", T_OBJECT_EX, offsetof(getdns_ResultObject, canonical_name), READONLY, "Canonical name" }, { "validation_chain", T_OBJECT_EX, offsetof(getdns_ResultObject, validation_chain), READONLY, "DNSSEC certificate chain" }, #if GETDNS_NUMERIC_VERSION < 0x00090000 { "call_debugging", T_OBJECT_EX, offsetof(getdns_ResultObject, call_debugging), READONLY, "Query debugging info" }, #else { "call_reporting", T_OBJECT_EX, offsetof(getdns_ResultObject, call_reporting), READONLY, "Return call reporting data" }, #endif { NULL }, }; static PyMethodDef Result_methods[] = { { NULL }, }; PyTypeObject getdns_ResultType = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #endif "getdns.Result", /*tp_name*/ sizeof(getdns_ResultObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)result_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ result_str, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ result_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Result objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Result_methods, /* tp_methods */ Result_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)result_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ }; PyMethodDef Context_methods[] = { { "get_api_information", (PyCFunction)context_get_api_information, METH_NOARGS, "Return context settings" }, { "general", (PyCFunction)context_general, METH_VARARGS|METH_KEYWORDS, "method for looking up any type of DNS record" }, { "address", (PyCFunction)context_address, METH_VARARGS|METH_KEYWORDS, "method for looking up an address given a host name" }, { "hostname", (PyCFunction)context_hostname, METH_VARARGS|METH_KEYWORDS, "method for looking up a host name given an IP address" }, { "service", (PyCFunction)context_service, METH_VARARGS|METH_KEYWORDS, "method for looking up relevant SRV record for a name" }, { "run", (PyCFunction)context_run, METH_VARARGS|METH_KEYWORDS, "run unprocessed events" }, { "cancel_callback", (PyCFunction)context_cancel_callback, METH_VARARGS|METH_KEYWORDS, "cancel outstanding callbacks" }, { "get_supported_attributes", (PyCFunction)context_get_attributes, METH_NOARGS, "Return a list of support attributes" }, { NULL } }; PyMemberDef Context_members[] = { { "timeout", T_INT, offsetof(getdns_ContextObject, timeout), 0, "timeout in milliseconds" }, { "resolution_type", T_INT, offsetof(getdns_ContextObject, resolution_type), 0, "lookup as recursive or stub resolver" }, { "dns_transport_list", T_OBJECT, offsetof(getdns_ContextObject, dns_transport_list), 0, "ordered list of dns transports" }, { "limit_outstanding_queries", T_INT, offsetof(getdns_ContextObject, limit_outstanding_queries), 0, "limit on the number of unanswered queries" }, { "follow_redirects", T_INT, offsetof(getdns_ContextObject, follow_redirects), 0, "follow redirects" }, { "append_name", T_INT, offsetof(getdns_ContextObject, append_name), 0, "append a suffix to the query string before resolving name" }, { "dnssec_allowed_skew", T_INT, offsetof(getdns_ContextObject, dnssec_allowed_skew), 0, "number of seconds of skew allowed when checking RRSIG Expiration and Inception fields" }, { "edns_maximum_udp_payload_size", T_INT, offsetof(getdns_ContextObject, edns_maximum_udp_payload_size), 0, "edns maximum udp payload size" }, { "edns_extended_rcode", T_INT, offsetof(getdns_ContextObject, edns_extended_rcode), 0, "edns extended rcode" }, { "edns_do_bit", T_INT, offsetof(getdns_ContextObject, edns_do_bit), 0, "edns do bit" }, { "edns_version", T_INT, offsetof(getdns_ContextObject, edns_version), 0, "edns version" }, { "namespaces", T_OBJECT, offsetof(getdns_ContextObject, namespaces), 0, "ordered list of namespaces to be queried" }, { "dns_root_servers", T_OBJECT, offsetof(getdns_ContextObject, dns_root_servers), 0, "list of dictionaries of root servers" }, { "dnssec_trust_anchors", T_OBJECT, offsetof(getdns_ContextObject, dnssec_trust_anchors), 0, "list of trust anchors" }, { "suffix", T_OBJECT, offsetof(getdns_ContextObject, suffix), 0, "list of strings to be appended to search strings" }, { "upstream_recursive_servers", T_OBJECT, offsetof(getdns_ContextObject, upstream_recursive_servers), 0, "list of dictionaries defining where a stub resolver will send queries" }, { "implementation_string", T_STRING|READONLY, offsetof(getdns_ContextObject, implementation_string), 0, "string set by the implementer" }, { "version_string", T_STRING|READONLY, offsetof(getdns_ContextObject, version_string), 0, "string set by the implementer" }, {"idle_timeout", T_INT, offsetof(getdns_ContextObject, idle_timeout), 0, "TCP idle timeout" }, {"tls_authentication", T_INT, offsetof(getdns_ContextObject, tls_authentication), 0, "TLS authentication basis" }, {"num_pending_requests", T_INT, offsetof(getdns_ContextObject, num_pending_requests), READONLY, "count of outstanding requests" }, #if GETDNS_NUMERIC_VERSION > 0x00050000 {"tls_query_padding_blocksize", T_INT, offsetof(getdns_ContextObject, tls_query_padding_blocksize), 0, "padding blocksize" }, { "edns_client_subnet_private", T_INT, offsetof(getdns_ContextObject, edns_client_subnet_private), 0, "ask upstreams not to reveal query's originating network" }, #endif { NULL } }; PyTypeObject getdns_ContextType = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, #endif "getdns.Context", sizeof(getdns_ContextObject), 0, /*tp_itemsize*/ (destructor)context_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /*tp_compare*/ context_str, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ context_str, /*tp_str*/ context_getattro, /*tp_getattro*/ context_setattro, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Context object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Context_methods, /* tp_methods */ Context_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)context_init, /* tp_init */ }; static PyObject * alabel_to_ulabel(PyObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "alabel", NULL }; char *alabel; char *ulabel; if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", kwlist, &alabel)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } ulabel = (char*)getdns_convert_alabel_to_ulabel((char*)alabel); #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromString(ulabel); #else return PyString_FromString(ulabel); #endif } static PyObject * ulabel_to_alabel(PyObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "ulabel", NULL }; char *alabel; char *ulabel; if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", kwlist, &ulabel)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } alabel = (char*)getdns_convert_ulabel_to_alabel((char*)ulabel); #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromString(alabel); #else return PyString_FromString(alabel); #endif } static PyObject * wire_to_dict(PyObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "wirebuf", NULL }; int nbytes; uint8_t *wirebuf; getdns_dict *rrdict; PyObject *py_rrdict; getdns_return_t ret; if (!PyArg_ParseTupleAndKeywords(args, keywds, "t#", kwlist, &wirebuf, &nbytes)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } printf("len = %d\n", nbytes); if ((ret = getdns_wire2rr_dict(wirebuf, (size_t)nbytes, &rrdict)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_rrdict = gdict_to_pdict(rrdict)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } return py_rrdict; } static PyObject * get_errorstr_by_id(PyObject *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = { "id", NULL }; int id; char *errstr; if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &id)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if ((errstr = (char *)getdns_get_errorstr_by_id((uint16_t)id)) == 0) return Py_None; else #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromString(errstr); #else return PyString_FromString(errstr); #endif } static PyObject * root_trust_anchor(PyObject *self, PyObject *args, PyObject *keywds) { getdns_list *trust_anchors; time_t anchors_date; struct tm *but; /* busted out time */ PyObject *pdate; PyObject *ta_tuple; PyDateTime_IMPORT; if ((trust_anchors = getdns_root_trust_anchor(&anchors_date)) == NULL) Py_RETURN_NONE; but = gmtime(&anchors_date); pdate = PyDateTime_FromDateAndTime(but->tm_year+1900, but->tm_mon+1, but->tm_mday, but->tm_hour, but->tm_min, but->tm_sec, 0); ta_tuple = PyTuple_Pack(2, glist_to_plist(trust_anchors), pdate); Py_INCREF(ta_tuple); return ta_tuple; } #if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit_getdns(void) { PyObject *g; /* the getdns module object */ Py_Initialize(); if ((g = PyModule_Create(&getdnsdef)) == NULL) { PyErr_SetString(PyExc_ImportError, "Unable to initialize getdns"); return NULL; } getdns_error = PyErr_NewException("getdns.error", NULL, NULL); Py_INCREF(getdns_error); PyModule_AddObject(g, "error", getdns_error); getdns_ContextType.tp_new = PyType_GenericNew; getdns_ResultType.tp_new = PyType_GenericNew; if (PyType_Ready(&getdns_ResultType) < 0) { PyErr_SetString(PyExc_ImportError, "Unable to initialize getdns"); return NULL; } Py_INCREF(&getdns_ResultType); PyModule_AddObject(g, "Result", (PyObject *)&getdns_ResultType); if (PyType_Ready(&getdns_ContextType) < 0) { PyErr_SetString(PyExc_ImportError, "Unable to initialize getdns"); return NULL; } Py_INCREF(&getdns_ContextType); PyModule_AddObject(g, "Context", (PyObject *)&getdns_ContextType); PyModule_AddStringConstant(g, "__version__", PYGETDNS_VERSION); add_getdns_constants(g); return g; } #else PyMODINIT_FUNC initgetdns(void) { PyObject *g; Py_Initialize(); if ((g = Py_InitModule3("getdns", getdns_methods, GETDNS_DOCSTRING)) == NULL) return; getdns_error = PyErr_NewException("getdns.error", NULL, NULL); Py_INCREF(getdns_error); PyModule_AddObject(g, "error", getdns_error); getdns_ContextType.tp_new = PyType_GenericNew; getdns_ResultType.tp_new = PyType_GenericNew; if (PyType_Ready(&getdns_ResultType) < 0) return; Py_INCREF(&getdns_ResultType); PyModule_AddObject(g, "Result", (PyObject *)&getdns_ResultType); if (PyType_Ready(&getdns_ContextType) < 0) return; Py_INCREF(&getdns_ContextType); PyModule_AddObject(g, "Context", (PyObject *)&getdns_ContextType); PyModule_AddStringConstant(g, "__version__", PYGETDNS_VERSION); add_getdns_constants(g); } #endif static void add_getdns_constants(PyObject *g) { /* * return value constants */ PyModule_AddIntConstant(g, "RETURN_GOOD", 0); PyModule_AddIntConstant(g, "RETURN_GENERIC_ERROR", 1); PyModule_AddIntConstant(g, "RETURN_BAD_DOMAIN_NAME", 300); PyModule_AddIntConstant(g, "RETURN_BAD_CONTEXT", 301); PyModule_AddIntConstant(g, "RETURN_CONTEXT_UPDATE_FAIL", 302); PyModule_AddIntConstant(g, "RETURN_UNKNOWN_TRANSACTION", 303); PyModule_AddIntConstant(g, "RETURN_NO_SUCH_LIST_ITEM", 304); PyModule_AddIntConstant(g, "RETURN_NO_SUCH_DICT_NAME", 305); PyModule_AddIntConstant(g, "RETURN_WRONG_TYPE_REQUESTED", 306); PyModule_AddIntConstant(g, "RETURN_NO_SUCH_EXTENSION", 307); PyModule_AddIntConstant(g, "RETURN_EXTENSION_MISFORMAT", 308); PyModule_AddIntConstant(g, "RETURN_DNSSEC_WITH_STUB_DISALLOWED", 309); PyModule_AddIntConstant(g, "RETURN_MEMORY_ERROR", 310); PyModule_AddIntConstant(g, "RETURN_INVALID_PARAMETER", 311); PyModule_AddIntConstant(g, "RETURN_NOT_IMPLEMENTED", 312); /* * dnssec values */ PyModule_AddIntConstant(g, "DNSSEC_SECURE", 400); PyModule_AddIntConstant(g, "DNSSEC_BOGUS", 401); PyModule_AddIntConstant(g, "DNSSEC_INDETERMINATE", 402); PyModule_AddIntConstant(g, "DNSSEC_INSECURE", 403); PyModule_AddIntConstant(g, "DNSSEC_NOT_PERFORMED", 404); /* * namespace types */ PyModule_AddIntConstant(g, "NAMESPACE_DNS", 500); PyModule_AddIntConstant(g, "NAMESPACE_LOCALNAMES", 501); PyModule_AddIntConstant(g, "NAMESPACE_NETBIOS", 502); PyModule_AddIntConstant(g, "NAMESPACE_MDNS", 503); PyModule_AddIntConstant(g, "NAMESPACE_NIS", 504); /* * resolution types */ PyModule_AddIntConstant(g, "RESOLUTION_STUB", 520); PyModule_AddIntConstant(g, "RESOLUTION_RECURSING", 521); /* * redirect policies */ PyModule_AddIntConstant(g, "REDIRECTS_FOLLOW", 530); PyModule_AddIntConstant(g, "REDIRECTS_DO_NOT_FOLLOW", 531); /* * transport arrangements */ PyModule_AddIntConstant(g, "TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", 540); PyModule_AddIntConstant(g, "TRANSPORT_UDP_ONLY", 541); PyModule_AddIntConstant(g, "TRANSPORT_TCP_ONLY", 542); PyModule_AddIntConstant(g, "TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", 543); /* * misc. implementation-specific constants */ PyModule_AddIntConstant(g, "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", 618); PyModule_AddIntConstant(g, "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", 619); PyModule_AddIntConstant(g, "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620); PyModule_AddIntConstant(g, "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", 621); /* * transport list constants */ PyModule_AddIntConstant(g, "TRANSPORT_UDP", 1200); PyModule_AddIntConstant(g, "TRANSPORT_TCP", 1201); PyModule_AddIntConstant(g, "TRANSPORT_TLS", 1202); /* * suffix appending methods */ PyModule_AddIntConstant(g, "APPEND_NAME_ALWAYS", 550); PyModule_AddIntConstant(g, "APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", 551); PyModule_AddIntConstant(g, "APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", 552); PyModule_AddIntConstant(g, "APPEND_NAME_NEVER", 553); PyModule_AddIntConstant(g, "GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST", 554); /* * context codes */ PyModule_AddIntConstant(g, "CONTEXT_CODE_NAMESPACES", 600); PyModule_AddIntConstant(g, "CONTEXT_CODE_RESOLUTION_TYPE", 601); PyModule_AddIntConstant(g, "CONTEXT_CODE_FOLLOW_REDIRECTS", 602); PyModule_AddIntConstant(g, "CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", 603); PyModule_AddIntConstant(g, "CONTEXT_CODE_DNS_ROOT_SERVERS", 604); PyModule_AddIntConstant(g, "CONTEXT_CODE_DNS_TRANSPORT", 605); PyModule_AddIntConstant(g, "CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", 606); PyModule_AddIntConstant(g, "CONTEXT_CODE_APPEND_NAME", 607); PyModule_AddIntConstant(g, "CONTEXT_CODE_SUFFIX", 608); PyModule_AddIntConstant(g, "CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", 609); PyModule_AddIntConstant(g, "CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", 610); PyModule_AddIntConstant(g, "CONTEXT_CODE_EDNS_EXTENDED_RCODE", 611); PyModule_AddIntConstant(g, "CONTEXT_CODE_EDNS_VERSION", 612); PyModule_AddIntConstant(g, "CONTEXT_CODE_EDNS_DO_BIT", 613); PyModule_AddIntConstant(g, "CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", 614); PyModule_AddIntConstant(g, "CONTEXT_CODE_MEMORY_FUNCTIONS", 615); PyModule_AddIntConstant(g, "CONTEXT_CODE_TIMEOUT", 616); PyModule_AddIntConstant(g, "CONTEXT_CODE_IDLE_TIMEOUT", 617); /* * callback types */ PyModule_AddIntConstant(g, "CALLBACK_COMPLETE", 700); PyModule_AddIntConstant(g, "CALLBACK_CANCEL", 701); PyModule_AddIntConstant(g, "CALLBACK_TIMEOUT", 702); PyModule_AddIntConstant(g, "CALLBACK_ERROR", 703); /* * name service types */ PyModule_AddIntConstant(g, "GETDNS_NAMETYPE_DNS", 800); PyModule_AddIntConstant(g, "GETDNS_NAMETYPE_WINS", 801); PyModule_AddIntConstant(g, "RESPSTATUS_GOOD", 900); PyModule_AddIntConstant(g, "RESPSTATUS_NO_NAME", 901); PyModule_AddIntConstant(g, "RESPSTATUS_ALL_TIMEOUT", 902); PyModule_AddIntConstant(g, "RESPSTATUS_NO_SECURE_ANSWERS", 903); PyModule_AddIntConstant(g, "RESPSTATUS_ALL_BOGUS_ANSWERS", 904); PyModule_AddIntConstant(g, "EXTENSION_TRUE", 1000); PyModule_AddIntConstant(g, "EXTENSION_FALSE", 1001); PyModule_AddIntConstant(g, "BAD_DNS_CNAME_IN_TARGET", 1100); PyModule_AddIntConstant(g, "BAD_DNS_ALL_NUMERIC_LABEL", 1101); PyModule_AddIntConstant(g, "BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE", 1102); /* * rr type constants */ PyModule_AddIntConstant(g, "RRTYPE_A", 1); PyModule_AddIntConstant(g, "RRTYPE_NS", 2); PyModule_AddIntConstant(g, "RRTYPE_MD", 3); PyModule_AddIntConstant(g, "RRTYPE_MF", 4); PyModule_AddIntConstant(g, "RRTYPE_CNAME", 5); PyModule_AddIntConstant(g, "RRTYPE_SOA", 6); PyModule_AddIntConstant(g, "RRTYPE_MB", 7); PyModule_AddIntConstant(g, "RRTYPE_MG", 8); PyModule_AddIntConstant(g, "RRTYPE_MR", 9); PyModule_AddIntConstant(g, "RRTYPE_NULL", 10); PyModule_AddIntConstant(g, "RRTYPE_WKS", 11); PyModule_AddIntConstant(g, "RRTYPE_PTR", 12); PyModule_AddIntConstant(g, "RRTYPE_HINFO", 13); PyModule_AddIntConstant(g, "RRTYPE_MINFO", 14); PyModule_AddIntConstant(g, "RRTYPE_MX", 15); PyModule_AddIntConstant(g, "RRTYPE_TXT", 16); PyModule_AddIntConstant(g, "RRTYPE_RP", 17); PyModule_AddIntConstant(g, "RRTYPE_AFSDB", 18); PyModule_AddIntConstant(g, "RRTYPE_X25", 19); PyModule_AddIntConstant(g, "RRTYPE_ISDN", 20); PyModule_AddIntConstant(g, "RRTYPE_RT", 21); PyModule_AddIntConstant(g, "RRTYPE_NSAP", 22); PyModule_AddIntConstant(g, "RRTYPE_SIG", 24); PyModule_AddIntConstant(g, "RRTYPE_KEY", 25); PyModule_AddIntConstant(g, "RRTYPE_PX", 26); PyModule_AddIntConstant(g, "RRTYPE_GPOS", 27); PyModule_AddIntConstant(g, "RRTYPE_AAAA", 28); PyModule_AddIntConstant(g, "RRTYPE_LOC", 29); PyModule_AddIntConstant(g, "RRTYPE_NXT", 30); PyModule_AddIntConstant(g, "RRTYPE_EID", 31); PyModule_AddIntConstant(g, "RRTYPE_NIMLOC", 32); PyModule_AddIntConstant(g, "RRTYPE_SRV", 33); PyModule_AddIntConstant(g, "RRTYPE_ATMA", 34); PyModule_AddIntConstant(g, "RRTYPE_NAPTR", 35); PyModule_AddIntConstant(g, "RRTYPE_KX", 36); PyModule_AddIntConstant(g, "RRTYPE_CERT", 37); PyModule_AddIntConstant(g, "RRTYPE_A6", 38); PyModule_AddIntConstant(g, "RRTYPE_DNAME", 39); PyModule_AddIntConstant(g, "RRTYPE_SINK", 40); PyModule_AddIntConstant(g, "RRTYPE_OPT", 41); PyModule_AddIntConstant(g, "RRTYPE_APL", 42); PyModule_AddIntConstant(g, "RRTYPE_DS", 43); PyModule_AddIntConstant(g, "RRTYPE_SSHFP", 44); PyModule_AddIntConstant(g, "RRTYPE_IPSECKEY", 45); PyModule_AddIntConstant(g, "RRTYPE_RRSIG", 46); PyModule_AddIntConstant(g, "RRTYPE_NSEC", 47); PyModule_AddIntConstant(g, "RRTYPE_DNSKEY", 48); PyModule_AddIntConstant(g, "RRTYPE_DHCID", 49); PyModule_AddIntConstant(g, "RRTYPE_NSEC3", 50); PyModule_AddIntConstant(g, "RRTYPE_NSEC3PARAM", 51); PyModule_AddIntConstant(g, "RRTYPE_TLSA", 52); PyModule_AddIntConstant(g, "RRTYPE_HIP", 55); PyModule_AddIntConstant(g, "RRTYPE_NINFO", 56); PyModule_AddIntConstant(g, "RRTYPE_RKEY", 57); PyModule_AddIntConstant(g, "RRTYPE_TALINK", 58); PyModule_AddIntConstant(g, "RRTYPE_CDS", 59); PyModule_AddIntConstant(g, "RRTYPE_CDNSKEY", 60); PyModule_AddIntConstant(g, "RRTYPE_OPENPGPKEY", 61); PyModule_AddIntConstant(g, "RRTYPE_CSYNC", 62); PyModule_AddIntConstant(g, "RRTYPE_SPF", 99); PyModule_AddIntConstant(g, "RRTYPE_UINFO", 100); PyModule_AddIntConstant(g, "RRTYPE_UID", 101); PyModule_AddIntConstant(g, "RRTYPE_GID", 102); PyModule_AddIntConstant(g, "RRTYPE_UNSPEC", 103); PyModule_AddIntConstant(g, "RRTYPE_NID", 104); PyModule_AddIntConstant(g, "RRTYPE_L32", 105); PyModule_AddIntConstant(g, "RRTYPE_L64", 106); PyModule_AddIntConstant(g, "RRTYPE_LP", 107); PyModule_AddIntConstant(g, "RRTYPE_EUI48", 108); PyModule_AddIntConstant(g, "RRTYPE_EUI64", 109); PyModule_AddIntConstant(g, "RRTYPE_TKEY", 249); PyModule_AddIntConstant(g, "RRTYPE_TSIG", 250); PyModule_AddIntConstant(g, "RRTYPE_IXFR", 251); PyModule_AddIntConstant(g, "RRTYPE_AXFR", 252); PyModule_AddIntConstant(g, "RRTYPE_MAILB", 253); PyModule_AddIntConstant(g, "RRTYPE_MAILA", 254); PyModule_AddIntConstant(g, "RRTYPE_ANY", 255); PyModule_AddIntConstant(g, "RRTYPE_URI", 256); PyModule_AddIntConstant(g, "RRTYPE_CAA", 257); PyModule_AddIntConstant(g, "RRTYPE_TA", 32768); PyModule_AddIntConstant(g, "RRTYPE_DLV", 32769); PyModule_AddIntConstant(g, "RRCLASS_IN", 1); PyModule_AddIntConstant(g, "RRCLASS_CH", 3); PyModule_AddIntConstant(g, "RRCLASS_HS", 4); PyModule_AddIntConstant(g, "RRCLASS_NONE", 254); PyModule_AddIntConstant(g, "RRCLASS_ANY", 255); PyModule_AddIntConstant(g, "OPCODE_QUERY", 0); PyModule_AddIntConstant(g, "OPCODE_IQUERY", 1); PyModule_AddIntConstant(g, "OPCODE_STATUS", 2); PyModule_AddIntConstant(g, "OPCODE_NOTIFY", 4); PyModule_AddIntConstant(g, "OPCODE_UPDATE", 5); PyModule_AddIntConstant(g, "RCODE_NOERROR", 0); PyModule_AddIntConstant(g, "RCODE_FORMERR", 1); PyModule_AddIntConstant(g, "RCODE_SERVFAIL", 2); PyModule_AddIntConstant(g, "RCODE_NXDOMAIN", 3); PyModule_AddIntConstant(g, "RCODE_NOTIMP", 4); PyModule_AddIntConstant(g, "RCODE_REFUSED", 5); PyModule_AddIntConstant(g, "RCODE_YXDOMAIN", 6); PyModule_AddIntConstant(g, "RCODE_YXRRSET", 7); PyModule_AddIntConstant(g, "RCODE_NXRRSET", 8); PyModule_AddIntConstant(g, "RCODE_NOTAUTH", 9); PyModule_AddIntConstant(g, "RCODE_NOTZONE", 10); PyModule_AddIntConstant(g, "RCODE_BADVERS", 16); PyModule_AddIntConstant(g, "RCODE_BADSIG", 16); PyModule_AddIntConstant(g, "RCODE_BADKEY", 17); PyModule_AddIntConstant(g, "RCODE_BADTIME", 18); PyModule_AddIntConstant(g, "RCODE_BADMODE", 19); PyModule_AddIntConstant(g, "RCODE_BADNAME", 20); PyModule_AddIntConstant(g, "RCODE_BADALG", 21); PyModule_AddIntConstant(g, "RCODE_BADTRUNC", 22); /* * extras */ /* * values for tls_authentication */ PyModule_AddIntConstant(g, "AUTHENTICATION_NONE", 1300); PyModule_AddIntConstant(g, "AUTHENTICATION_HOSTNAME", 1301); PyModule_AddIntConstant(g, "AUTHENTICATION_REQUIRED", 1301); } getdns-python-bindings-1.0.0b1/pygetdns.h000066400000000000000000000201021267725536200203510ustar00rootroot00000000000000/** * defines, declarations, and globals for pygetdns */ /* * Copyright (c) 2014, Versign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Include. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef PYGETDNS_H #define PYGETDNS_H #define PYGETDNS_VERSION "v1.0.0b" #define GETDNS_DOCSTRING "getdns bindings for Python (see http://www.getdnsapi.net)" #define GETDNS_STR_IPV4 "IPv4" #define GETDNS_STR_IPV6 "IPv6" #if !defined(UNUSED_PARAM) # define UNUSED_PARAM(x) ((void)(x)) #endif extern PyObject *getdns_error; typedef struct { PyObject_HEAD PyObject *just_address_answers; PyObject *answer_type; PyObject *status; PyObject *replies_tree; PyObject *canonical_name; PyObject *replies_full; PyObject *validation_chain; #if GETDNS_NUMERIC_VERSION < 0x00090000 PyObject *call_debugging; #else PyObject *call_reporting; #endif } getdns_ResultObject; typedef struct { PyObject *callback_func; char userarg[BUFSIZ]; } userarg_blob; typedef struct { PyObject_HEAD PyObject *py_context; /* Python capsule containing getdns_context */ uint64_t timeout; /* timeout attribute (milliseconds) */ uint64_t idle_timeout; /* TCP timeout attribute (milliseconds) */ getdns_resolution_t resolution_type; /* stub or recursive? */ #if 0 getdns_transport_t dns_transport; /* udp/tcp/etc */ #endif uint16_t limit_outstanding_queries; getdns_redirects_t follow_redirects; getdns_append_name_t append_name; getdns_list *suffix; uint32_t dnssec_allowed_skew; uint16_t edns_maximum_udp_payload_size; uint8_t edns_extended_rcode; uint8_t edns_do_bit; uint8_t edns_version; getdns_namespace_t *namespaces; getdns_list *dns_root_servers; getdns_list *dnssec_trust_anchors; getdns_list *upstream_recursive_servers; getdns_transport_list_t *dns_transport_list; char *implementation_string; char *version_string; uint16_t tls_authentication; uint32_t num_pending_requests; #if GETDNS_NUMERIC_VERSION > 0x00050000 uint16_t tls_query_padding_blocksize; uint8_t edns_client_subnet_private; #endif } getdns_ContextObject; struct setter_table { /* we're now using bsearch to find */ char *name; /* setters for attribute names - somewhat */ int (*setter)(getdns_context *, PyObject *); /* more efficient but much more maintainable */ }; extern PyTypeObject getdns_ResultType; void result_dealloc(getdns_ResultObject *self); extern PyObject *result_getattro(PyObject *self, PyObject *nameobj); PyObject *py_result(PyObject *result_capsule); PyObject *result_create(struct getdns_dict *resp); PyObject *result_str(PyObject *self); int get_status(struct getdns_dict *result_dict); int get_answer_type(struct getdns_dict *result_dict); char *get_canonical_name(struct getdns_dict *result_dict); PyObject *get_just_address_answers(struct getdns_dict *result_dict); PyObject *get_replies_tree(struct getdns_dict *result_dict); PyObject *get_validation_chain(struct getdns_dict *result_dict); #if GETDNS_NUMERIC_VERSION < 0x00090000 PyObject *get_call_debugging(struct getdns_dict *result_dict); #else PyObject *get_call_reporting(struct getdns_dict *result_dict); #endif int context_init(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_getattro(PyObject *self, PyObject *nameobj); int context_setattro(PyObject *self, PyObject *attrname, PyObject *value); int context_set_timeout(getdns_context *context, PyObject *py_value); int context_set_resolution_type(getdns_context *context, PyObject *py_value); int context_set_dns_transport(getdns_context *context, PyObject *py_value); int context_set_limit_outstanding_queries(getdns_context *context, PyObject *py_value); int context_set_follow_redirects(getdns_context *context, PyObject *py_value); int context_set_append_name(getdns_context *context, PyObject *py_value); int context_set_suffix(getdns_context *context, PyObject *py_value); int context_set_dnssec_allowed_skew(getdns_context *context, PyObject *py_value); int context_set_edns_maximum_udp_payload_size(getdns_context *context, PyObject *py_value); int context_set_edns_extended_rcode(getdns_context *context, PyObject *py_value); int context_set_edns_version(getdns_context *context, PyObject *py_value); int context_set_namespaces(getdns_context *context, PyObject *py_value); int context_set_dns_root_servers(getdns_context *context, PyObject *py_value); int context_set_dnssec_trust_anchors(getdns_context *context, PyObject *py_value); int context_set_upstream_recursive_servers(getdns_context *context, PyObject *py_value); int context_set_edns_do_bit(getdns_context *context, PyObject *py_value); int context_set_dns_transport_list(getdns_context *context, PyObject *py_value); int context_set_tls_query_padding_blocksize(getdns_context *context, PyObject *py_value); int context_set_edns_client_subnet_private(getdns_context *context, PyObject *py_value); PyObject *context_str(PyObject *self); PyObject *context_get_api_information(getdns_ContextObject *self, PyObject *unused); PyObject *context_general(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_address(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_hostname(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_service(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_run(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_cancel_callback(getdns_ContextObject *self, PyObject *args, PyObject *keywds); PyObject *context_get_attributes(getdns_ContextObject *self, PyObject *unused); void context_dealloc(getdns_ContextObject *self); PyObject *get_callback(char *py_main, char *callback); void callback_shim(struct getdns_context *context, getdns_callback_type_t type, struct getdns_dict *response, void *userarg, getdns_transaction_t tid); int result_init(getdns_ResultObject *self, PyObject *args, PyObject *keywds); PyObject *result_getattro(PyObject *self, PyObject *nameobj); int result_setattro(PyObject *self, PyObject *attrname, PyObject *value); PyObject *pythonify_address_list(getdns_list *list); PyObject *glist_to_plist(struct getdns_list *list); PyObject *gdict_to_pdict(struct getdns_dict *dict); PyObject *convertBinData(getdns_bindata* data, const char* key); struct getdns_dict *extensions_to_getdnsdict(PyDictObject *); PyObject *decode_getdns_response(struct getdns_dict *); PyObject *decode_getdns_replies_tree_response(struct getdns_dict *response); PyObject *getFullResponse(struct getdns_dict *dict); getdns_dict *getdnsify_addressdict(PyObject *pydict); PyObject *convertToDict(struct getdns_dict* dict); #endif /* PYGETDNS_H */ getdns-python-bindings-1.0.0b1/pygetdns_util.c000066400000000000000000001267631267725536200214250ustar00rootroot00000000000000/* * \ file pygetdns_util.c * @brief utility functions to support pygetdns bindings */ /* * Copyright (c) 2014, Verisign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Include. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "pygetdns.h" int get_status(struct getdns_dict *result_dict) { uint32_t status; getdns_return_t ret; if ((ret = getdns_dict_get_int(result_dict, "status", &status)) != GETDNS_RETURN_GOOD) return 0; return (int)status; } int get_answer_type(struct getdns_dict *result_dict) { uint32_t answer_type; getdns_return_t ret; if ((ret = getdns_dict_get_int(result_dict, "answer_type", &answer_type)) != GETDNS_RETURN_GOOD) return 0; return (int)answer_type; } char * get_canonical_name(struct getdns_dict *result_dict) { getdns_bindata *canonical_name; getdns_return_t ret; if ((ret = getdns_dict_get_bindata(result_dict, "canonical_name", &canonical_name)) == GETDNS_RETURN_GOOD) { char *dname = 0; if (getdns_convert_dns_name_to_fqdn(canonical_name, &dname) == GETDNS_RETURN_GOOD) return dname; else return (char *)canonical_name->data; } else return 0; } PyObject * get_just_address_answers(struct getdns_dict *result_dict) { struct getdns_list *just_address_answers; getdns_return_t ret; if ((ret = getdns_dict_get_list(result_dict, "just_address_answers", &just_address_answers)) != GETDNS_RETURN_GOOD) return NULL; return pythonify_address_list(just_address_answers); } PyObject * get_replies_tree(struct getdns_dict *result_dict) { struct getdns_list *replies_tree; getdns_return_t ret; if ((ret = getdns_dict_get_list(result_dict, "replies_tree", &replies_tree)) != GETDNS_RETURN_GOOD) return NULL; return glist_to_plist(replies_tree); } PyObject * get_validation_chain(struct getdns_dict *result_dict) { struct getdns_list *validation_chain; getdns_return_t ret; if ((ret = getdns_dict_get_list(result_dict, "validation_chain", &validation_chain)) != GETDNS_RETURN_GOOD) Py_RETURN_NONE; else return glist_to_plist(validation_chain); } #if GETDNS_NUMERIC_VERSION < 0x00090000 PyObject * get_call_debugging(struct getdns_dict *result_dict) #else PyObject * get_call_reporting(struct getdns_dict *result_dict) #endif { #if GETDNS_NUMERIC_VERSION < 0x00090000 struct getdns_list *call_debugging; #else struct getdns_list *call_reporting; #endif getdns_return_t ret; #if GETDNS_NUMERIC_VERSION < 0x00090000 if ((ret = getdns_dict_get_list(result_dict, "call_debugging", &call_debugging)) != #else if ((ret = getdns_dict_get_list(result_dict, "call_reporting", &call_reporting)) != #endif GETDNS_RETURN_GOOD) Py_RETURN_NONE; else #if GETDNS_NUMERIC_VERSION < 0x00090000 return glist_to_plist(call_debugging); #else return glist_to_plist(call_reporting); #endif } struct getdns_dict * extensions_to_getdnsdict(PyDictObject *pydict) { struct getdns_dict *newdict = 0; Py_ssize_t pos = 0, optiondictpos = 0, optionlistpos = 0; PyObject *key, *value; char *tmpoptionlistkey; struct getdns_list *optionslist = 0; /* for options list */ int optionlistsize; /* how many options in options list */ int i; /* loop counter */ PyObject *optionitem; PyObject *optiondictkey, *optiondictvalue; /* for processing option list dicts */ struct getdns_bindata *option_data; struct getdns_dict *tmpoptions_list_dict; /* a dict to hold add_opt_parameters[options] stuff */ if ((!pydict) || (!PyDict_Check(pydict))) { PyErr_SetString(getdns_error, "Expected dict, didn't get one"); return NULL; } newdict = getdns_dict_create(); /* this is what we'll return */ while (PyDict_Next((PyObject *)pydict, &pos, &key, &value)) { /* these options take TRUE or FALSE args */ char *tmp_key; int tmp_int; #if PY_MAJOR_VERSION >= 3 tmp_key = PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(key), "ascii", NULL)); #else tmp_key = PyString_AsString(PyObject_Str(key)); #endif if ( (!strncmp(tmp_key, "dnssec_return_status", strlen("dnssec_return_status"))) || (!strncmp(tmp_key, "dnssec_return_all_statuses", strlen("dnssec_return_all_statuses"))) || (!strncmp(tmp_key, "dnssec_return_only_secure", strlen("dnssec_return_only_secure"))) || (!strncmp(tmp_key, "dnssec_return_validation_chain", strlen("dnssec_return_validation_chain"))) || (!strncmp(tmp_key, "return_both_v4_and_v6", strlen("return_both_v4_and_v6"))) || (!strncmp(tmp_key, "return_api_information", strlen("return_api_information"))) || #if GETDNS_NUMERIC_VERSION < 0x00090000 (!strncmp(tmp_key, "return_call_debugging", strlen("return_call_debugging"))) || #else (!strncmp(tmp_key, "return_call_reporting", strlen("return_call_reporting"))) || #endif (!strncmp(tmp_key, "add_warning_for_bad_dns", strlen("add_warning_for_bad_dns"))) ) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value)) { #else if (!PyInt_Check(value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 if ( !((PyLong_AsLong(value) == GETDNS_EXTENSION_TRUE) || (PyLong_AsLong(value) == GETDNS_EXTENSION_FALSE)) ) { #else if ( !((PyInt_AsLong(value) == GETDNS_EXTENSION_TRUE) || (PyInt_AsLong(value) == GETDNS_EXTENSION_FALSE)) ) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 tmp_int = (int)PyLong_AsLong(value); #else tmp_int = (int)PyInt_AsLong(value); #endif (void)getdns_dict_set_int(newdict, tmp_key, tmp_int); } else if (!strncmp(tmp_key, "specify_class", strlen("specify_class"))) { /* takes integer */ #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value)) { #else if (!PyInt_Check(value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 tmp_int = (int)PyLong_AsLong(value); #else tmp_int = (int)PyInt_AsLong(value); #endif (void)getdns_dict_set_int(newdict, tmp_key, tmp_int); /* * dns OPT resource record setup * * extensions['add_opt_parameters'][option_name] */ } else if (!strncmp(tmp_key, "add_opt_parameters", strlen("add_opt_parameters"))) { /* this is a dict */ PyObject *in_optdict; /* points at dictionary passed in */ struct getdns_dict *out_optdict = 0; Py_ssize_t opt_pos = 0; PyObject *opt_key, *opt_value; char *tmp_opt_key; int optint; in_optdict = value; if (!PyDict_Check(in_optdict)) { PyErr_SetString(getdns_error, "Expected dict, didn't get one"); return NULL; } out_optdict = getdns_dict_create(); while (PyDict_Next((PyObject *)in_optdict, &opt_pos, &opt_key, &opt_value)) { #if PY_MAJOR_VERSION >= 3 tmp_opt_key = PyBytes_AsString(PyUnicode_AsEncodedString(opt_key, "ascii", NULL)); #else tmp_opt_key = PyString_AsString(opt_key); #endif if ( (!strncmp(tmp_opt_key, "maximum_udp_payload_size", strlen("maximum_udp_payload_size"))) || (!strncmp(tmp_opt_key, "extended_rcode", strlen("extended_rcode"))) || (!strncmp(tmp_opt_key, "version", strlen("version"))) || (!strncmp(tmp_opt_key, "do_bit", strlen("do_bit"))) ) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(opt_value)) { #else if (!PyInt_Check(opt_value)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 optint = (int)PyLong_AsLong(opt_value); #else optint = (int)PyInt_AsLong(opt_value); #endif (void)getdns_dict_set_int(out_optdict, tmp_opt_key, optint); } else if (!strncmp(tmp_opt_key, "options", strlen("options"))) { /* options */ /* * options with arbitrary opt code * * add_opt_parameters is a dict containing * options is a list containing * dicts for each option containing * option_code (int) * option_data (bindata) * */ if (!PyList_Check(opt_value)) { PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } optionslist = getdns_list_create(); optionlistsize = (int)PyList_Size(opt_value); for ( i = 0 ; i < optionlistsize ; i++) { tmpoptions_list_dict = getdns_dict_create(); optionitem = PyList_GetItem(opt_value, i); if (!PyDict_Check(optionitem)) { PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } /* optionitem should be a dict with keys option_code and option_data */ while (PyDict_Next(optionitem, &optiondictpos, &optiondictkey, &optiondictvalue)) { #if PY_MAJOR_VERSION >= 3 tmpoptionlistkey = PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Str(optiondictkey), "ascii", NULL)); /* XXX */ #else tmpoptionlistkey = PyString_AsString(PyObject_Str(optiondictkey)); #endif if (!strncmp(tmpoptionlistkey, "option_code", strlen("option_code"))) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(optiondictvalue)) { #else if (!PyInt_Check(optiondictvalue)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 getdns_dict_set_int(tmpoptions_list_dict, "option_code", (uint32_t)PyLong_AsLong(optiondictvalue)); #else getdns_dict_set_int(tmpoptions_list_dict, "option_code", (uint32_t)PyInt_AsLong(optiondictvalue)); #endif } else if (!strncmp(tmpoptionlistkey, "option_data", strlen("option_data"))) { option_data = (struct getdns_bindata *)malloc(sizeof(struct getdns_bindata)); option_data->size = PyObject_Length(optiondictvalue); #if PY_MAJOR_VERSION >= 3 option_data->data = (uint8_t *)PyBytes_AS_STRING(optiondictvalue); #else option_data->data = (uint8_t *)PyString_AS_STRING(optiondictvalue); #endif getdns_dict_set_bindata(tmpoptions_list_dict, "option_data", option_data); } else { PyErr_SetString(getdns_error, GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT); return NULL; } getdns_list_set_dict(optionslist, optionlistpos, tmpoptions_list_dict); } } /* for i ... optionlistsize */ getdns_dict_set_list(out_optdict, "options", optionslist); } /* for options */ getdns_dict_set_dict(newdict, "add_opt_parameters", out_optdict); } /* while PyDict_Next(tmp_optdict ... ) */ } else { PyErr_SetString(getdns_error, GETDNS_RETURN_NO_SUCH_EXTENSION_TEXT); return NULL; } } return newdict; } /* * turn a Python address dictionary into a getdns data structure (inc. validation) */ getdns_dict * getdnsify_addressdict(PyObject *pydict) { getdns_dict *addr_dict; getdns_bindata addr_data; getdns_bindata addr_type; PyObject *str; unsigned char buf[sizeof(struct in6_addr)]; int domain; getdns_bindata tls_auth_name; getdns_bindata scope_id; getdns_bindata tsig_name; getdns_bindata tsig_alg; getdns_bindata tsig_secret; uint32_t tls_port, port; getdns_return_t ret; getdns_list *tls_pubkey_pinset; if (!PyDict_Check(pydict)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } /* XXX rewrite this so it's more general */ /* dict members supported: * address_data * address_type * tls_auth_name * scope_id * port * tls_port * tsig_name * tsig_secret * tsig_algorithm * tls_pubkey_pinset */ addr_dict = getdns_dict_create(); if ((str = PyDict_GetItemString(pydict, "address_type")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(str)) { #else if (!PyString_Check(str)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 addr_type.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(str, "ascii", NULL))); #else addr_type.data = (uint8_t *)strdup(PyString_AsString(str)); #endif addr_type.size = strlen((char *)addr_type.data); if (strlen((char *)addr_type.data) != 4) { PyErr_SetString(getdns_error, GETDNS_RETURN_WRONG_TYPE_REQUESTED_TEXT); return NULL; } if (!strncasecmp((char *)addr_type.data, "IPv4", 4)) domain = AF_INET; else if (!strncasecmp((char *)addr_type.data, "IPv6", 4)) domain = AF_INET6; else { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } getdns_dict_set_bindata(addr_dict, "address_type", &addr_type); if ((str = PyDict_GetItemString(pydict, "address_data")) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(str)) { #else if (!PyString_Check(str)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 if (inet_pton(domain, PyBytes_AsString(PyUnicode_AsEncodedString(str, "ascii", NULL)), buf) <= 0) { #else if (inet_pton(domain, PyString_AsString(str), buf) <= 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } addr_data.data = (uint8_t *)buf; addr_data.size = (domain == AF_INET ? 4 : 16); getdns_dict_set_bindata(addr_dict, "address_data", &addr_data); if ((str = PyDict_GetItemString(pydict, "tls_auth_name")) != NULL) { #if PY_MAJOR_VERSION >= 3 tls_auth_name.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(str, "ascii", NULL))); #else tls_auth_name.data = (uint8_t *)strdup(PyString_AsString(str)); #endif tls_auth_name.size = (size_t)strlen((char *)tls_auth_name.data); getdns_dict_set_bindata(addr_dict, "tls_auth_name", &tls_auth_name); } if ((str = PyDict_GetItemString(pydict, "scope_id")) != NULL) { #if PY_MAJOR_VERSION >= 3 scope_id.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(str, "ascii", NULL))); #else scope_id.data = (uint8_t *)strdup(PyString_AsString(str)); #endif scope_id.size = (size_t)strlen((char *)scope_id.data); getdns_dict_set_bindata(addr_dict, "scope_id", &scope_id); } if ((str = PyDict_GetItemString(pydict, "tsig_name")) != NULL) { #if PY_MAJOR_VERSION >= 3 tsig_name.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(str, "ascii", NULL))); #else tsig_name.data = (uint8_t *)strdup(PyBytes_AsString(str)); #endif tsig_name.size = (size_t)strlen((char *)tsig_name.data); if ((ret = getdns_dict_set_bindata(addr_dict, "tsig_name", &tsig_name)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, "bad tsig name"); return NULL; } } if ((str = PyDict_GetItemString(pydict, "tsig_algorithm")) != NULL) { #if PY_MAJOR_VERSION >= 3 tsig_alg.data = (uint8_t *)strdup(PyBytes_AsString(PyUnicode_AsEncodedString(str, "ascii", NULL))); #else tsig_alg.data = (uint8_t *)strdup(PyBytes_AsString(str)); #endif tsig_alg.size = (size_t)strlen((char *)tsig_alg.data); if ((ret = getdns_dict_set_bindata(addr_dict, "tsig_algorithm", &tsig_alg)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, "bad tsig algorithm"); return NULL; } } if ((str = PyDict_GetItemString(pydict, "tsig_secret")) != NULL) { tsig_secret.size = PyByteArray_Size(str); #if PY_MAJOR_VERSION >= 3 tsig_secret.data = (uint8_t *)strdup(PyBytes_AS_STRING(str)); #else tsig_secret.data = (uint8_t *)strdup(PyBytes_AsString(str)); #endif if ((ret = getdns_dict_set_bindata(addr_dict, "tsig_secret", &tsig_secret)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, "bad tsig secret"); return NULL; } } if ((str = PyDict_GetItemString(pydict, "tls_pubkey_pinset")) != NULL) { Py_ssize_t pinset_len; int i; PyObject *py_item; char *str_item; getdns_dict *pubkey_pin = 0; if (!PyList_Check(str)) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } pinset_len = PyList_Size(str); if (pinset_len == 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } tls_pubkey_pinset = getdns_list_create(); for ( i = 0 ; i < (int)pinset_len ; i++ ) { py_item = PyList_GetItem(str, (Py_ssize_t)i); #if PY_MAJOR_VERSION >= 3 str_item = PyBytes_AsString(PyUnicode_AsEncodedString(py_item, "ascii", NULL)); #else str_item = PyString_AsString(py_item); #endif pubkey_pin = getdns_pubkey_pin_create_from_string(0, str_item); if (pubkey_pin == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } if ((ret = getdns_list_set_dict(tls_pubkey_pinset, i, pubkey_pin)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } } if (pubkey_pin) getdns_dict_destroy(pubkey_pin); getdns_dict_set_list(addr_dict, "tls_pubkey_pinset", tls_pubkey_pinset); } if ((str = PyDict_GetItemString(pydict, "port")) != NULL) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(str)) { #else if (!PyInt_Check(str)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 port = (uint32_t)PyLong_AsLong(str); #else port = (uint32_t)PyInt_AsLong(str); #endif getdns_dict_set_int(addr_dict, "port", port); } if ((str = PyDict_GetItemString(pydict, "tls_port")) != NULL) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(str)) { #else if (!PyInt_Check(str)) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_INVALID_PARAMETER_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 tls_port = (uint32_t)PyLong_AsLong(str); #else tls_port = (uint32_t)PyInt_AsLong(str); #endif getdns_dict_set_int(addr_dict, "tls_port", tls_port); } return addr_dict; } PyObject * pythonify_address_list(getdns_list *list) { size_t length; getdns_return_t ret; int i; PyObject *py_list; getdns_data_type type; getdns_dict *a_item; PyObject *py_item; getdns_bindata *a_address_data; getdns_bindata *a_address_type; int domain; char paddr_buf[256]; if ((ret = getdns_list_get_length(list, &length)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } py_list = PyList_New(0); for ( i = 0 ; i < (int)length ; i++ ) { if ((ret = getdns_list_get_data_type(list, i, &type)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (type != t_dict) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((ret = getdns_list_get_dict(list, (size_t)i, &a_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((ret = getdns_dict_get_bindata(a_item, "address_type", &a_address_type)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((ret = getdns_dict_get_bindata(a_item, "address_data", &a_address_data)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (!strncasecmp((char *)a_address_type->data, "IPv4", 4)) domain = AF_INET; else if (!strncasecmp((char *)a_address_type->data, "IPv6", 4)) domain = AF_INET6; else { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } py_item = PyDict_New(); PyDict_SetItemString(py_item, "address_data", #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString(inet_ntop(domain, (void *)a_address_data->data, (char *)paddr_buf, 256))); #else PyString_FromString(inet_ntop(domain, (void *)a_address_data->data, (char *)paddr_buf, 256))); #endif PyDict_SetItemString(py_item, "address_type", #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString((domain == AF_INET ? "IPv4" : "IPv6"))); #else PyString_FromString((domain == AF_INET ? "IPv4" : "IPv6"))); #endif PyList_Append(py_list, py_item); } return py_list; } PyObject * glist_to_plist(struct getdns_list *list) { PyObject *py_list; size_t count; getdns_return_t ret; int i; getdns_data_type type; struct getdns_dict *dict_item; struct getdns_list *list_item; PyObject *py_dict, *py_locallist, *py_bindata, *py_int; uint32_t localint; getdns_bindata *data; if (!list) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((ret = getdns_list_get_length(list, &count)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } py_list = PyList_New(0); for ( i = 0 ; i < count ; i++ ) { (void)getdns_list_get_data_type(list, i, &type); switch (type) { case t_dict: if ((ret = getdns_list_get_dict(list, i, &dict_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_dict = gdict_to_pdict(dict_item)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if (PyList_Append(py_list, py_dict) == -1) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } break; case t_list: if ((ret = getdns_list_get_list(list, i, &list_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_locallist = glist_to_plist(list_item)) == NULL) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (PyList_Append(py_list, py_locallist) == -1) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } break; case t_int: if ((ret = getdns_list_get_int(list, i, &localint)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 py_int = PyLong_FromLong((long)localint); #else py_int = PyInt_FromLong((long)localint); #endif if (PyList_Append(py_list, py_int) == -1) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } break; case t_bindata: if ((ret = getdns_list_get_bindata(list, i, &data)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_bindata = convertBinData(data, "")) == 0) { return NULL; } if (PyList_Append(py_list, py_bindata) == -1) { return NULL; } break; default: PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } } return py_list; } PyObject * gdict_to_pdict(struct getdns_dict *dict) { PyObject *py_dict; getdns_list *keys; size_t n_keys; getdns_return_t ret; int i; getdns_bindata *key_name; getdns_data_type type; getdns_list *list_item; getdns_dict *dict_item; uint32_t int_item; getdns_bindata *bindata_item; PyObject *py_localdict; PyObject *py_locallist; PyObject *py_localint; PyObject *py_localbindata; if ((ret = getdns_dict_get_names(dict, &keys)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } py_dict = PyDict_New(); (void)getdns_list_get_length(keys, &n_keys); for (i = 0 ; i < (int)n_keys ; i++ ) { if ((ret = getdns_list_get_bindata(keys, (size_t)i, &key_name)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if (strnlen((char *)key_name->data, 256) == 256) { /* too long, something's wrong */ PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((ret = getdns_dict_get_data_type(dict, (char *)key_name->data, &type)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } switch (type) { case t_dict: if ((ret = getdns_dict_get_dict(dict, (char *)key_name->data, &dict_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_localdict = gdict_to_pdict(dict_item)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if (PyDict_SetItemString(py_dict, (char *)key_name->data, py_localdict) != 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } break; case t_list: if ((ret = getdns_dict_get_list(dict, (char *)key_name->data, &list_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((py_locallist = glist_to_plist(list_item)) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if (PyDict_SetItemString(py_dict, (char *)key_name->data, py_locallist) != 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } break; case t_int: if ((ret = getdns_dict_get_int(dict, (char *)key_name->data, &int_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } #if PY_MAJOR_VERSION >= 3 py_localint = PyLong_FromLong((long)int_item); #else py_localint = PyInt_FromLong((long)int_item); #endif if (PyDict_SetItemString(py_dict, (char *)key_name->data, py_localint) == -1) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } break; case t_bindata: if ((ret = getdns_dict_get_bindata(dict, (char *)key_name->data, &bindata_item)) != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, getdns_get_errorstr_by_id(ret)); return NULL; } if ((bindata_item == 0) || (bindata_item->data == 0) || bindata_item->size == 0) { break; } if ((py_localbindata = convertBinData(bindata_item, (char *)key_name->data)) == 0) { return NULL; } if (PyDict_SetItemString(py_dict, (char *)key_name->data, py_localbindata) == -1) { return NULL; } break; default: PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } } return py_dict; } /* * Error checking helper */ void error_exit(char* msg, getdns_return_t ret) { char error_str[512]; if (ret != GETDNS_RETURN_GOOD) { sprintf(error_str, "%s: %d", msg, ret); printf("ERROR: %s: %d", msg, ret); PyErr_SetString(getdns_error, error_str); } } // Code to display the entire response. // answer_type // canonical_name // just_address_answers // replies_full // replies_tree // Taken from getdns source to do label checking static int priv_getdns_bindata_is_dname(struct getdns_bindata *bindata) { size_t i = 0, n_labels = 0; while (i < bindata->size) { i += ((size_t)bindata->data[i]) + 1; n_labels++; } return i == bindata->size && n_labels > 1 && bindata->data[bindata->size - 1] == 0; } // Convert bindata into a good representational string or // into a buffer. Handles dname, printable, ".", // and an ip address if it is under a known key PyObject * convertBinData(getdns_bindata* data, const char* key) { size_t i; // the root if (data->size == 1 && data->data[0] == 0) { PyObject *a_string; #if PY_MAJOR_VERSION >= 3 if ((a_string = PyUnicode_FromString(".")) == NULL) { #else if ((a_string = PyString_FromString(".")) == NULL) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } return(a_string); } int printable = 1; for (i = 0; i < data->size; ++i) { if (!isprint(data->data[i])) { if (data->data[i] == 0 && i == data->size - 1) { break; } printable = 0; break; } } // basic string? if (printable == 1) { PyObject *a_string; #if PY_MAJOR_VERSION >= 3 if ((a_string = PyUnicode_FromStringAndSize((char *)data->data, (Py_ssize_t)(data->size))) == NULL) { #else if ((a_string = PyString_FromStringAndSize((char *)data->data, (Py_ssize_t)(data->size))) == NULL) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } return(a_string); } // dname if (priv_getdns_bindata_is_dname(data)) { char* dname = NULL; PyObject *dname_string; if (getdns_convert_dns_name_to_fqdn(data, &dname) == GETDNS_RETURN_GOOD) { #if PY_MAJOR_VERSION >= 3 if ((dname_string = PyUnicode_FromString(dname)) != NULL) { #else if ((dname_string = PyString_FromString(dname)) != NULL) { #endif return(dname_string); } else { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } } else { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } } else if (key != NULL && (strcmp(key, "address_data") == 0)) { /* XXX */ #if 0 (strcmp(key, "ipv4_address") == 0 || strcmp(key, "ipv6_address") == 0)) { #endif char* ipStr = getdns_display_ip_address(data); if (ipStr) { PyObject *addr_string; #if PY_MAJOR_VERSION >= 3 if ((addr_string = PyUnicode_FromString(ipStr)) == NULL) { #else if ((addr_string = PyString_FromString(ipStr)) == NULL) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } return(addr_string); } } else { /* none of the above, treat it like a blob */ uint8_t *blob = (uint8_t *)malloc(data->size); memcpy(blob, data->data, data->size); #if PY_MAJOR_VERSION >= 3 return (PyMemoryView_FromMemory((char *)blob, (Py_ssize_t)data->size, PyBUF_READ)); #else return (PyBuffer_FromMemory(blob, (Py_ssize_t)data->size)); #endif } return NULL; /* should never get here .. */ } PyObject *getdns_dict_to_ip_string(getdns_dict* dict); PyObject *convertToList(struct getdns_list* list); PyObject* convertToDict(struct getdns_dict* dict) { PyObject *resultsdict1; if (!dict) { return 0; } if ((resultsdict1 = PyDict_New()) == NULL) { error_exit("Unable to allocate response dict", 0); return NULL; } // try it as an IP PyObject *ipdict = getdns_dict_to_ip_string(dict); if (ipdict) { return ipdict; } getdns_list* names; getdns_dict_get_names(dict, &names); size_t len = 0, i = 0; getdns_list_get_length(names, &len); for (i = 0; i < len; ++i) { getdns_bindata* nameBin; getdns_list_get_bindata(names, i, &nameBin); getdns_data_type type; getdns_dict_get_data_type(dict, (char*)nameBin->data, &type); switch (type) { case t_bindata: { getdns_bindata* data = NULL; getdns_dict_get_bindata(dict, (char*)nameBin->data, &data); PyObject* res = convertBinData(data, (char*)nameBin->data); #if PY_MAJOR_VERSION >= 3 PyDict_SetItem(resultsdict1, PyUnicode_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size), res); #else PyDict_SetItem(resultsdict1, PyString_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size), res); #endif break; } case t_int: { uint32_t res = 0; getdns_dict_get_int(dict, (char*)nameBin->data, &res); PyObject* rl1 = Py_BuildValue("i", res); PyObject *res1 = Py_BuildValue("O", rl1); #if PY_MAJOR_VERSION >= 3 PyDict_SetItem(resultsdict1, PyUnicode_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size), res1); #else PyDict_SetItem(resultsdict1, PyString_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size), res1); #endif break; } case t_dict: { getdns_dict* subdict = NULL; getdns_dict_get_dict(dict, (char*)nameBin->data, &subdict); PyObject *rl1 = convertToDict(subdict); PyObject *res1 = Py_BuildValue("O", rl1); #if PY_MAJOR_VERSION >= 3 PyDict_SetItem(resultsdict1, PyUnicode_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size), res1); #else PyDict_SetItem(resultsdict1, PyString_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size), res1); #endif break; } case t_list: { getdns_list* list = NULL; getdns_dict_get_list(dict, (char*)nameBin->data, &list); PyObject *rl1 = convertToList(list); PyObject *res1 = Py_BuildValue("O", rl1); #if PY_MAJOR_VERSION >= 3 PyObject *key = PyUnicode_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size); #else PyObject *key = PyString_FromStringAndSize((char *)nameBin->data, (Py_ssize_t)nameBin->size); #endif PyDict_SetItem(resultsdict1, key, res1); break; } default: break; } } getdns_list_destroy(names); return resultsdict1; } PyObject* convertToList(struct getdns_list* list) { if (!list) { return 0; } PyObject* resultslist1; if ((resultslist1 = PyList_New(0)) == NULL) { error_exit("Unable to allocate response list", 0); return NULL; } size_t len, i; getdns_list_get_length(list, &len); for (i = 0; i < len; ++i) { getdns_data_type type; getdns_list_get_data_type(list, i, &type); switch (type) { case t_bindata: { getdns_bindata* data = NULL; getdns_list_get_bindata(list, i, &data); PyObject* res = convertBinData(data, NULL); if (res) { PyList_Append(resultslist1, res); } else { PyObject* res1 = Py_BuildValue("s", "empty"); PyList_Append(resultslist1, res1); } break; } case t_int: { uint32_t res = 0; getdns_list_get_int(list, i, &res); PyObject* res1 = Py_BuildValue("i", res); PyList_Append(resultslist1, res1); break; } case t_dict: { getdns_dict* dict = NULL; getdns_list_get_dict(list, i, &dict); PyObject *rl1 = convertToDict(dict); PyList_Append(resultslist1, rl1); break; } case t_list: { getdns_list* sublist = NULL; getdns_list_get_list(list, i, &sublist); PyObject* rl1 = convertToList(sublist); PyObject *res1 = Py_BuildValue("O", rl1); PyList_Append(resultslist1, res1); break; } default: break; } } return resultslist1; } // potential helper to get the ip string of a dict PyObject * getdns_dict_to_ip_string(getdns_dict* dict) { getdns_bindata *addr; getdns_bindata *type; getdns_return_t r; PyObject *addr_dict; char *addr_string; PyObject *pyaddr_string; if (!dict) { return NULL; } r = getdns_dict_get_bindata(dict, "address_type", &type); if (r != GETDNS_RETURN_GOOD) { return NULL; } if (type->size == 5 && (strcmp("IPv4", (char*) type->data) == 0 || strcmp("IPv6", (char*) type->data) == 0)) { r = getdns_dict_get_bindata(dict, "address_data", &addr); if (r != GETDNS_RETURN_GOOD) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if ((addr_dict = PyDict_New()) == NULL) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } #if PY_MAJOR_VERSION >= 3 if (PyDict_SetItemString(addr_dict, "address_type", PyUnicode_FromStringAndSize((char *)type->data, (Py_ssize_t)type->size)) != 0) { #else if (PyDict_SetItemString(addr_dict, "address_type", PyString_FromStringAndSize((char *)type->data, (Py_ssize_t)type->size)) != 0) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } addr_string = getdns_display_ip_address(addr); #if PY_MAJOR_VERSION >= 3 if ((pyaddr_string = PyUnicode_FromString(addr_string)) == NULL) { #else if ((pyaddr_string = PyString_FromString(addr_string)) == NULL) { #endif PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } if (PyDict_SetItemString(addr_dict, "address_data", pyaddr_string) != 0) { PyErr_SetString(getdns_error, GETDNS_RETURN_GENERIC_ERROR_TEXT); return NULL; } } return NULL; } getdns-python-bindings-1.0.0b1/result.c000066400000000000000000000134421267725536200200360ustar00rootroot00000000000000/* * Copyright (c) 2015, Versign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Include. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "pygetdns.h" #if !defined(Py_TYPE) #define Py_TYPE(ob) (((PyObject *)(ob))->ob_type) #endif int result_init(getdns_ResultObject *self, PyObject *args, PyObject *keywds) { PyObject *result_capsule; struct getdns_dict *result_dict; int status; int answer_type; char *canonical_name; if (!PyArg_ParseTuple(args, "|O", &result_capsule)) { PyErr_SetString(PyExc_AttributeError, GETDNS_RETURN_INVALID_PARAMETER_TEXT); Py_DECREF(self); return -1; } if ((result_dict = PyCapsule_GetPointer(result_capsule, "result")) == NULL) { PyErr_SetString(PyExc_AttributeError, "Unable to initialize result object"); Py_DECREF(self); return -1; } if ((self->replies_full = gdict_to_pdict(result_dict)) == NULL) { Py_DECREF(self); return -1; } if ((self->replies_tree = get_replies_tree(result_dict)) == NULL) { Py_DECREF(self); return -1; } if ((status = get_status(result_dict)) == 0) { Py_DECREF(self); return -1; } #if PY_MAJOR_VERSION >= 3 self->status = PyLong_FromLong((long)status); #else self->status = PyInt_FromLong((long)status); #endif if ((answer_type = get_answer_type(result_dict)) == 0) { Py_DECREF(self); return -1; } #if PY_MAJOR_VERSION >= 3 self->answer_type = PyLong_FromLong((long)answer_type); #else self->answer_type = PyInt_FromLong((long)answer_type); #endif if ((canonical_name = get_canonical_name(result_dict)) == 0) self->canonical_name = Py_None; else #if PY_MAJOR_VERSION >= 3 self->canonical_name = PyUnicode_FromString(canonical_name); #else self->canonical_name = PyString_FromString(canonical_name); #endif if ((self->just_address_answers = get_just_address_answers(result_dict)) == NULL) { self->just_address_answers = Py_None; } if ((self->validation_chain = get_validation_chain(result_dict)) == NULL) self->validation_chain = Py_None; #if GETDNS_NUMERIC_VERSION < 0x00090000 if ((self->call_debugging = get_call_debugging(result_dict)) == NULL) self->call_debugging = Py_None; #else if ((self->call_reporting = get_call_reporting(result_dict)) == NULL) self->call_reporting = Py_None; #endif return 0; } PyObject * result_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { getdns_ResultObject *self; self = (getdns_ResultObject *)type->tp_alloc(type, 0); if (self != NULL) { self->just_address_answers = Py_None; self->answer_type = Py_None; self->status = Py_None; self->replies_tree = Py_None; self->canonical_name = Py_None; self->replies_full = Py_None; self->validation_chain = Py_None; #if GETDNS_NUMERIC_VERSION < 0x00090000 self->call_debugging = Py_None; #else self->call_reporting = Py_None; #endif } return (PyObject *)self; } void result_dealloc(getdns_ResultObject *self) { Py_XDECREF(self->just_address_answers); Py_XDECREF(self->answer_type); Py_XDECREF(self->status); Py_XDECREF(self->replies_tree); Py_XDECREF(self->replies_full); Py_XDECREF(self->canonical_name); Py_XDECREF(self->validation_chain); #if GETDNS_NUMERIC_VERSION < 0x00090000 Py_XDECREF(self->call_debugging); #else Py_XDECREF(self->call_reporting); #endif #if PY_MAJOR_VERSION >= 3 Py_TYPE(self)->tp_free((PyObject *)self); #else self->ob_type->tp_free((PyObject *)self); #endif } PyObject * result_getattro(PyObject *self, PyObject *nameobj) { Py_RETURN_NONE; } PyObject * result_str(PyObject *self) { getdns_ResultObject *me = (getdns_ResultObject *)self; PyObject *cname; cname = me->canonical_name; Py_INCREF(cname); return cname; } /* * package up a getdns response dict and use it to * build a new Python result object */ PyObject * result_create(struct getdns_dict *resp) { PyObject *result_capsule; PyObject *args; result_capsule = PyCapsule_New(resp, "result", 0); args = Py_BuildValue("(O)", result_capsule); return PyObject_CallObject((PyObject *)&getdns_ResultType, args); } getdns-python-bindings-1.0.0b1/setup.py000066400000000000000000000074721267725536200200740ustar00rootroot00000000000000# Copyright (c) 2014, NLnet Labs, Verisign, Inc. # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the names of the copyright holders nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from distutils.core import setup, Extension from distutils.fancy_getopt import fancy_getopt import platform, os, sys long_description = ( 'getdns is a set of wrappers around the getdns' 'library (http://www.getdnsapi.net), providing' 'Python language bindings for the API') CFLAGS = [ '-g' ] lib_dir = "" if '--with-getdns' in sys.argv: getdns_root = sys.argv[sys.argv.index('--with-getdns')+1] inc_dir = getdns_root + '/include' lib_dir = getdns_root + '/lib' CFLAGS.append('-I{0}'.format(inc_dir)) sys.argv.remove('--with-getdns') sys.argv.remove(getdns_root) library_dirs = [ '/usr/local/lib' ] if lib_dir: library_dirs.append(lib_dir) platform_version = list(platform.python_version_tuple())[0:2] if not ((platform_version[0] == '3') or (platform_version == ['2', '7'])): print('getdns requires Python version 2.7 or Python version 3. Exiting ... ') os._exit(1) getdns_module = Extension('getdns', include_dirs = [ '/usr/local/include', ], libraries = [ 'getdns' ], library_dirs = library_dirs, sources = [ 'getdns.c', 'pygetdns_util.c', 'context.c', 'context_util.c', 'result.c' ], extra_compile_args = CFLAGS, runtime_library_dirs = library_dirs, ) setup(name='getdns', version='v1.0beta', description='Python bindings for getdns', long_description=long_description, license='BSD', author='Melinda Shore', author_email='melinda.shore@nomountain.net', url='http://getdns.readthedocs.org', dependency_links=['git+https://github.com/getdnsapi/getdns/tree/release/v0.9.0'], ext_modules = [ getdns_module ], classifiers = [ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Intended Audience :: System Administrators', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.4', 'Topic :: Internet :: Name Service (DNS)', 'Topic :: Security', 'Topic :: Software Development :: Libraries :: Python Modules' ], keywords='DNS DNSSEC DANE', )