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