libunbound.i revision 238106
1238106Sdes/*
2238106Sdes * libounbound.i: pyUnbound module (libunbound wrapper for Python)
3238106Sdes *
4238106Sdes * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5238106Sdes *                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)
6238106Sdes *
7238106Sdes * This software is open source.
8238106Sdes *
9238106Sdes * Redistribution and use in source and binary forms, with or without
10238106Sdes * modification, are permitted provided that the following conditions
11238106Sdes * are met:
12238106Sdes *
13238106Sdes *    * Redistributions of source code must retain the above copyright notice,
14238106Sdes *      this list of conditions and the following disclaimer.
15238106Sdes *
16238106Sdes *    * Redistributions in binary form must reproduce the above copyright notice,
17238106Sdes *      this list of conditions and the following disclaimer in the documentation
18238106Sdes *      and/or other materials provided with the distribution.
19238106Sdes *
20238106Sdes *    * Neither the name of the organization nor the names of its
21238106Sdes *      contributors may be used to endorse or promote products derived from this
22238106Sdes *      software without specific prior written permission.
23238106Sdes *
24238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
28238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34238106Sdes * POSSIBILITY OF SUCH DAMAGE.
35238106Sdes */
36238106Sdes%module unbound
37238106Sdes%{
38238106Sdes   #include <sys/types.h>
39238106Sdes   #include <sys/socket.h>
40238106Sdes   #include <netinet/in.h>
41238106Sdes   #include <arpa/inet.h>
42238106Sdes   #include "libunbound/unbound.h"
43238106Sdes%}
44238106Sdes
45238106Sdes%pythoncode %{
46238106Sdes   import encodings.idna
47238106Sdes%}
48238106Sdes
49238106Sdes//%include "doc.i"
50238106Sdes%include "file.i"
51238106Sdes
52238106Sdes%feature("docstring") strerror "Convert error value to a human readable string."
53238106Sdes
54238106Sdes// ================================================================================
55238106Sdes// ub_resolve - perform resolution and validation
56238106Sdes// ================================================================================
57238106Sdes%typemap(in,numinputs=0,noblock=1) (struct ub_result** result)
58238106Sdes{
59238106Sdes   struct ub_result* newubr;
60238106Sdes   $1 = &newubr;
61238106Sdes}
62238106Sdes
63238106Sdes/* result generation */
64238106Sdes%typemap(argout,noblock=1) (struct ub_result** result)
65238106Sdes{
66238106Sdes  if(1) { /* new code block for variable on stack */
67238106Sdes    PyObject* tuple;
68238106Sdes    tuple = PyTuple_New(2);
69238106Sdes    PyTuple_SetItem(tuple, 0, $result);
70238106Sdes    if (result == 0) {
71238106Sdes       PyTuple_SetItem(tuple, 1, SWIG_NewPointerObj(SWIG_as_voidptr(newubr), SWIGTYPE_p_ub_result, SWIG_POINTER_OWN |  0 ));
72238106Sdes    } else {
73238106Sdes       PyTuple_SetItem(tuple, 1, Py_None);
74238106Sdes    }
75238106Sdes    $result = tuple;
76238106Sdes  }
77238106Sdes}
78238106Sdes
79238106Sdes
80238106Sdes// ================================================================================
81238106Sdes// ub_ctx - validation context
82238106Sdes// ================================================================================
83238106Sdes%nodefaultctor ub_ctx; //no default constructor & destructor
84238106Sdes%nodefaultdtor ub_ctx;
85238106Sdes
86238106Sdes%newobject ub_ctx_create;
87238106Sdes%delobject ub_ctx_delete;
88238106Sdes%rename(_ub_ctx_delete) ub_ctx_delete;
89238106Sdes
90238106Sdes%newobject ub_resolve;
91238106Sdes
92238106Sdes%inline %{
93238106Sdes  void ub_ctx_free_dbg (struct ub_ctx* c) {
94238106Sdes    printf("******** UB_CTX free 0x%lX ************\n", (long unsigned int)c);
95238106Sdes    ub_ctx_delete(c);
96238106Sdes  }
97238106Sdes
98238106Sdes  //RR types
99238106Sdes  enum enum_rr_type
100238106Sdes  {
101238106Sdes    /**  a host address */
102238106Sdes    RR_TYPE_A = 1,
103238106Sdes    /**  an authoritative name server */
104238106Sdes    RR_TYPE_NS = 2,
105238106Sdes    /**  a mail destination (Obsolete - use MX) */
106238106Sdes    RR_TYPE_MD = 3,
107238106Sdes    /**  a mail forwarder (Obsolete - use MX) */
108238106Sdes    RR_TYPE_MF = 4,
109238106Sdes    /**  the canonical name for an alias */
110238106Sdes    RR_TYPE_CNAME = 5,
111238106Sdes    /**  marks the start of a zone of authority */
112238106Sdes    RR_TYPE_SOA = 6,
113238106Sdes    /**  a mailbox domain name (EXPERIMENTAL) */
114238106Sdes    RR_TYPE_MB = 7,
115238106Sdes    /**  a mail group member (EXPERIMENTAL) */
116238106Sdes    RR_TYPE_MG = 8,
117238106Sdes    /**  a mail rename domain name (EXPERIMENTAL) */
118238106Sdes    RR_TYPE_MR = 9,
119238106Sdes    /**  a null RR (EXPERIMENTAL) */
120238106Sdes    RR_TYPE_NULL = 10,
121238106Sdes    /**  a well known service description */
122238106Sdes    RR_TYPE_WKS = 11,
123238106Sdes    /**  a domain name pointer */
124238106Sdes    RR_TYPE_PTR = 12,
125238106Sdes    /**  host information */
126238106Sdes    RR_TYPE_HINFO = 13,
127238106Sdes    /**  mailbox or mail list information */
128238106Sdes    RR_TYPE_MINFO = 14,
129238106Sdes    /**  mail exchange */
130238106Sdes    RR_TYPE_MX = 15,
131238106Sdes    /**  text strings */
132238106Sdes    RR_TYPE_TXT = 16,
133238106Sdes    /**  RFC1183 */
134238106Sdes    RR_TYPE_RP = 17,
135238106Sdes    /**  RFC1183 */
136238106Sdes    RR_TYPE_AFSDB = 18,
137238106Sdes    /**  RFC1183 */
138238106Sdes    RR_TYPE_X25 = 19,
139238106Sdes    /**  RFC1183 */
140238106Sdes    RR_TYPE_ISDN = 20,
141238106Sdes    /**  RFC1183 */
142238106Sdes    RR_TYPE_RT = 21,
143238106Sdes    /**  RFC1706 */
144238106Sdes    RR_TYPE_NSAP = 22,
145238106Sdes    /**  RFC1348 */
146238106Sdes    RR_TYPE_NSAP_PTR = 23,
147238106Sdes    /**  2535typecode */
148238106Sdes    RR_TYPE_SIG = 24,
149238106Sdes    /**  2535typecode */
150238106Sdes    RR_TYPE_KEY = 25,
151238106Sdes    /**  RFC2163 */
152238106Sdes    RR_TYPE_PX = 26,
153238106Sdes    /**  RFC1712 */
154238106Sdes    RR_TYPE_GPOS = 27,
155238106Sdes    /**  ipv6 address */
156238106Sdes    RR_TYPE_AAAA = 28,
157238106Sdes    /**  LOC record  RFC1876 */
158238106Sdes    RR_TYPE_LOC = 29,
159238106Sdes    /**  2535typecode */
160238106Sdes    RR_TYPE_NXT = 30,
161238106Sdes    /**  draft-ietf-nimrod-dns-01.txt */
162238106Sdes    RR_TYPE_EID = 31,
163238106Sdes    /**  draft-ietf-nimrod-dns-01.txt */
164238106Sdes    RR_TYPE_NIMLOC = 32,
165238106Sdes    /**  SRV record RFC2782 */
166238106Sdes    RR_TYPE_SRV = 33,
167238106Sdes    /**  http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
168238106Sdes    RR_TYPE_ATMA = 34,
169238106Sdes    /**  RFC2915 */
170238106Sdes    RR_TYPE_NAPTR = 35,
171238106Sdes    /**  RFC2230 */
172238106Sdes    RR_TYPE_KX = 36,
173238106Sdes    /**  RFC2538 */
174238106Sdes    RR_TYPE_CERT = 37,
175238106Sdes    /**  RFC2874 */
176238106Sdes    RR_TYPE_A6 = 38,
177238106Sdes    /**  RFC2672 */
178238106Sdes    RR_TYPE_DNAME = 39,
179238106Sdes    /**  dnsind-kitchen-sink-02.txt */
180238106Sdes    RR_TYPE_SINK = 40,
181238106Sdes    /**  Pseudo OPT record... */
182238106Sdes    RR_TYPE_OPT = 41,
183238106Sdes    /**  RFC3123 */
184238106Sdes    RR_TYPE_APL = 42,
185238106Sdes    /**  draft-ietf-dnsext-delegation */
186238106Sdes    RR_TYPE_DS = 43,
187238106Sdes    /**  SSH Key Fingerprint */
188238106Sdes    RR_TYPE_SSHFP = 44,
189238106Sdes    /**  draft-richardson-ipseckey-rr-11.txt */
190238106Sdes    RR_TYPE_IPSECKEY = 45,
191238106Sdes    /**  draft-ietf-dnsext-dnssec-25 */
192238106Sdes    RR_TYPE_RRSIG = 46,
193238106Sdes    RR_TYPE_NSEC = 47,
194238106Sdes    RR_TYPE_DNSKEY = 48,
195238106Sdes    RR_TYPE_DHCID = 49,
196238106Sdes
197238106Sdes    RR_TYPE_NSEC3 = 50,
198238106Sdes    RR_TYPE_NSEC3PARAMS = 51,
199238106Sdes
200238106Sdes    RR_TYPE_UINFO = 100,
201238106Sdes    RR_TYPE_UID = 101,
202238106Sdes    RR_TYPE_GID = 102,
203238106Sdes    RR_TYPE_UNSPEC = 103,
204238106Sdes
205238106Sdes    RR_TYPE_TSIG = 250,
206238106Sdes    RR_TYPE_IXFR = 251,
207238106Sdes    RR_TYPE_AXFR = 252,
208238106Sdes    /**  A request for mailbox-related records (MB, MG or MR) */
209238106Sdes    RR_TYPE_MAILB = 253,
210238106Sdes    /**  A request for mail agent RRs (Obsolete - see MX) */
211238106Sdes    RR_TYPE_MAILA = 254,
212238106Sdes    /**  any type (wildcard) */
213238106Sdes    RR_TYPE_ANY = 255,
214238106Sdes
215238106Sdes    /* RFC 4431, 5074, DNSSEC Lookaside Validation */
216238106Sdes    RR_TYPE_DLV = 32769,
217238106Sdes  };
218238106Sdes
219238106Sdes  // RR classes
220238106Sdes  enum enum_rr_class
221238106Sdes  {
222238106Sdes    /** the Internet */
223238106Sdes    RR_CLASS_IN = 1,
224238106Sdes    /** Chaos class */
225238106Sdes    RR_CLASS_CH = 3,
226238106Sdes    /** Hesiod (Dyer 87) */
227238106Sdes    RR_CLASS_HS = 4,
228238106Sdes    /** None class, dynamic update */
229238106Sdes    RR_CLASS_NONE = 254,
230238106Sdes    /** Any class */
231238106Sdes    RR_CLASS_ANY = 255,
232238106Sdes  };
233238106Sdes%}
234238106Sdes
235238106Sdes%feature("docstring") ub_ctx "Unbound resolving and validation context.
236238106Sdes
237238106SdesThe validation context is created to hold the resolver status, validation keys and a small cache (containing messages, rrsets, roundtrip times, trusted keys, lameness information).
238238106Sdes
239238106Sdes**Usage**
240238106Sdes
241238106Sdes>>> import unbound
242238106Sdes>>> ctx = unbound.ub_ctx()
243238106Sdes>>> ctx.resolvconf(\"/etc/resolv.conf\")
244238106Sdes>>> status, result = ctx.resolve(\"www.google.com\", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
245238106Sdes>>> if status==0 and result.havedata:
246238106Sdes>>>    print \"Result:\",result.data.address_list
247238106SdesResult: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
248238106Sdes"
249238106Sdes
250238106Sdes%extend ub_ctx
251238106Sdes{
252238106Sdes %pythoncode %{
253238106Sdes        def __init__(self):
254238106Sdes            """Creates a resolving and validation context.
255238106Sdes
256238106Sdes               An exception is invoked if the process of creation an ub_ctx instance fails.
257238106Sdes            """
258238106Sdes            self.this = _unbound.ub_ctx_create()
259238106Sdes            if not self.this:
260238106Sdes                raise Exception("Fatal error: unbound context initialization failed")
261238106Sdes
262238106Sdes        #__swig_destroy__ = _unbound.ub_ctx_free_dbg
263238106Sdes        __swig_destroy__ = _unbound._ub_ctx_delete
264238106Sdes
265238106Sdes        #UB_CTX_METHODS_#
266238106Sdes        def add_ta(self,ta):
267238106Sdes            """Add a trust anchor to the given context.
268238106Sdes
269238106Sdes               The trust anchor is a string, on one line, that holds a valid DNSKEY or DS RR.
270238106Sdes
271238106Sdes               :param ta:
272238106Sdes                   string, with zone-format RR on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
273238106Sdes               :returns: (int) 0 if OK, else error.
274238106Sdes            """
275238106Sdes            return _unbound.ub_ctx_add_ta(self,ta)
276238106Sdes            #parameters: struct ub_ctx *,char *,
277238106Sdes            #retvals: int
278238106Sdes
279238106Sdes        def add_ta_file(self,fname):
280238106Sdes            """Add trust anchors to the given context.
281238106Sdes
282238106Sdes               Pass name of a file with DS and DNSKEY records (like from dig or drill).
283238106Sdes
284238106Sdes               :param fname:
285238106Sdes                   filename of file with keyfile with trust anchors.
286238106Sdes               :returns: (int) 0 if OK, else error.
287238106Sdes            """
288238106Sdes            return _unbound.ub_ctx_add_ta_file(self,fname)
289238106Sdes            #parameters: struct ub_ctx *,char *,
290238106Sdes            #retvals: int
291238106Sdes
292238106Sdes        def config(self,fname):
293238106Sdes            """setup configuration for the given context.
294238106Sdes
295238106Sdes               :param fname:
296238106Sdes                   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.
297238106Sdes               :returns: (int) 0 if OK, else error.
298238106Sdes            """
299238106Sdes            return _unbound.ub_ctx_config(self,fname)
300238106Sdes            #parameters: struct ub_ctx *,char *,
301238106Sdes            #retvals: int
302238106Sdes
303238106Sdes        def debuglevel(self,d):
304238106Sdes            """Set debug verbosity for the context Output is directed to stderr.
305238106Sdes
306238106Sdes               :param d:
307238106Sdes                   debug level, 0 is off, 1 is very minimal, 2 is detailed, and 3 is lots.
308238106Sdes               :returns: (int) 0 if OK, else error.
309238106Sdes            """
310238106Sdes            return _unbound.ub_ctx_debuglevel(self,d)
311238106Sdes            #parameters: struct ub_ctx *,int,
312238106Sdes            #retvals: int
313238106Sdes
314238106Sdes        def debugout(self,out):
315238106Sdes            """Set debug output (and error output) to the specified stream.
316238106Sdes
317238106Sdes               Pass None to disable. Default is stderr.
318238106Sdes
319238106Sdes               :param out:
320238106Sdes                   File stream to log to.
321238106Sdes               :returns: (int) 0 if OK, else error.
322238106Sdes
323238106Sdes               **Usage:**
324238106Sdes
325238106Sdes                  In order to log into file, use
326238106Sdes
327238106Sdes                  ::
328238106Sdes
329238106Sdes                    ctx = unbound.ub_ctx()
330238106Sdes                    fw = fopen("debug.log")
331238106Sdes                    ctx.debuglevel(3)
332238106Sdes                    ctx.debugout(fw)
333238106Sdes
334238106Sdes                  Another option is to print the debug informations to stderr output
335238106Sdes
336238106Sdes                  ::
337238106Sdes
338238106Sdes                    ctx = unbound.ub_ctx()
339238106Sdes                    ctx.debuglevel(10)
340238106Sdes                    ctx.debugout(sys.stderr)
341238106Sdes            """
342238106Sdes            return _unbound.ub_ctx_debugout(self,out)
343238106Sdes            #parameters: struct ub_ctx *,void *,
344238106Sdes            #retvals: int
345238106Sdes
346238106Sdes        def hosts(self,fname="/etc/hosts"):
347238106Sdes            """Read list of hosts from the filename given.
348238106Sdes
349238106Sdes               Usually "/etc/hosts". These addresses are not flagged as DNSSEC secure when queried for.
350238106Sdes
351238106Sdes               :param fname:
352238106Sdes                   file name string. If None "/etc/hosts" is used.
353238106Sdes               :returns: (int) 0 if OK, else error.
354238106Sdes            """
355238106Sdes            return _unbound.ub_ctx_hosts(self,fname)
356238106Sdes            #parameters: struct ub_ctx *,char *,
357238106Sdes            #retvals: int
358238106Sdes
359238106Sdes        def print_local_zones(self):
360238106Sdes            """Print the local zones and their content (RR data) to the debug output.
361238106Sdes
362238106Sdes               :returns: (int) 0 if OK, else error.
363238106Sdes            """
364238106Sdes            return _unbound.ub_ctx_print_local_zones(self)
365238106Sdes            #parameters: struct ub_ctx *,
366238106Sdes            #retvals: int
367238106Sdes
368238106Sdes        def resolvconf(self,fname="/etc/resolv.conf"):
369238106Sdes            """Read list of nameservers to use from the filename given.
370238106Sdes
371238106Sdes               Usually "/etc/resolv.conf". Uses those nameservers as caching proxies. If they do not support DNSSEC, validation may fail.
372238106Sdes
373238106Sdes               Only nameservers are picked up, the searchdomain, ndots and other settings from resolv.conf(5) are ignored.
374238106Sdes
375238106Sdes               :param fname:
376238106Sdes                   file name string. If None "/etc/resolv.conf" is used.
377238106Sdes               :returns: (int) 0 if OK, else error.
378238106Sdes            """
379238106Sdes            return _unbound.ub_ctx_resolvconf(self,fname)
380238106Sdes            #parameters: struct ub_ctx *,char *,
381238106Sdes            #retvals: int
382238106Sdes
383238106Sdes        def set_async(self,dothread):
384238106Sdes            """Set a context behaviour for asynchronous action.
385238106Sdes
386238106Sdes               :param dothread:
387238106Sdes                   if True, enables threading and a call to :meth:`resolve_async` creates a thread to handle work in the background.
388238106Sdes                   If False, a process is forked to handle work in the background.
389238106Sdes                   Changes to this setting after :meth:`async` calls have been made have no effect (delete and re-create the context to change).
390238106Sdes               :returns: (int) 0 if OK, else error.
391238106Sdes            """
392238106Sdes            return _unbound.ub_ctx_async(self,dothread)
393238106Sdes            #parameters: struct ub_ctx *,int,
394238106Sdes            #retvals: int
395238106Sdes
396238106Sdes        def set_fwd(self,addr):
397238106Sdes            """Set machine to forward DNS queries to, the caching resolver to use.
398238106Sdes
399238106Sdes               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.
400238106Sdes
401238106Sdes               To read the list of nameservers from /etc/resolv.conf (from DHCP or so), use the call :meth:`resolvconf`.
402238106Sdes
403238106Sdes               :param addr:
404238106Sdes                   address, IP4 or IP6 in string format. If the addr is None, forwarding is disabled.
405238106Sdes               :returns: (int) 0 if OK, else error.
406238106Sdes            """
407238106Sdes            return _unbound.ub_ctx_set_fwd(self,addr)
408238106Sdes            #parameters: struct ub_ctx *,char *,
409238106Sdes            #retvals: int
410238106Sdes
411238106Sdes        def set_option(self,opt,val):
412238106Sdes            """Set an option for the context.
413238106Sdes
414238106Sdes               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).
415238106Sdes
416238106Sdes               :param opt:
417238106Sdes                   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.
418238106Sdes               :param val:
419238106Sdes                   value of the option.
420238106Sdes               :returns: (int) 0 if OK, else error.
421238106Sdes            """
422238106Sdes            return _unbound.ub_ctx_set_option(self,opt,val)
423238106Sdes            #parameters: struct ub_ctx *,char *,char *,
424238106Sdes            #retvals: int
425238106Sdes
426238106Sdes        def trustedkeys(self,fname):
427238106Sdes            """Add trust anchors to the given context.
428238106Sdes
429238106Sdes               Pass the name of a bind-style config file with trusted-keys{}.
430238106Sdes
431238106Sdes               :param fname:
432238106Sdes                   filename of file with bind-style config entries with trust anchors.
433238106Sdes               :returns: (int) 0 if OK, else error.
434238106Sdes            """
435238106Sdes            return _unbound.ub_ctx_trustedkeys(self,fname)
436238106Sdes            #parameters: struct ub_ctx *,char *,
437238106Sdes            #retvals: int
438238106Sdes        #_UB_CTX_METHODS#
439238106Sdes
440238106Sdes        def zone_print(self):
441238106Sdes            """Print local zones using debougout"""
442238106Sdes            _unbound.ub_ctx_print_local_zones(self)
443238106Sdes
444238106Sdes        def zone_add(self,zonename,zonetype):
445238106Sdes            """Add new local zone
446238106Sdes
447238106Sdes               :param zonename: zone domain name (e.g. myzone.)
448238106Sdes               :param zonetype: type of the zone ("static",...)
449238106Sdes               :returns: (int) 0 if OK, else error.
450238106Sdes            """
451238106Sdes            return _unbound.ub_ctx_zone_add(self,zonename, zonetype)
452238106Sdes            #parameters: struct ub_ctx *,char*, char*
453238106Sdes            #retvals: int
454238106Sdes
455238106Sdes        def zone_remove(self,zonename):
456238106Sdes            """Remove local zone
457238106Sdes
458238106Sdes               If exists, removes local zone with all the RRs.
459238106Sdes
460238106Sdes               :param zonename: zone domain name
461238106Sdes               :returns: (int) 0 if OK, else error.
462238106Sdes            """
463238106Sdes            return _unbound.ub_ctx_zone_remove(self,zonename)
464238106Sdes            #parameters: struct ub_ctx *,char*
465238106Sdes            #retvals: int
466238106Sdes
467238106Sdes        def data_add(self,rrdata):
468238106Sdes            """Add new local RR data
469238106Sdes
470238106Sdes               :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
471238106Sdes               :returns: (int) 0 if OK, else error.
472238106Sdes
473238106Sdes               **Usage**
474238106Sdes                  The local data ...
475238106Sdes
476238106Sdes                  ::
477238106Sdes
478238106Sdes                    >>> ctx = unbound.ub_ctx()
479238106Sdes                    >>> ctx.zone_add("mydomain.net.","static")
480238106Sdes                    0
481238106Sdes                    >>> status = ctx.data_add("test.mydomain.net. IN A 192.168.1.1")
482238106Sdes                    0
483238106Sdes                    >>> status, result = ctx.resolve("test.mydomain.net")
484238106Sdes                    >>> if status==0 and result.havedata:
485238106Sdes                    >>>    print \"Result:\",result.data.address_list
486238106Sdes                    Result: ['192.168.1.1']
487238106Sdes
488238106Sdes            """
489238106Sdes            return _unbound.ub_ctx_data_add(self,rrdata)
490238106Sdes            #parameters: struct ub_ctx *,char*
491238106Sdes            #retvals: int
492238106Sdes
493238106Sdes        def data_remove(self,rrdata):
494238106Sdes            """Remove local RR data
495238106Sdes
496238106Sdes               If exists, remove resource record from local zone
497238106Sdes
498238106Sdes               :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
499238106Sdes               :returns: (int) 0 if OK, else error.
500238106Sdes            """
501238106Sdes            return _unbound.ub_ctx_data_remove(self,rrdata)
502238106Sdes            #parameters: struct ub_ctx *,char*
503238106Sdes            #retvals: int
504238106Sdes
505238106Sdes        #UB_METHODS_#
506238106Sdes        def cancel(self,async_id):
507238106Sdes            """Cancel an async query in progress.
508238106Sdes
509238106Sdes               Its callback will not be called.
510238106Sdes
511238106Sdes               :param async_id:
512238106Sdes                   which query to cancel.
513238106Sdes               :returns: (int) 0 if OK, else error.
514238106Sdes            """
515238106Sdes            return _unbound.ub_cancel(self,async_id)
516238106Sdes            #parameters: struct ub_ctx *,int,
517238106Sdes            #retvals: int
518238106Sdes
519238106Sdes        def get_fd(self):
520238106Sdes            """Get file descriptor.
521238106Sdes
522238106Sdes               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.
523238106Sdes
524238106Sdes               :returns: (int) -1 on error, or file descriptor to use select(2) with.
525238106Sdes            """
526238106Sdes            return _unbound.ub_fd(self)
527238106Sdes            #parameters: struct ub_ctx *,
528238106Sdes            #retvals: int
529238106Sdes
530238106Sdes        def poll(self):
531238106Sdes            """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.
532238106Sdes
533238106Sdes               :returns: (int) 0 if nothing to read, or nonzero if a result is available. If nonzero, call ctx_process() to do callbacks.
534238106Sdes            """
535238106Sdes            return _unbound.ub_poll(self)
536238106Sdes            #parameters: struct ub_ctx *,
537238106Sdes            #retvals: int
538238106Sdes
539238106Sdes        def process(self):
540238106Sdes            """Call this routine to continue processing results from the validating resolver (when the fd becomes readable).
541238106Sdes
542238106Sdes               Will perform necessary callbacks.
543238106Sdes
544238106Sdes               :returns: (int) 0 if OK, else error.
545238106Sdes            """
546238106Sdes            return _unbound.ub_process(self)
547238106Sdes            #parameters: struct ub_ctx *,
548238106Sdes            #retvals: int
549238106Sdes
550238106Sdes        def resolve(self,name,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
551238106Sdes            """Perform resolution and validation of the target name.
552238106Sdes
553238106Sdes               :param name:
554238106Sdes                   domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
555238106Sdes               :param rrtype:
556238106Sdes                   type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
557238106Sdes               :param rrclass:
558238106Sdes                   class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
559238106Sdes               :returns: * (int) 0 if OK, else error.
560238106Sdes                         * (: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).
561238106Sdes            """
562238106Sdes            if isinstance(name, unicode): #probably IDN
563238106Sdes                return _unbound.ub_resolve(self,idn2dname(name),rrtype,rrclass)
564238106Sdes            else:
565238106Sdes                return _unbound.ub_resolve(self,name,rrtype,rrclass)
566238106Sdes            #parameters: struct ub_ctx *,char *,int,int,
567238106Sdes            #retvals: int,struct ub_result **
568238106Sdes
569238106Sdes        def resolve_async(self,name,mydata,callback,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
570238106Sdes            """Perform resolution and validation of the target name.
571238106Sdes
572238106Sdes               Asynchronous, after a while, the callback will be called with your data and the result.
573238106Sdes               If an error happens during processing, your callback will be called with error set to a nonzero value (and result==None).
574238106Sdes
575238106Sdes               :param name:
576238106Sdes                   domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
577238106Sdes               :param mydata:
578238106Sdes                   this data is your own data (you can pass arbitrary python object or None) which are passed on to the callback function.
579238106Sdes               :param callback:
580238106Sdes                   call-back function which is called on completion of the resolution.
581238106Sdes               :param rrtype:
582238106Sdes                   type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
583238106Sdes               :param rrclass:
584238106Sdes                   class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
585238106Sdes               :returns: * (int) 0 if OK, else error.
586238106Sdes                         * (int) async_id, an identifier number is returned for the query as it is in progress. It can be used to cancel the query.
587238106Sdes
588238106Sdes               **Call-back function:**
589238106Sdes                    The call-back function looks as the follows::
590238106Sdes
591238106Sdes                        def call_back(mydata, status, result):
592238106Sdes                            pass
593238106Sdes
594238106Sdes                    **Parameters:**
595238106Sdes                        * `mydata` - mydata object
596238106Sdes                        * `status` - 0 when a result has been found
597238106Sdes                        * `result` - the result structure. The result may be None, in that case err is set.
598238106Sdes
599238106Sdes            """
600238106Sdes            if isinstance(name, unicode): #probably IDN
601238106Sdes                return _unbound._ub_resolve_async(self,idn2dname(name),rrtype,rrclass,mydata,callback)
602238106Sdes            else:
603238106Sdes                return _unbound._ub_resolve_async(self,name,rrtype,rrclass,mydata,callback)
604238106Sdes            #parameters: struct ub_ctx *,char *,int,int,void *,ub_callback_t,
605238106Sdes            #retvals: int, int
606238106Sdes
607238106Sdes        def wait(self):
608238106Sdes            """Wait for a context to finish with results.
609238106Sdes
610238106Sdes               Calls  after the wait for you. After the wait, there are no more outstanding asynchronous queries.
611238106Sdes
612238106Sdes               :returns: (int) 0 if OK, else error.
613238106Sdes            """
614238106Sdes            return _unbound.ub_wait(self)
615238106Sdes            #parameters: struct ub_ctx *,
616238106Sdes            #retvals: int
617238106Sdes
618238106Sdes        #_UB_METHODS#
619238106Sdes %}
620238106Sdes}
621238106Sdes
622238106Sdes
623238106Sdes// ================================================================================
624238106Sdes// ub_result - validation and resolution results
625238106Sdes// ================================================================================
626238106Sdes%nodefaultctor ub_result; //no default constructor & destructor
627238106Sdes%nodefaultdtor ub_result;
628238106Sdes
629238106Sdes%delobject ub_resolve_free;
630238106Sdes%rename(_ub_resolve_free) ub_resolve_free;
631238106Sdes
632238106Sdes%inline %{
633238106Sdes  void ub_resolve_free_dbg (struct ub_result* r) {
634238106Sdes    printf("******** UB_RESOLVE free 0x%lX ************\n", (long unsigned int)r);
635238106Sdes    ub_resolve_free(r);
636238106Sdes  }
637238106Sdes%}
638238106Sdes
639238106Sdes%feature("docstring") ub_result "The validation and resolution results."
640238106Sdes
641238106Sdes//ub_result.rcode
642238106Sdes%inline %{
643238106Sdes  enum result_enum_rcode {
644238106Sdes    RCODE_NOERROR = 0,
645238106Sdes    RCODE_FORMERR = 1,
646238106Sdes    RCODE_SERVFAIL = 2,
647238106Sdes    RCODE_NXDOMAIN = 3,
648238106Sdes    RCODE_NOTIMPL = 4,
649238106Sdes    RCODE_REFUSED = 5,
650238106Sdes    RCODE_YXDOMAIN = 6,
651238106Sdes    RCODE_YXRRSET = 7,
652238106Sdes    RCODE_NXRRSET = 8,
653238106Sdes    RCODE_NOTAUTH = 9,
654238106Sdes    RCODE_NOTZONE = 10
655238106Sdes  };
656238106Sdes%}
657238106Sdes
658238106Sdes%pythoncode %{
659238106Sdes   class ub_data:
660238106Sdes      """Class which makes the resolution results accessible"""
661238106Sdes      def __init__(self, data):
662238106Sdes         """Creates ub_data class
663238106Sdes            :param data: a list of the result data in RAW format
664238106Sdes         """
665238106Sdes         if data == None:
666238106Sdes            raise Exception("ub_data init: No data")
667238106Sdes         self.data = data
668238106Sdes
669238106Sdes      def __str__(self):
670238106Sdes         """Represents data as string"""
671238106Sdes         return ';'.join([' '.join(map(lambda x:"%02X" % ord(x),a)) for a in self.data])
672238106Sdes
673238106Sdes      @staticmethod
674238106Sdes      def dname2str(s, ofs=0, maxlen=0):
675238106Sdes         """Parses DNAME and produces a list of labels
676238106Sdes
677238106Sdes            :param ofs: where the conversion should start to parse data
678238106Sdes            :param maxlen: maximum length (0 means parse to the end)
679238106Sdes            :returns: list of labels (string)
680238106Sdes         """
681238106Sdes         if not s:
682238106Sdes            return []
683238106Sdes
684238106Sdes         res = []
685238106Sdes         slen = len(s)
686238106Sdes         if maxlen > 0:
687238106Sdes            slen = min(slen, maxlen)
688238106Sdes
689238106Sdes         idx = ofs
690238106Sdes         while (idx < slen):
691238106Sdes            complen = ord(s[idx])
692238106Sdes            res.append(s[idx+1:idx+1+complen])
693238106Sdes            idx += complen + 1
694238106Sdes
695238106Sdes         return res
696238106Sdes
697238106Sdes      def as_raw_data(self):
698238106Sdes         """Returns a list of RAW strings"""
699238106Sdes         return self.data
700238106Sdes
701238106Sdes      raw = property(as_raw_data, doc="Returns RAW data (a list of binary encoded strings). See :meth:`as_raw_data`")
702238106Sdes
703238106Sdes      def as_mx_list(self):
704238106Sdes         """Represents data as a list of MX records (query for RR_TYPE_MX)
705238106Sdes
706238106Sdes            :returns: list of tuples (priority, dname)
707238106Sdes         """
708238106Sdes         return [(256*ord(rdf[0])+ord(rdf[1]),'.'.join([a for a in self.dname2str(rdf,2)])) for rdf in self.data]
709238106Sdes
710238106Sdes      mx_list = property(as_mx_list, doc="Returns a list of tuples containing priority and domain names. See :meth:`as_mx_list`")
711238106Sdes
712238106Sdes      def as_idn_mx_list(self):
713238106Sdes         """Represents data as a list of MX records (query for RR_TYPE_MX)
714238106Sdes
715238106Sdes            :returns: list of tuples (priority, unicode dname)
716238106Sdes         """
717238106Sdes         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]
718238106Sdes
719238106Sdes      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`")
720238106Sdes
721238106Sdes      def as_address_list(self):
722238106Sdes         """Represents data as a list of IP addresses (query for RR_TYPE_PTR)
723238106Sdes
724238106Sdes            :returns: list of strings
725238106Sdes         """
726238106Sdes         return ['.'.join(map(lambda x:str(ord(x)),a)) for a in self.data]
727238106Sdes
728238106Sdes      address_list = property(as_address_list, doc="Returns a list of IP addresses. See :meth:`as_address_list`")
729238106Sdes
730238106Sdes      def as_domain_list(self):
731238106Sdes         """Represents data as a list of domain names (query for RR_TYPE_A)
732238106Sdes
733238106Sdes            :returns: list of strings
734238106Sdes         """
735238106Sdes         return map(lambda x:'.'.join(self.dname2str(x)), self.data)
736238106Sdes
737238106Sdes      domain_list = property(as_domain_list, doc="Returns a list of domain names. See :meth:`as_domain_list`")
738238106Sdes
739238106Sdes      def as_idn_domain_list(self):
740238106Sdes         """Represents data as a list of unicode domain names (query for RR_TYPE_A)
741238106Sdes
742238106Sdes            :returns: list of strings
743238106Sdes         """
744238106Sdes         return map(lambda x: '.'.join([encodings.idna.ToUnicode(a) for a in self.dname2str(x)]), self.data)
745238106Sdes
746238106Sdes      domain_list_idn = property(as_idn_domain_list, doc="Returns a list of IDN domain names. See :meth:`as_idn_domain_list`")
747238106Sdes%}
748238106Sdes
749238106Sdes%extend ub_result
750238106Sdes{
751238106Sdes
752238106Sdes  %rename(_data) data;
753238106Sdes
754238106Sdes  PyObject* _ub_result_data(struct ub_result* result) {
755238106Sdes    PyObject  *list;
756238106Sdes     int i,cnt;
757238106Sdes     (void)self;
758238106Sdes     if ((result == 0) || (!result->havedata) || (result->data == 0))
759238106Sdes        return Py_None;
760238106Sdes
761238106Sdes     for (cnt=0,i=0;;i++,cnt++)
762238106Sdes         if (result->data[i] == 0)
763238106Sdes            break;
764238106Sdes
765238106Sdes     list = PyList_New(cnt);
766238106Sdes     for (i=0;i<cnt;i++)
767238106Sdes         PyList_SetItem(list, i, PyString_FromStringAndSize(result->data[i],result->len[i]));
768238106Sdes
769238106Sdes     return list;
770238106Sdes  }
771238106Sdes
772238106Sdes  PyObject* _packet() {
773238106Sdes      return PyString_FromStringAndSize($self->answer_packet, $self->answer_len);
774238106Sdes  }
775238106Sdes
776238106Sdes %pythoncode %{
777238106Sdes   def __init__(self):
778238106Sdes       raise Exception("This class can't be created directly.")
779238106Sdes
780238106Sdes   #__swig_destroy__ = _unbound.ub_resolve_free_dbg
781238106Sdes   __swig_destroy__ = _unbound._ub_resolve_free
782238106Sdes
783238106Sdes   #havedata = property(_unbound.ub_result_havedata_get, _unbound.ub_result_havedata_set, "Havedata property")
784238106Sdes
785238106Sdes   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'}
786238106Sdes
787238106Sdes   def _get_rcode_str(self):
788238106Sdes       """Returns rcode in display representation form
789238106Sdes
790238106Sdes          :returns: string
791238106Sdes       """
792238106Sdes       return self.rcode2str[self.rcode]
793238106Sdes
794238106Sdes   __swig_getmethods__["rcode_str"] = _get_rcode_str
795238106Sdes   if _newclass:rcode_str = _swig_property(_get_rcode_str)
796238106Sdes
797238106Sdes   def _get_raw_data(self):
798238106Sdes       """Result data, a list of network order DNS rdata items.
799238106Sdes
800238106Sdes          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.
801238106Sdes       """
802238106Sdes       return self._ub_result_data(self)
803238106Sdes
804238106Sdes   __swig_getmethods__["rawdata"] = _get_raw_data
805238106Sdes   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.")
806238106Sdes
807238106Sdes   def _get_data(self):
808238106Sdes       if not self.havedata: return None
809238106Sdes       return ub_data(self._ub_result_data(self))
810238106Sdes
811238106Sdes   __swig_getmethods__["data"] = _get_data
812238106Sdes   __swig_getmethods__["packet"] = _packet
813238106Sdes   data = property(_get_data, doc="Returns :class:`ub_data` instance containing various decoding functions or None")
814238106Sdes
815238106Sdes%}
816238106Sdes
817238106Sdes}
818238106Sdes
819238106Sdes%exception ub_resolve
820238106Sdes%{
821238106Sdes  //printf("resolve_start(%lX)\n",(long unsigned int)arg1);
822238106Sdes  Py_BEGIN_ALLOW_THREADS
823238106Sdes  $function
824238106Sdes  Py_END_ALLOW_THREADS
825238106Sdes  //printf("resolve_stop()\n");
826238106Sdes%}
827238106Sdes
828238106Sdes%include "libunbound/unbound.h"
829238106Sdes
830238106Sdes%inline %{
831238106Sdes  //SWIG will see the ub_ctx as a class
832238106Sdes  struct ub_ctx {
833238106Sdes  };
834238106Sdes%}
835238106Sdes
836238106Sdes//ub_ctx_debugout void* parameter correction
837238106Sdesint ub_ctx_debugout(struct ub_ctx* ctx, FILE* out);
838238106Sdes
839238106Sdes// ================================================================================
840238106Sdes// ub_resolve_async - perform asynchronous resolution and validation
841238106Sdes// ================================================================================
842238106Sdes
843238106Sdes%typemap(in,numinputs=0,noblock=1) (int* async_id)
844238106Sdes{
845238106Sdes   int asyncid = -1;
846238106Sdes   $1 = &asyncid;
847238106Sdes}
848238106Sdes
849238106Sdes%apply PyObject* {void* mydata}
850238106Sdes
851238106Sdes/* result generation */
852238106Sdes%typemap(argout,noblock=1) (int* async_id)
853238106Sdes{
854238106Sdes  if(1) { /* new code block for variable on stack */
855238106Sdes    PyObject* tuple;
856238106Sdes    tuple = PyTuple_New(2);
857238106Sdes    PyTuple_SetItem(tuple, 0, $result);
858238106Sdes    PyTuple_SetItem(tuple, 1, SWIG_From_int(asyncid));
859238106Sdes    $result = tuple;
860238106Sdes  }
861238106Sdes}
862238106Sdes
863238106Sdes// Grab a Python function object as a Python object.
864238106Sdes%typemap(in) (PyObject *pyfunc) {
865238106Sdes  if (!PyCallable_Check($input))
866238106Sdes  {
867238106Sdes     PyErr_SetString(PyExc_TypeError, "Need a callable object!");
868238106Sdes     return NULL;
869238106Sdes  }
870238106Sdes  $1 = $input;
871238106Sdes}
872238106Sdes
873238106Sdes// Python callback workaround
874238106Sdesint _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, void* mydata, PyObject *pyfunc, int* async_id);
875238106Sdes
876238106Sdes%{
877238106Sdes   struct cb_data {
878238106Sdes      PyObject* data;
879238106Sdes      PyObject* func;
880238106Sdes   };
881238106Sdes
882238106Sdes   static void PythonCallBack(void* iddata, int status, struct ub_result* result)
883238106Sdes   {
884238106Sdes      PyObject *arglist;
885238106Sdes      PyObject *fresult;
886238106Sdes      struct cb_data* id;
887238106Sdes      id = (struct cb_data*) iddata;
888238106Sdes      arglist = Py_BuildValue("(OiO)",id->data,status, SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ub_result, 0 |  0 ));   // Build argument list
889238106Sdes      fresult = PyEval_CallObject(id->func,arglist);     // Call Python
890238106Sdes      Py_DECREF(id->func);
891238106Sdes      Py_DECREF(id->data);
892238106Sdes      free(id);
893238106Sdes      ub_resolve_free(result);                  //free ub_result
894238106Sdes      //ub_resolve_free_dbg(result);                  //free ub_result
895238106Sdes      Py_DECREF(arglist);                           // Trash arglist
896238106Sdes      Py_XDECREF(fresult);
897238106Sdes   }
898238106Sdes
899238106Sdes   int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, PyObject* mydata, PyObject *pyfunc, int* async_id) {
900238106Sdes      int r;
901238106Sdes      struct cb_data* id;
902238106Sdes      id = (struct cb_data*) malloc(sizeof(struct cb_data));
903238106Sdes      id->data = mydata;
904238106Sdes      id->func = pyfunc;
905238106Sdes
906238106Sdes      r = ub_resolve_async(ctx,name,rrtype,rrclass, (void *) id, PythonCallBack, async_id);
907238106Sdes      Py_INCREF(mydata);
908238106Sdes      Py_INCREF(pyfunc);
909238106Sdes      return r;
910238106Sdes   }
911238106Sdes
912238106Sdes%}
913238106Sdes
914238106Sdes%pythoncode %{
915238106Sdes    ub_resolve_async = _unbound._ub_resolve_async
916238106Sdes
917238106Sdes    def reverse(domain):
918238106Sdes        """Reverse domain name
919238106Sdes
920238106Sdes           Usable for reverse lookups when the IP address should be reversed
921238106Sdes        """
922238106Sdes        return '.'.join([a for a in domain.split(".")][::-1])
923238106Sdes
924238106Sdes    def idn2dname(idnname):
925238106Sdes        """Converts domain name in IDN format to canonic domain name
926238106Sdes
927238106Sdes           :param idnname: (unicode string) IDN name
928238106Sdes           :returns: (string) domain name
929238106Sdes        """
930238106Sdes        return '.'.join([encodings.idna.ToASCII(a) for a in idnname.split('.')])
931238106Sdes
932238106Sdes    def dname2idn(name):
933238106Sdes        """Converts canonic domain name in IDN format to unicode string
934238106Sdes
935238106Sdes            :param name: (string) domain name
936238106Sdes            :returns: (unicode string) domain name
937238106Sdes        """
938238106Sdes        return '.'.join([encodings.idna.ToUnicode(a) for a in name.split('.')])
939238106Sdes
940238106Sdes%}
941238106Sdes
942