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