2 * libunbound.i: pyUnbound module (libunbound wrapper for Python)
4 * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5 * Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
7 * This software is open source.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * * Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
20 * * Neither the name of the organization nor the names of its
21 * contributors may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
37 /* store state of warning output, restored at later pop */
38 #pragma GCC diagnostic push
39 /* ignore warnings for pragma below, where for older GCC it can produce a
40 warning if the cast-function-type warning is absent. */
41 #pragma GCC diagnostic ignored "-Wpragmas"
42 /* ignore gcc8 METH_NOARGS function cast warnings for swig function pointers */
43 #pragma GCC diagnostic ignored "-Wcast-function-type"
47 /* restore state of warning output, remove the functioncast ignore */
48 #pragma GCC diagnostic pop
49 #include <sys/types.h>
50 #ifdef HAVE_SYS_SOCKET_H
51 #include <sys/socket.h>
53 #ifdef HAVE_NETINET_IN_H
54 #include <netinet/in.h>
56 #ifdef HAVE_ARPA_INET_H
57 #include <arpa/inet.h>
59 #include "libunbound/unbound.h"
67 import __builtin__ as builtins
69 # Ensure compatibility with older python versions
70 if 'bytes' not in vars():
74 if isinstance(s, int):
76 return builtins.ord(s)
80 #if PY_MAJOR_VERSION >= 3
81 %include "file_py3.i" // python 3 FILE *
86 %feature("docstring") strerror "Convert error value to a human readable string."
88 // ================================================================================
89 // ub_resolve - perform resolution and validation
90 // ================================================================================
91 %typemap(in,numinputs=0,noblock=1) (struct ub_result** result)
93 struct ub_result* newubr;
97 /* result generation */
98 %typemap(argout,noblock=1) (struct ub_result** result)
100 if(1) { /* new code block for variable on stack */
102 tuple = PyTuple_New(2);
103 PyTuple_SetItem(tuple, 0, $result);
105 PyTuple_SetItem(tuple, 1, SWIG_NewPointerObj(SWIG_as_voidptr(newubr), SWIGTYPE_p_ub_result, SWIG_POINTER_OWN | 0 ));
107 PyTuple_SetItem(tuple, 1, Py_None);
114 // ================================================================================
115 // ub_ctx - validation context
116 // ================================================================================
117 %nodefaultctor ub_ctx; //no default constructor & destructor
118 %nodefaultdtor ub_ctx;
120 %newobject ub_ctx_create;
121 %delobject ub_ctx_delete;
122 %rename(_ub_ctx_delete) ub_ctx_delete;
124 %newobject ub_resolve;
127 void ub_ctx_free_dbg (struct ub_ctx* c) {
128 printf("******** UB_CTX free 0x%p ************\n", c);
135 /** a host address */
137 /** an authoritative name server */
139 /** a mail destination (Obsolete - use MX) */
141 /** a mail forwarder (Obsolete - use MX) */
143 /** the canonical name for an alias */
145 /** marks the start of a zone of authority */
147 /** a mailbox domain name (EXPERIMENTAL) */
149 /** a mail group member (EXPERIMENTAL) */
151 /** a mail rename domain name (EXPERIMENTAL) */
153 /** a null RR (EXPERIMENTAL) */
155 /** a well known service description */
157 /** a domain name pointer */
159 /** host information */
161 /** mailbox or mail list information */
180 RR_TYPE_NSAP_PTR = 23,
191 /** LOC record RFC1876 */
195 /** draft-ietf-nimrod-dns-01.txt */
197 /** draft-ietf-nimrod-dns-01.txt */
199 /** SRV record RFC2782 */
201 /** http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
213 /** dnsind-kitchen-sink-02.txt */
215 /** Pseudo OPT record... */
219 /** draft-ietf-dnsext-delegation */
221 /** SSH Key Fingerprint */
223 /** draft-richardson-ipseckey-rr-11.txt */
224 RR_TYPE_IPSECKEY = 45,
225 /** draft-ietf-dnsext-dnssec-25 */
232 RR_TYPE_NSEC3PARAMS = 51,
237 RR_TYPE_UNSPEC = 103,
242 /** A request for mailbox-related records (MB, MG or MR) */
244 /** A request for mail agent RRs (Obsolete - see MX) */
246 /** any type (wildcard) */
250 /* RFC 4431, 5074, DNSSEC Lookaside Validation */
261 /** Hesiod (Dyer 87) */
263 /** None class, dynamic update */
270 %feature("docstring") ub_ctx "Unbound resolving and validation context.
272 The validation context is created to hold the resolver status, validation keys and a small cache (containing messages, rrsets, roundtrip times, trusted keys, lameness information).
277 >>> ctx = unbound.ub_ctx()
278 >>> ctx.resolvconf(\"/etc/resolv.conf\")
279 >>> status, result = ctx.resolve(\"www.google.com\", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
280 >>> if status==0 and result.havedata:
281 >>> print \"Result:\",result.data.address_list
282 Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
289 """Creates a resolving and validation context.
291 An exception is invoked if the process of creation an ub_ctx instance fails.
293 self.this = _unbound.ub_ctx_create()
295 raise Exception("Fatal error: unbound context initialization failed")
297 #__swig_destroy__ = _unbound.ub_ctx_free_dbg
298 __swig_destroy__ = _unbound._ub_ctx_delete
302 """Add a trust anchor to the given context.
304 The trust anchor is a string, on one line, that holds a valid DNSKEY or DS RR.
307 string, with zone-format RR on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
308 :returns: (int) 0 if OK, else error.
310 return _unbound.ub_ctx_add_ta(self,ta)
311 #parameters: struct ub_ctx *,char *,
314 def add_ta_file(self,fname):
315 """Add trust anchors to the given context.
317 Pass name of a file with DS and DNSKEY records (like from dig or drill).
320 filename of file with keyfile with trust anchors.
321 :returns: (int) 0 if OK, else error.
323 return _unbound.ub_ctx_add_ta_file(self,fname)
324 #parameters: struct ub_ctx *,char *,
327 def config(self,fname):
328 """setup configuration for the given context.
331 unbound config file (not all settings applicable). This is a power-users interface that lets you specify all sorts of options. For some specific options, such as adding trust anchors, special routines exist.
332 :returns: (int) 0 if OK, else error.
334 return _unbound.ub_ctx_config(self,fname)
335 #parameters: struct ub_ctx *,char *,
338 def debuglevel(self,d):
339 """Set debug verbosity for the context Output is directed to stderr.
342 debug level, 0 is off, 1 is very minimal, 2 is detailed, and 3 is lots.
343 :returns: (int) 0 if OK, else error.
345 return _unbound.ub_ctx_debuglevel(self,d)
346 #parameters: struct ub_ctx *,int,
349 def debugout(self,out):
350 """Set debug output (and error output) to the specified stream.
352 Pass None to disable. Default is stderr.
355 File stream to log to.
356 :returns: (int) 0 if OK, else error.
360 In order to log into file, use
364 ctx = unbound.ub_ctx()
365 fw = fopen("debug.log")
369 Another option is to print the debug information to stderr output
373 ctx = unbound.ub_ctx()
375 ctx.debugout(sys.stderr)
377 return _unbound.ub_ctx_debugout(self,out)
378 #parameters: struct ub_ctx *,void *,
381 def hosts(self,fname="/etc/hosts"):
382 """Read list of hosts from the filename given.
384 Usually "/etc/hosts". These addresses are not flagged as DNSSEC secure when queried for.
387 file name string. If None "/etc/hosts" is used.
388 :returns: (int) 0 if OK, else error.
390 return _unbound.ub_ctx_hosts(self,fname)
391 #parameters: struct ub_ctx *,char *,
394 def print_local_zones(self):
395 """Print the local zones and their content (RR data) to the debug output.
397 :returns: (int) 0 if OK, else error.
399 return _unbound.ub_ctx_print_local_zones(self)
400 #parameters: struct ub_ctx *,
403 def resolvconf(self,fname="/etc/resolv.conf"):
404 """Read list of nameservers to use from the filename given.
406 Usually "/etc/resolv.conf". Uses those nameservers as caching proxies. If they do not support DNSSEC, validation may fail.
408 Only nameservers are picked up, the searchdomain, ndots and other settings from resolv.conf(5) are ignored.
411 file name string. If None "/etc/resolv.conf" is used.
412 :returns: (int) 0 if OK, else error.
414 return _unbound.ub_ctx_resolvconf(self,fname)
415 #parameters: struct ub_ctx *,char *,
418 def set_async(self,dothread):
419 """Set a context behaviour for asynchronous action.
422 if True, enables threading and a call to :meth:`resolve_async` creates a thread to handle work in the background.
423 If False, a process is forked to handle work in the background.
424 Changes to this setting after :meth:`async` calls have been made have no effect (delete and re-create the context to change).
425 :returns: (int) 0 if OK, else error.
427 return _unbound.ub_ctx_async(self,dothread)
428 #parameters: struct ub_ctx *,int,
431 def set_fwd(self,addr):
432 """Set machine to forward DNS queries to, the caching resolver to use.
434 IP4 or IP6 address. Forwards all DNS requests to that machine, which is expected to run a recursive resolver. If the is not DNSSEC-capable, validation may fail. Can be called several times, in that case the addresses are used as backup servers.
436 To read the list of nameservers from /etc/resolv.conf (from DHCP or so), use the call :meth:`resolvconf`.
439 address, IP4 or IP6 in string format. If the addr is None, forwarding is disabled.
440 :returns: (int) 0 if OK, else error.
442 return _unbound.ub_ctx_set_fwd(self,addr)
443 #parameters: struct ub_ctx *,char *,
446 def set_option(self,opt,val):
447 """Set an option for the context.
449 Changes to the options after :meth:`resolve`, :meth:`resolve_async`, :meth:`zone_add`, :meth:`zone_remove`, :meth:`data_add` or :meth:`data_remove` have no effect (you have to delete and re-create the context).
452 option name from the unbound.conf config file format. (not all settings applicable). The name includes the trailing ':' for example set_option("logfile:", "mylog.txt"); This is a power-users interface that lets you specify all sorts of options. For some specific options, such as adding trust anchors, special routines exist.
455 :returns: (int) 0 if OK, else error.
457 return _unbound.ub_ctx_set_option(self,opt,val)
458 #parameters: struct ub_ctx *,char *,char *,
461 def trustedkeys(self,fname):
462 """Add trust anchors to the given context.
464 Pass the name of a bind-style config file with trusted-keys{}.
467 filename of file with bind-style config entries with trust anchors.
468 :returns: (int) 0 if OK, else error.
470 return _unbound.ub_ctx_trustedkeys(self,fname)
471 #parameters: struct ub_ctx *,char *,
475 def zone_print(self):
476 """Print local zones using debugout"""
477 _unbound.ub_ctx_print_local_zones(self)
479 def zone_add(self,zonename,zonetype):
480 """Add new local zone
482 :param zonename: zone domain name (e.g. myzone.)
483 :param zonetype: type of the zone ("static",...)
484 :returns: (int) 0 if OK, else error.
486 return _unbound.ub_ctx_zone_add(self,zonename, zonetype)
487 #parameters: struct ub_ctx *,char*, char*
490 def zone_remove(self,zonename):
493 If exists, removes local zone with all the RRs.
495 :param zonename: zone domain name
496 :returns: (int) 0 if OK, else error.
498 return _unbound.ub_ctx_zone_remove(self,zonename)
499 #parameters: struct ub_ctx *,char*
502 def data_add(self,rrdata):
503 """Add new local RR data
505 :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
506 :returns: (int) 0 if OK, else error.
513 >>> ctx = unbound.ub_ctx()
514 >>> ctx.zone_add("mydomain.net.","static")
516 >>> status = ctx.data_add("test.mydomain.net. IN A 192.168.1.1")
518 >>> status, result = ctx.resolve("test.mydomain.net")
519 >>> if status==0 and result.havedata:
520 >>> print \"Result:\",result.data.address_list
521 Result: ['192.168.1.1']
524 return _unbound.ub_ctx_data_add(self,rrdata)
525 #parameters: struct ub_ctx *,char*
528 def data_remove(self,rrdata):
529 """Remove local RR data
531 If exists, remove resource record from local zone
533 :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
534 :returns: (int) 0 if OK, else error.
536 return _unbound.ub_ctx_data_remove(self,rrdata)
537 #parameters: struct ub_ctx *,char*
541 def cancel(self,async_id):
542 """Cancel an async query in progress.
544 Its callback will not be called.
547 which query to cancel.
548 :returns: (int) 0 if OK, else error.
550 return _unbound.ub_cancel(self,async_id)
551 #parameters: struct ub_ctx *,int,
555 """Get file descriptor.
557 Wait for it to become readable, at this point answers are returned from the asynchronous validating resolver. Then call the ub_process to continue processing. This routine works immediately after context creation, the fd does not change.
559 :returns: (int) -1 on error, or file descriptor to use select(2) with.
561 return _unbound.ub_fd(self)
562 #parameters: struct ub_ctx *,
566 """Poll a context to see if it has any new results Do not poll in a loop, instead extract the fd below to poll for readiness, and then check, or wait using the wait routine.
568 :returns: (int) 0 if nothing to read, or nonzero if a result is available. If nonzero, call ctx_process() to do callbacks.
570 return _unbound.ub_poll(self)
571 #parameters: struct ub_ctx *,
575 """Call this routine to continue processing results from the validating resolver (when the fd becomes readable).
577 Will perform necessary callbacks.
579 :returns: (int) 0 if OK, else error.
581 return _unbound.ub_process(self)
582 #parameters: struct ub_ctx *,
585 def resolve(self,name,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
586 """Perform resolution and validation of the target name.
589 domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
591 type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
593 class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
594 :returns: * (int) 0 if OK, else error.
595 * (:class:`ub_result`) the result data is returned in a newly allocated result structure. May be None on return, return value is set to an error in that case (out of memory).
597 if isinstance(name, bytes): #probably IDN
598 return _unbound.ub_resolve(self,name,rrtype,rrclass)
600 return _unbound.ub_resolve(self,idn2dname(name),rrtype,rrclass)
601 #parameters: struct ub_ctx *,char *,int,int,
602 #retvals: int,struct ub_result **
604 def resolve_async(self,name,mydata,callback,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
605 """Perform resolution and validation of the target name.
607 Asynchronous, after a while, the callback will be called with your data and the result.
608 If an error happens during processing, your callback will be called with error set to a nonzero value (and result==None).
611 domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
613 this data is your own data (you can pass arbitrary python object or None) which are passed on to the callback function.
615 call-back function which is called on completion of the resolution.
617 type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
619 class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
620 :returns: * (int) 0 if OK, else error.
621 * (int) async_id, an identifier number is returned for the query as it is in progress. It can be used to cancel the query.
623 **Call-back function:**
624 The call-back function looks as the follows::
626 def call_back(mydata, status, result):
630 * `mydata` - mydata object
631 * `status` - 0 when a result has been found
632 * `result` - the result structure. The result may be None, in that case err is set.
635 if isinstance(name, bytes): #probably IDN
636 return _unbound._ub_resolve_async(self,name,rrtype,rrclass,mydata,callback)
638 return _unbound._ub_resolve_async(self,idn2dname(name),rrtype,rrclass,mydata,callback)
639 #parameters: struct ub_ctx *,char *,int,int,void *,ub_callback_t,
643 """Wait for a context to finish with results.
645 Calls after the wait for you. After the wait, there are no more outstanding asynchronous queries.
647 :returns: (int) 0 if OK, else error.
649 return _unbound.ub_wait(self)
650 #parameters: struct ub_ctx *,
658 // ================================================================================
659 // ub_result - validation and resolution results
660 // ================================================================================
661 %nodefaultctor ub_result; //no default constructor & destructor
662 %nodefaultdtor ub_result;
664 %delobject ub_resolve_free;
665 %rename(_ub_resolve_free) ub_resolve_free;
668 void ub_resolve_free_dbg (struct ub_result* r) {
669 printf("******** UB_RESOLVE free 0x%p ************\n", r);
674 %feature("docstring") ub_result "The validation and resolution results."
678 enum result_enum_rcode {
695 """Class which makes the resolution results accessible"""
696 def __init__(self, data):
697 """Creates ub_data class
698 :param data: a list of the result data in RAW format
701 raise Exception("ub_data init: No data")
705 """Represents data as string"""
706 return ';'.join([' '.join(map(lambda x:"%02X" % ord(x),a)) for a in self.data])
709 def dname2str(s, ofs=0, maxlen=0):
710 """Parses DNAME and produces a list of labels
712 :param ofs: where the conversion should start to parse data
713 :param maxlen: maximum length (0 means parse to the end)
714 :returns: list of labels (string)
722 slen = min(slen, maxlen)
726 complen = ord(s[idx])
727 # In python 3.x `str()` converts the string to unicode which is the expected text string type
728 res.append(str(s[idx+1:idx+1+complen].decode()))
733 def as_raw_data(self):
734 """Returns a list of RAW strings"""
737 raw = property(as_raw_data, doc="Returns RAW data (a list of binary encoded strings). See :meth:`as_raw_data`")
739 def as_mx_list(self):
740 """Represents data as a list of MX records (query for RR_TYPE_MX)
742 :returns: list of tuples (priority, dname)
744 return [(256*ord(rdf[0])+ord(rdf[1]),'.'.join([a for a in self.dname2str(rdf,2)])) for rdf in self.data]
746 mx_list = property(as_mx_list, doc="Returns a list of tuples containing priority and domain names. See :meth:`as_mx_list`")
748 def as_idn_mx_list(self):
749 """Represents data as a list of MX records (query for RR_TYPE_MX)
751 :returns: list of tuples (priority, unicode dname)
753 return [(256*ord(rdf[0])+ord(rdf[1]),'.'.join([encodings.idna.ToUnicode(a) for a in self.dname2str(rdf,2)])) for rdf in self.data]
755 mx_list_idn = property(as_idn_mx_list, doc="Returns a list of tuples containing priority and IDN domain names. See :meth:`as_idn_mx_list`")
757 def as_address_list(self):
758 """Represents data as a list of IP addresses (query for RR_TYPE_PTR)
760 :returns: list of strings
762 return ['.'.join(map(lambda x:str(ord(x)),a)) for a in self.data]
764 address_list = property(as_address_list, doc="Returns a list of IP addresses. See :meth:`as_address_list`")
766 def as_domain_list(self):
767 """Represents data as a list of domain names (query for RR_TYPE_A)
769 :returns: list of strings
771 return map(lambda x:'.'.join(self.dname2str(x)), self.data)
773 domain_list = property(as_domain_list, doc="Returns a list of domain names. See :meth:`as_domain_list`")
775 def as_idn_domain_list(self):
776 """Represents data as a list of unicode domain names (query for RR_TYPE_A)
778 :returns: list of strings
780 return map(lambda x: '.'.join([encodings.idna.ToUnicode(a) for a in self.dname2str(x)]), self.data)
782 domain_list_idn = property(as_idn_domain_list, doc="Returns a list of IDN domain names. See :meth:`as_idn_domain_list`")
790 PyObject* _ub_result_data(struct ub_result* result) {
794 if ((result == 0) || (!result->havedata) || (result->data == 0))
797 for (cnt=0,i=0;;i++,cnt++)
798 if (result->data[i] == 0)
801 list = PyList_New(cnt);
803 PyList_SetItem(list, i, PyBytes_FromStringAndSize(result->data[i],result->len[i]));
808 PyObject* _packet() {
809 return PyBytes_FromStringAndSize($self->answer_packet, $self->answer_len);
814 raise Exception("This class can't be created directly.")
816 #__swig_destroy__ = _unbound.ub_resolve_free_dbg
817 __swig_destroy__ = _unbound._ub_resolve_free
819 #havedata = property(_unbound.ub_result_havedata_get, _unbound.ub_result_havedata_set, "Havedata property")
821 rcode2str = {RCODE_NOERROR:'no error', RCODE_FORMERR:'form error', RCODE_SERVFAIL:'serv fail', RCODE_NXDOMAIN:'nx domain', RCODE_NOTIMPL:'not implemented', RCODE_REFUSED:'refused', RCODE_YXDOMAIN:'yxdomain', RCODE_YXRRSET:'yxrrset', RCODE_NXRRSET:'nxrrset', RCODE_NOTAUTH:'not auth', RCODE_NOTZONE:'not zone'}
823 def _get_rcode_str(self):
824 """Returns rcode in display representation form
828 return self.rcode2str[self.rcode]
830 rcode_str = property(_get_rcode_str)
832 def _get_raw_data(self):
833 """Result data, a list of network order DNS rdata items.
835 Data are represented as a list of strings. To decode RAW data to the list of IP addresses use :attr:`data` attribute which returns an :class:`ub_data` instance containing conversion function.
837 return self._ub_result_data(self)
839 rawdata = property(_get_raw_data, doc="Returns raw data, a list of rdata items. To decode RAW data use the :attr:`data` attribute which returns an instance of :class:`ub_data` containing the conversion functions.")
842 if not self.havedata: return None
843 return ub_data(self._ub_result_data(self))
845 packet = property(_packet)
846 data = property(_get_data, doc="Returns :class:`ub_data` instance containing various decoding functions or None")
852 %exception ub_resolve
854 //printf("resolve_start(%lX)\n",(long unsigned int)arg1);
855 Py_BEGIN_ALLOW_THREADS
858 //printf("resolve_stop()\n");
861 %include "libunbound/unbound.h"
864 //SWIG will see the ub_ctx as a class
866 /* Dummy member, so the struct is not empty, MSVC complains about
872 //ub_ctx_debugout void* parameter correction
873 int ub_ctx_debugout(struct ub_ctx* ctx, FILE* out);
875 // ================================================================================
876 // ub_resolve_async - perform asynchronous resolution and validation
877 // ================================================================================
879 %typemap(in,numinputs=0,noblock=1) (int* async_id)
885 %apply PyObject* {void* mydata}
887 /* result generation */
888 %typemap(argout,noblock=1) (int* async_id)
890 if(1) { /* new code block for variable on stack */
892 tuple = PyTuple_New(2);
893 PyTuple_SetItem(tuple, 0, $result);
894 PyTuple_SetItem(tuple, 1, SWIG_From_int(asyncid));
899 // Grab a Python function object as a Python object.
900 %typemap(in) (PyObject *pyfunc) {
901 if (!PyCallable_Check($input))
903 PyErr_SetString(PyExc_TypeError, "Need a callable object!");
909 // Python callback workaround
910 int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, void* mydata, PyObject *pyfunc, int* async_id);
918 static void PythonCallBack(void* iddata, int status, struct ub_result* result)
923 id = (struct cb_data*) iddata;
924 arglist = Py_BuildValue("(OiO)",id->data,status, SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ub_result, 0 | 0 )); // Build argument list
925 #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
926 /* for python before 3.9 */
927 fresult = PyEval_CallObject(id->func,arglist); // Call Python
929 /* for python 3.9 and newer */
930 fresult = PyObject_Call(id->func,arglist,NULL);
935 ub_resolve_free(result); //free ub_result
936 //ub_resolve_free_dbg(result); //free ub_result
937 Py_DECREF(arglist); // Trash arglist
941 int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, PyObject* mydata, PyObject *pyfunc, int* async_id) {
944 id = (struct cb_data*) malloc(sizeof(struct cb_data));
946 return -2; /* UB_NOMEM */
950 r = ub_resolve_async(ctx,name,rrtype,rrclass, (void *) id, PythonCallBack, async_id);
959 ub_resolve_async = _unbound._ub_resolve_async
962 """Reverse domain name
964 Usable for reverse lookups when the IP address should be reversed
966 return '.'.join([a for a in domain.split(".")][::-1])
968 def idn2dname(idnname):
969 """Converts domain name in IDN format to canonic domain name
971 :param idnname: (unicode string) IDN name
972 :returns: (string) domain name
974 return '.'.join([encodings.idna.ToASCII(a) if a else '' for a in idnname.split('.')])
977 """Converts canonic domain name in IDN format to unicode string
979 :param name: (string) domain name
980 :returns: (unicode string) domain name
982 return '.'.join([encodings.idna.ToUnicode(a) for a in name.split('.')])