]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libunbound/python/libunbound.i
Vendor import of Unbound 1.9.1.
[FreeBSD/FreeBSD.git] / libunbound / python / libunbound.i
1 /*
2  * libunbound.i: pyUnbound module (libunbound wrapper for Python)
3  * 
4  * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5  *                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)
6  *
7  * This software is open source.
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 
13  *    * Redistributions of source code must retain the above copyright notice,
14  *      this list of conditions and the following disclaimer.
15  * 
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.
19  * 
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.
23  *
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.
35  */
36 %begin %{
37 /* store state of warning output, restored at later pop */
38 #pragma GCC diagnostic push
39 /* ignore gcc8 METH_NOARGS function cast warnings for swig function pointers */
40 #pragma GCC diagnostic ignored "-Wcast-function-type"
41 %}
42 %module unbound
43 %{
44 /* restore state of warning output, remove the functioncast ignore */
45 #pragma GCC diagnostic pop
46    #include <sys/types.h>
47    #ifdef HAVE_SYS_SOCKET_H
48    #include <sys/socket.h>
49    #endif
50    #ifdef HAVE_NETINET_IN_H
51    #include <netinet/in.h>
52    #endif
53    #ifdef HAVE_ARPA_INET_H
54    #include <arpa/inet.h>
55    #endif
56    #include "libunbound/unbound.h"
57 %}
58
59 %pythoncode %{
60    import encodings.idna
61    try:
62        import builtins
63    except ImportError:
64        import __builtin__ as builtins
65
66    # Ensure compatibility with older python versions
67    if 'bytes' not in vars():
68        bytes = str
69
70    def ord(s):
71        if isinstance(s, int):
72            return s
73        return builtins.ord(s)
74 %}
75
76 //%include "doc.i"
77 #if PY_MAJOR_VERSION >= 3
78 %include "file_py3.i" // python 3 FILE *
79 #else
80 %include "file.i"
81 #endif
82
83 %feature("docstring") strerror "Convert error value to a human readable string."
84
85 // ================================================================================
86 // ub_resolve - perform resolution and validation
87 // ================================================================================
88 %typemap(in,numinputs=0,noblock=1) (struct ub_result** result)  
89
90    struct ub_result* newubr;
91    $1 = &newubr;
92
93   
94 /* result generation */
95 %typemap(argout,noblock=1) (struct ub_result** result)
96 {
97   if(1) { /* new code block for variable on stack */
98     PyObject* tuple;
99     tuple = PyTuple_New(2);
100     PyTuple_SetItem(tuple, 0, $result);
101     if (result == 0) {
102        PyTuple_SetItem(tuple, 1, SWIG_NewPointerObj(SWIG_as_voidptr(newubr), SWIGTYPE_p_ub_result, SWIG_POINTER_OWN |  0 ));
103     } else {
104        PyTuple_SetItem(tuple, 1, Py_None);
105     }
106     $result = tuple;
107   }
108 }
109
110                        
111 // ================================================================================
112 // ub_ctx - validation context
113 // ================================================================================
114 %nodefaultctor ub_ctx; //no default constructor & destructor
115 %nodefaultdtor ub_ctx;
116
117 %newobject ub_ctx_create;
118 %delobject ub_ctx_delete;
119 %rename(_ub_ctx_delete) ub_ctx_delete;
120
121 %newobject ub_resolve;
122
123 %inline %{
124   void ub_ctx_free_dbg (struct ub_ctx* c) {
125     printf("******** UB_CTX free 0x%p ************\n", c);
126     ub_ctx_delete(c);
127   }
128
129   //RR types
130   enum enum_rr_type
131   {
132     /**  a host address */
133     RR_TYPE_A = 1, 
134     /**  an authoritative name server */
135     RR_TYPE_NS = 2, 
136     /**  a mail destination (Obsolete - use MX) */
137     RR_TYPE_MD = 3, 
138     /**  a mail forwarder (Obsolete - use MX) */
139     RR_TYPE_MF = 4, 
140     /**  the canonical name for an alias */
141     RR_TYPE_CNAME = 5, 
142     /**  marks the start of a zone of authority */
143     RR_TYPE_SOA = 6, 
144     /**  a mailbox domain name (EXPERIMENTAL) */
145     RR_TYPE_MB = 7, 
146     /**  a mail group member (EXPERIMENTAL) */
147     RR_TYPE_MG = 8, 
148     /**  a mail rename domain name (EXPERIMENTAL) */
149     RR_TYPE_MR = 9, 
150     /**  a null RR (EXPERIMENTAL) */
151     RR_TYPE_NULL = 10,
152     /**  a well known service description */
153     RR_TYPE_WKS = 11,
154     /**  a domain name pointer */
155     RR_TYPE_PTR = 12,
156     /**  host information */
157     RR_TYPE_HINFO = 13,
158     /**  mailbox or mail list information */
159     RR_TYPE_MINFO = 14,
160     /**  mail exchange */
161     RR_TYPE_MX = 15,
162     /**  text strings */
163     RR_TYPE_TXT = 16,
164     /**  RFC1183 */
165     RR_TYPE_RP = 17,
166     /**  RFC1183 */
167     RR_TYPE_AFSDB = 18,
168     /**  RFC1183 */
169     RR_TYPE_X25 = 19,
170     /**  RFC1183 */
171     RR_TYPE_ISDN = 20,
172     /**  RFC1183 */
173     RR_TYPE_RT = 21,
174     /**  RFC1706 */
175     RR_TYPE_NSAP = 22,
176     /**  RFC1348 */
177     RR_TYPE_NSAP_PTR = 23,
178     /**  2535typecode */
179     RR_TYPE_SIG = 24,
180     /**  2535typecode */
181     RR_TYPE_KEY = 25,
182     /**  RFC2163 */
183     RR_TYPE_PX = 26,
184     /**  RFC1712 */
185     RR_TYPE_GPOS = 27,
186     /**  ipv6 address */
187     RR_TYPE_AAAA = 28,
188     /**  LOC record  RFC1876 */
189     RR_TYPE_LOC = 29,
190     /**  2535typecode */
191     RR_TYPE_NXT = 30,
192     /**  draft-ietf-nimrod-dns-01.txt */
193     RR_TYPE_EID = 31,
194     /**  draft-ietf-nimrod-dns-01.txt */
195     RR_TYPE_NIMLOC = 32,
196     /**  SRV record RFC2782 */
197     RR_TYPE_SRV = 33,
198     /**  http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
199     RR_TYPE_ATMA = 34,
200     /**  RFC2915 */
201     RR_TYPE_NAPTR = 35,
202     /**  RFC2230 */
203     RR_TYPE_KX = 36,
204     /**  RFC2538 */
205     RR_TYPE_CERT = 37,
206     /**  RFC2874 */
207     RR_TYPE_A6 = 38,
208     /**  RFC2672 */
209     RR_TYPE_DNAME = 39,
210     /**  dnsind-kitchen-sink-02.txt */
211     RR_TYPE_SINK = 40,
212     /**  Pseudo OPT record... */
213     RR_TYPE_OPT = 41,
214     /**  RFC3123 */
215     RR_TYPE_APL = 42,
216     /**  draft-ietf-dnsext-delegation */
217     RR_TYPE_DS = 43,
218     /**  SSH Key Fingerprint */
219     RR_TYPE_SSHFP = 44,
220     /**  draft-richardson-ipseckey-rr-11.txt */
221     RR_TYPE_IPSECKEY = 45,
222     /**  draft-ietf-dnsext-dnssec-25 */
223     RR_TYPE_RRSIG = 46,
224     RR_TYPE_NSEC = 47,      
225     RR_TYPE_DNSKEY = 48,
226     RR_TYPE_DHCID = 49,
227
228     RR_TYPE_NSEC3 = 50,
229     RR_TYPE_NSEC3PARAMS = 51,
230
231     RR_TYPE_UINFO = 100,
232     RR_TYPE_UID = 101,
233     RR_TYPE_GID = 102,
234     RR_TYPE_UNSPEC = 103,
235
236     RR_TYPE_TSIG = 250,
237     RR_TYPE_IXFR = 251,
238     RR_TYPE_AXFR = 252,
239     /**  A request for mailbox-related records (MB, MG or MR) */
240     RR_TYPE_MAILB = 253,
241     /**  A request for mail agent RRs (Obsolete - see MX) */
242     RR_TYPE_MAILA = 254,
243     /**  any type (wildcard) */
244     RR_TYPE_ANY = 255,
245
246     /* RFC 4431, 5074, DNSSEC Lookaside Validation */
247     RR_TYPE_DLV = 32769,
248   };
249
250   // RR classes
251   enum enum_rr_class
252   { 
253     /** the Internet */
254     RR_CLASS_IN = 1,
255     /** Chaos class */
256     RR_CLASS_CH = 3,
257     /** Hesiod (Dyer 87) */
258     RR_CLASS_HS = 4,
259     /** None class, dynamic update */
260     RR_CLASS_NONE = 254,
261     /** Any class */
262     RR_CLASS_ANY = 255,
263   };
264 %} 
265
266 %feature("docstring") ub_ctx "Unbound resolving and validation context. 
267
268 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).
269
270 **Usage**
271
272 >>> import unbound
273 >>> ctx = unbound.ub_ctx()
274 >>> ctx.resolvconf(\"/etc/resolv.conf\")
275 >>> status, result = ctx.resolve(\"www.google.com\", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
276 >>> if status==0 and result.havedata:
277 >>>    print \"Result:\",result.data.address_list
278 Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
279 "
280
281 %extend ub_ctx
282 {
283  %pythoncode %{
284         def __init__(self):
285             """Creates a resolving and validation context.
286                
287                An exception is invoked if the process of creation an ub_ctx instance fails.
288             """
289             self.this = _unbound.ub_ctx_create()
290             if not self.this:
291                 raise Exception("Fatal error: unbound context initialization failed")
292
293         #__swig_destroy__ = _unbound.ub_ctx_free_dbg
294         __swig_destroy__ = _unbound._ub_ctx_delete
295
296         #UB_CTX_METHODS_#   
297         def add_ta(self,ta):
298             """Add a trust anchor to the given context.
299                
300                The trust anchor is a string, on one line, that holds a valid DNSKEY or DS RR.
301                
302                :param ta:
303                    string, with zone-format RR on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
304                :returns: (int) 0 if OK, else error.
305             """
306             return _unbound.ub_ctx_add_ta(self,ta)
307             #parameters: struct ub_ctx *,char *,
308             #retvals: int
309
310         def add_ta_file(self,fname):
311             """Add trust anchors to the given context.
312                
313                Pass name of a file with DS and DNSKEY records (like from dig or drill).
314                
315                :param fname:
316                    filename of file with keyfile with trust anchors.
317                :returns: (int) 0 if OK, else error.
318             """
319             return _unbound.ub_ctx_add_ta_file(self,fname)
320             #parameters: struct ub_ctx *,char *,
321             #retvals: int
322
323         def config(self,fname):
324             """setup configuration for the given context.
325                
326                :param fname:
327                    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.
328                :returns: (int) 0 if OK, else error.
329             """
330             return _unbound.ub_ctx_config(self,fname)
331             #parameters: struct ub_ctx *,char *,
332             #retvals: int
333
334         def debuglevel(self,d):
335             """Set debug verbosity for the context Output is directed to stderr.
336                
337                :param d:
338                    debug level, 0 is off, 1 is very minimal, 2 is detailed, and 3 is lots.
339                :returns: (int) 0 if OK, else error.
340             """
341             return _unbound.ub_ctx_debuglevel(self,d)
342             #parameters: struct ub_ctx *,int,
343             #retvals: int
344
345         def debugout(self,out):
346             """Set debug output (and error output) to the specified stream.
347                
348                Pass None to disable. Default is stderr.
349                
350                :param out:
351                    File stream to log to.
352                :returns: (int) 0 if OK, else error.
353
354                **Usage:**
355
356                   In order to log into file, use
357
358                   ::
359
360                     ctx = unbound.ub_ctx()
361                     fw = fopen("debug.log")
362                     ctx.debuglevel(3)
363                     ctx.debugout(fw)
364
365                   Another option is to print the debug informations to stderr output
366
367                   ::
368
369                     ctx = unbound.ub_ctx()
370                     ctx.debuglevel(10)
371                     ctx.debugout(sys.stderr) 
372             """
373             return _unbound.ub_ctx_debugout(self,out)
374             #parameters: struct ub_ctx *,void *,
375             #retvals: int
376
377         def hosts(self,fname="/etc/hosts"):
378             """Read list of hosts from the filename given.
379                
380                Usually "/etc/hosts". These addresses are not flagged as DNSSEC secure when queried for.
381                
382                :param fname:
383                    file name string. If None "/etc/hosts" is used.
384                :returns: (int) 0 if OK, else error.
385             """
386             return _unbound.ub_ctx_hosts(self,fname)
387             #parameters: struct ub_ctx *,char *,
388             #retvals: int
389
390         def print_local_zones(self):
391             """Print the local zones and their content (RR data) to the debug output.
392                
393                :returns: (int) 0 if OK, else error.
394             """
395             return _unbound.ub_ctx_print_local_zones(self)
396             #parameters: struct ub_ctx *,
397             #retvals: int
398
399         def resolvconf(self,fname="/etc/resolv.conf"):
400             """Read list of nameservers to use from the filename given.
401                
402                Usually "/etc/resolv.conf". Uses those nameservers as caching proxies. If they do not support DNSSEC, validation may fail.
403                
404                Only nameservers are picked up, the searchdomain, ndots and other settings from resolv.conf(5) are ignored.
405                
406                :param fname:
407                    file name string. If None "/etc/resolv.conf" is used.
408                :returns: (int) 0 if OK, else error.
409             """
410             return _unbound.ub_ctx_resolvconf(self,fname)
411             #parameters: struct ub_ctx *,char *,
412             #retvals: int
413
414         def set_async(self,dothread):
415             """Set a context behaviour for asynchronous action.
416                
417                :param dothread:
418                    if True, enables threading and a call to :meth:`resolve_async` creates a thread to handle work in the background. 
419                    If False, a process is forked to handle work in the background. 
420                    Changes to this setting after :meth:`async` calls have been made have no effect (delete and re-create the context to change).
421                :returns: (int) 0 if OK, else error.
422             """
423             return _unbound.ub_ctx_async(self,dothread)
424             #parameters: struct ub_ctx *,int,
425             #retvals: int
426
427         def set_fwd(self,addr):
428             """Set machine to forward DNS queries to, the caching resolver to use.
429                
430                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.
431                
432                To read the list of nameservers from /etc/resolv.conf (from DHCP or so), use the call :meth:`resolvconf`.
433                
434                :param addr:
435                    address, IP4 or IP6 in string format. If the addr is None, forwarding is disabled.
436                :returns: (int) 0 if OK, else error.
437             """
438             return _unbound.ub_ctx_set_fwd(self,addr)
439             #parameters: struct ub_ctx *,char *,
440             #retvals: int
441
442         def set_option(self,opt,val):
443             """Set an option for the context.
444
445                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).
446                
447                :param opt:
448                    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.
449                :param val:
450                    value of the option.
451                :returns: (int) 0 if OK, else error.
452             """
453             return _unbound.ub_ctx_set_option(self,opt,val)
454             #parameters: struct ub_ctx *,char *,char *,
455             #retvals: int
456
457         def trustedkeys(self,fname):
458             """Add trust anchors to the given context.
459                
460                Pass the name of a bind-style config file with trusted-keys{}.
461                
462                :param fname:
463                    filename of file with bind-style config entries with trust anchors.
464                :returns: (int) 0 if OK, else error.
465             """
466             return _unbound.ub_ctx_trustedkeys(self,fname)
467             #parameters: struct ub_ctx *,char *,
468             #retvals: int
469         #_UB_CTX_METHODS#   
470         
471         def zone_print(self):
472             """Print local zones using debugout"""            
473             _unbound.ub_ctx_print_local_zones(self)
474
475         def zone_add(self,zonename,zonetype):
476             """Add new local zone
477
478                :param zonename: zone domain name (e.g. myzone.)
479                :param zonetype: type of the zone ("static",...) 
480                :returns: (int) 0 if OK, else error. 
481             """ 
482             return _unbound.ub_ctx_zone_add(self,zonename, zonetype)
483             #parameters: struct ub_ctx *,char*, char*
484             #retvals: int
485
486         def zone_remove(self,zonename):
487             """Remove local zone
488             
489                If exists, removes local zone with all the RRs.
490
491                :param zonename: zone domain name
492                :returns: (int) 0 if OK, else error. 
493             """ 
494             return _unbound.ub_ctx_zone_remove(self,zonename)
495             #parameters: struct ub_ctx *,char*
496             #retvals: int
497
498         def data_add(self,rrdata):
499             """Add new local RR data
500
501                :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
502                :returns: (int) 0 if OK, else error. 
503
504                **Usage**
505                   The local data ...
506
507                   ::
508
509                     >>> ctx = unbound.ub_ctx()
510                     >>> ctx.zone_add("mydomain.net.","static")
511                     0
512                     >>> status = ctx.data_add("test.mydomain.net. IN A 192.168.1.1")
513                     0
514                     >>> status, result = ctx.resolve("test.mydomain.net")
515                     >>> if status==0 and result.havedata:
516                     >>>    print \"Result:\",result.data.address_list
517                     Result: ['192.168.1.1']
518
519             """ 
520             return _unbound.ub_ctx_data_add(self,rrdata)
521             #parameters: struct ub_ctx *,char*
522             #retvals: int
523
524         def data_remove(self,rrdata):
525             """Remove local RR data
526
527                If exists, remove resource record from local zone
528
529                :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
530                :returns: (int) 0 if OK, else error. 
531             """ 
532             return _unbound.ub_ctx_data_remove(self,rrdata)
533             #parameters: struct ub_ctx *,char*
534             #retvals: int
535
536         #UB_METHODS_#
537         def cancel(self,async_id):
538             """Cancel an async query in progress.
539                
540                Its callback will not be called.
541                
542                :param async_id:
543                    which query to cancel.
544                :returns: (int) 0 if OK, else error.
545             """
546             return _unbound.ub_cancel(self,async_id)
547             #parameters: struct ub_ctx *,int,
548             #retvals: int
549
550         def get_fd(self):
551             """Get file descriptor.
552                
553                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.
554                
555                :returns: (int) -1 on error, or file descriptor to use select(2) with.
556             """
557             return _unbound.ub_fd(self)
558             #parameters: struct ub_ctx *,
559             #retvals: int
560
561         def poll(self):
562             """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.
563                
564                :returns: (int) 0 if nothing to read, or nonzero if a result is available. If nonzero, call ctx_process() to do callbacks.
565             """
566             return _unbound.ub_poll(self)
567             #parameters: struct ub_ctx *,
568             #retvals: int
569
570         def process(self):
571             """Call this routine to continue processing results from the validating resolver (when the fd becomes readable).
572                
573                Will perform necessary callbacks.
574                
575                :returns: (int) 0 if OK, else error.
576             """
577             return _unbound.ub_process(self)
578             #parameters: struct ub_ctx *,
579             #retvals: int
580
581         def resolve(self,name,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
582             """Perform resolution and validation of the target name. 
583                
584                :param name:
585                    domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
586                :param rrtype:
587                    type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
588                :param rrclass:
589                    class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
590                :returns: * (int) 0 if OK, else error.
591                          * (: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).
592             """
593             if isinstance(name, bytes): #probably IDN
594                 return _unbound.ub_resolve(self,name,rrtype,rrclass)
595             else:
596                 return _unbound.ub_resolve(self,idn2dname(name),rrtype,rrclass)
597             #parameters: struct ub_ctx *,char *,int,int,
598             #retvals: int,struct ub_result **
599
600         def resolve_async(self,name,mydata,callback,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
601             """Perform resolution and validation of the target name.
602                
603                Asynchronous, after a while, the callback will be called with your data and the result. 
604                If an error happens during processing, your callback will be called with error set to a nonzero value (and result==None).
605                
606                :param name:
607                    domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
608                :param mydata:
609                    this data is your own data (you can pass arbitrary python object or None) which are passed on to the callback function.
610                :param callback:
611                    call-back function which is called on completion of the resolution. 
612                :param rrtype:
613                    type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
614                :param rrclass:
615                    class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
616                :returns: * (int) 0 if OK, else error.
617                          * (int) async_id, an identifier number is returned for the query as it is in progress. It can be used to cancel the query.
618
619                **Call-back function:**
620                     The call-back function looks as the follows::
621                     
622                         def call_back(mydata, status, result):
623                             pass
624
625                     **Parameters:** 
626                         * `mydata` - mydata object
627                         * `status` - 0 when a result has been found
628                         * `result` - the result structure. The result may be None, in that case err is set.
629
630             """
631             if isinstance(name, bytes): #probably IDN
632                 return _unbound._ub_resolve_async(self,name,rrtype,rrclass,mydata,callback)
633             else:
634                 return _unbound._ub_resolve_async(self,idn2dname(name),rrtype,rrclass,mydata,callback)
635             #parameters: struct ub_ctx *,char *,int,int,void *,ub_callback_t,
636             #retvals: int, int
637
638         def wait(self):
639             """Wait for a context to finish with results.
640                
641                Calls  after the wait for you. After the wait, there are no more outstanding asynchronous queries.
642                
643                :returns: (int) 0 if OK, else error.
644             """
645             return _unbound.ub_wait(self)
646             #parameters: struct ub_ctx *,
647             #retvals: int
648
649         #_UB_METHODS#
650  %}
651 }
652
653
654 // ================================================================================
655 // ub_result - validation and resolution results
656 // ================================================================================
657 %nodefaultctor ub_result; //no default constructor & destructor
658 %nodefaultdtor ub_result;
659
660 %delobject ub_resolve_free;
661 %rename(_ub_resolve_free) ub_resolve_free;
662  
663 %inline %{
664   void ub_resolve_free_dbg (struct ub_result* r) {
665     printf("******** UB_RESOLVE free 0x%p ************\n", r);
666     ub_resolve_free(r);
667   }
668 %} 
669
670 %feature("docstring") ub_result "The validation and resolution results."
671
672 //ub_result.rcode
673 %inline %{
674   enum result_enum_rcode {
675     RCODE_NOERROR = 0,
676     RCODE_FORMERR = 1,
677     RCODE_SERVFAIL = 2,
678     RCODE_NXDOMAIN = 3,
679     RCODE_NOTIMPL = 4,
680     RCODE_REFUSED = 5,
681     RCODE_YXDOMAIN = 6,
682     RCODE_YXRRSET = 7,
683     RCODE_NXRRSET = 8,
684     RCODE_NOTAUTH = 9,
685     RCODE_NOTZONE = 10
686   };
687 %}
688
689 %pythoncode %{
690    class ub_data:
691       """Class which makes the resolution results accessible"""
692       def __init__(self, data):
693          """Creates ub_data class
694             :param data: a list of the result data in RAW format
695          """
696          if data == None:
697             raise Exception("ub_data init: No data")
698          self.data = data
699
700       def __str__(self):
701          """Represents data as string"""
702          return ';'.join([' '.join(map(lambda x:"%02X" % ord(x),a)) for a in self.data])
703
704       @staticmethod
705       def dname2str(s, ofs=0, maxlen=0):
706          """Parses DNAME and produces a list of labels
707         
708             :param ofs: where the conversion should start to parse data
709             :param maxlen: maximum length (0 means parse to the end)
710             :returns: list of labels (string)
711          """
712          if not s:
713             return []
714
715          res = []
716          slen = len(s)
717          if maxlen > 0:
718             slen = min(slen, maxlen)
719
720          idx = ofs
721          while (idx < slen):
722             complen = ord(s[idx])
723             # In python 3.x `str()` converts the string to unicode which is the expected text string type
724             res.append(str(s[idx+1:idx+1+complen].decode()))
725             idx += complen + 1
726
727          return res
728
729       def as_raw_data(self):
730          """Returns a list of RAW strings"""
731          return self.data
732
733       raw = property(as_raw_data, doc="Returns RAW data (a list of binary encoded strings). See :meth:`as_raw_data`")
734
735       def as_mx_list(self):
736          """Represents data as a list of MX records (query for RR_TYPE_MX)
737         
738             :returns: list of tuples (priority, dname)
739          """
740          return [(256*ord(rdf[0])+ord(rdf[1]),'.'.join([a for a in self.dname2str(rdf,2)])) for rdf in self.data]
741       
742       mx_list = property(as_mx_list, doc="Returns a list of tuples containing priority and domain names. See :meth:`as_mx_list`")
743
744       def as_idn_mx_list(self):
745          """Represents data as a list of MX records (query for RR_TYPE_MX)
746         
747             :returns: list of tuples (priority, unicode dname)
748          """
749          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]
750
751       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`")
752
753       def as_address_list(self):
754          """Represents data as a list of IP addresses (query for RR_TYPE_PTR)
755         
756             :returns: list of strings
757          """
758          return ['.'.join(map(lambda x:str(ord(x)),a)) for a in self.data]
759
760       address_list = property(as_address_list, doc="Returns a list of IP addresses. See :meth:`as_address_list`")
761
762       def as_domain_list(self):
763          """Represents data as a list of domain names (query for RR_TYPE_A)
764
765             :returns: list of strings
766          """
767          return map(lambda x:'.'.join(self.dname2str(x)), self.data)
768
769       domain_list = property(as_domain_list, doc="Returns a list of domain names. See :meth:`as_domain_list`")
770
771       def as_idn_domain_list(self):
772          """Represents data as a list of unicode domain names (query for RR_TYPE_A)
773
774             :returns: list of strings
775          """
776          return map(lambda x: '.'.join([encodings.idna.ToUnicode(a) for a in self.dname2str(x)]), self.data)
777
778       domain_list_idn = property(as_idn_domain_list, doc="Returns a list of IDN domain names. See :meth:`as_idn_domain_list`")
779 %}
780         
781 %extend ub_result
782 {
783
784   %rename(_data) data;
785   
786   PyObject* _ub_result_data(struct ub_result* result) {
787     PyObject  *list;
788      int i,cnt;
789      (void)self;
790      if ((result == 0) || (!result->havedata) || (result->data == 0))
791         return Py_None;
792
793      for (cnt=0,i=0;;i++,cnt++) 
794          if (result->data[i] == 0)
795             break;
796      
797      list = PyList_New(cnt);
798      for (i=0;i<cnt;i++) 
799          PyList_SetItem(list, i, PyBytes_FromStringAndSize(result->data[i],result->len[i]));
800      
801      return list;
802   }
803
804   PyObject* _packet() {
805       return PyBytes_FromStringAndSize($self->answer_packet, $self->answer_len);
806   }
807   
808  %pythoncode %{
809    def __init__(self):
810        raise Exception("This class can't be created directly.")
811
812    #__swig_destroy__ = _unbound.ub_resolve_free_dbg
813    __swig_destroy__ = _unbound._ub_resolve_free
814
815    #havedata = property(_unbound.ub_result_havedata_get, _unbound.ub_result_havedata_set, "Havedata property")
816
817    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'}
818
819    def _get_rcode_str(self):
820        """Returns rcode in display representation form
821
822           :returns: string
823        """
824        return self.rcode2str[self.rcode]
825
826    __swig_getmethods__["rcode_str"] = _get_rcode_str
827    if _newclass:rcode_str = _swig_property(_get_rcode_str)
828
829    def _get_raw_data(self):
830        """Result data, a list of network order DNS rdata items. 
831
832           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.
833        """
834        return self._ub_result_data(self)
835
836    __swig_getmethods__["rawdata"] = _get_raw_data
837    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.")
838
839    def _get_data(self):
840        if not self.havedata: return None
841        return ub_data(self._ub_result_data(self))
842   
843    __swig_getmethods__["data"] = _get_data
844    __swig_getmethods__["packet"] = _packet
845    data = property(_get_data, doc="Returns :class:`ub_data` instance containing various decoding functions or None")
846
847 %}
848              
849 }
850
851 %exception ub_resolve
852 %{ 
853   //printf("resolve_start(%lX)\n",(long unsigned int)arg1);
854   Py_BEGIN_ALLOW_THREADS 
855   $function 
856   Py_END_ALLOW_THREADS 
857   //printf("resolve_stop()\n");
858 %} 
859
860 %include "libunbound/unbound.h"
861
862 %inline %{
863   //SWIG will see the ub_ctx as a class
864   struct ub_ctx {
865   };
866 %}
867
868 //ub_ctx_debugout void* parameter correction
869 int ub_ctx_debugout(struct ub_ctx* ctx, FILE* out);
870
871 // ================================================================================
872 // ub_resolve_async - perform asynchronous resolution and validation
873 // ================================================================================
874
875 %typemap(in,numinputs=0,noblock=1) (int* async_id)  
876
877    int asyncid = -1;
878    $1 = &asyncid;
879
880
881 %apply PyObject* {void* mydata}
882        
883 /* result generation */
884 %typemap(argout,noblock=1) (int* async_id)
885 {
886   if(1) { /* new code block for variable on stack */
887     PyObject* tuple;
888     tuple = PyTuple_New(2);
889     PyTuple_SetItem(tuple, 0, $result);
890     PyTuple_SetItem(tuple, 1, SWIG_From_int(asyncid));
891     $result = tuple;
892   }
893 }
894
895 // Grab a Python function object as a Python object.
896 %typemap(in) (PyObject *pyfunc) {
897   if (!PyCallable_Check($input)) 
898   {
899      PyErr_SetString(PyExc_TypeError, "Need a callable object!");
900      return NULL;
901   }
902   $1 = $input;
903 }
904    
905 // Python callback workaround
906 int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, void* mydata, PyObject *pyfunc, int* async_id);
907
908 %{
909    struct cb_data {
910       PyObject* data;
911       PyObject* func;
912    };
913
914    static void PythonCallBack(void* iddata, int status, struct ub_result* result)
915    {
916       PyObject *arglist;
917       PyObject *fresult;
918       struct cb_data* id;
919       id = (struct cb_data*) iddata;
920       arglist = Py_BuildValue("(OiO)",id->data,status, SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ub_result, 0 |  0 ));   // Build argument list
921       fresult = PyEval_CallObject(id->func,arglist);     // Call Python
922       Py_DECREF(id->func);
923       Py_DECREF(id->data);
924       free(id);
925       ub_resolve_free(result);                  //free ub_result
926       //ub_resolve_free_dbg(result);                  //free ub_result
927       Py_DECREF(arglist);                           // Trash arglist
928       Py_XDECREF(fresult);
929    }
930
931    int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, PyObject* mydata, PyObject *pyfunc, int* async_id) {
932       int r;
933       struct cb_data* id;
934       id = (struct cb_data*) malloc(sizeof(struct cb_data));
935       id->data = mydata;
936       id->func = pyfunc;
937    
938       r = ub_resolve_async(ctx,name,rrtype,rrclass, (void *) id, PythonCallBack, async_id);
939       Py_INCREF(mydata);
940       Py_INCREF(pyfunc);
941       return r;
942    }
943
944 %}
945
946 %pythoncode %{
947     ub_resolve_async = _unbound._ub_resolve_async
948
949     def reverse(domain):
950         """Reverse domain name
951         
952            Usable for reverse lookups when the IP address should be reversed
953         """
954         return '.'.join([a for a in domain.split(".")][::-1])
955
956     def idn2dname(idnname):
957         """Converts domain name in IDN format to canonic domain name
958
959            :param idnname: (unicode string) IDN name
960            :returns: (string) domain name
961         """
962         return '.'.join([encodings.idna.ToASCII(a) if a else '' for a in idnname.split('.')])
963
964     def dname2idn(name):
965         """Converts canonic domain name in IDN format to unicode string
966
967             :param name: (string) domain name
968             :returns: (unicode string) domain name
969         """
970         return '.'.join([encodings.idna.ToUnicode(a) for a in name.split('.')])
971
972 %}
973