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