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