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