=head1 NAME
Unbound.xs - Perl interface to libunbound
=head1 DESCRIPTION
Perl XS extension providing access to the NLnetLabs libunbound library.
This implementation is intended to support Net::DNS::Resolver::Unbound.
It is NOT, nor will it ever be, suitable for general use.
=head1 COPYRIGHT
Copyright (c)2022 Dick Franks
All Rights Reserved
=head1 LICENSE
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the original copyright notices appear in all copies and that both
copyright notice and this permission notice appear in supporting
documentation, and that the name of the author not be used in advertising
or publicity pertaining to distribution of the software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
=cut
#ifdef __cplusplus
extern "C" {
#endif
#define PERL_NO_GET_CONTEXT
#define PERL_REENTRANT
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
#include <unbound.h>
#ifdef __cplusplus
}
#endif
#define UNBOUND_VERSION (UNBOUND_VERSION_MAJOR*100 + UNBOUND_VERSION_MINOR)*100 + UNBOUND_VERSION_MICRO
#define checkerr(arg) checkret( (arg), __LINE__ )
static void checkret(const int err, int line)
{
if (err) croak( "%s (%d) %s line %d", ub_strerror(err), err, __FILE__, line );
}
typedef struct ub_ctx* Net__DNS__Resolver__Unbound__Context;
typedef struct ub_result* Net__DNS__Resolver__Unbound__Result;
typedef struct av* Net__DNS__Resolver__Unbound__Handle;
static void async_callback(void* mydata, int err, struct ub_result* result)
{
dTHX; /* fetch context */
SV* resobj = newSV(0);
sv_setref_pv(resobj, "Net::DNS::Resolver::Unbound::Result", (void*)result);
av_push( (AV*)mydata, newSViv(err) );
av_push( (AV*)mydata, resobj );
return;
}
MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::Unbound::Handle
PROTOTYPES: ENABLE
void
DESTROY(struct av* handle)
CODE:
sv_2mortal( (SV*) handle );
int
query_id(struct av* handle)
INIT:
SV** index = av_fetch(handle, 0, 0);
CODE:
RETVAL = SvIVX(*index);
OUTPUT:
RETVAL
SV*
err(struct av* handle)
INIT:
SV** index = av_fetch(handle, 1, 0);
int err = index ? SvIVX(*index) : 0;
CODE:
RETVAL = newSVpvf( err ? "%s (%d)" : "", ub_strerror(err), err );
OUTPUT:
RETVAL
SV*
result(struct av* handle)
INIT:
SV** index = av_fetch(handle, 2, 0);
CODE:
RETVAL = index ? av_pop(handle) : NULL;
OUTPUT:
RETVAL
int
waiting(struct av* handle)
INIT:
SV** index = av_fetch(handle, 1, 0);
CODE:
RETVAL = index ? 0 : 1;
OUTPUT:
RETVAL
MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::Unbound::Result
void
DESTROY(struct ub_result* result)
CODE:
ub_resolve_free(result);
SV*
answer_packet(struct ub_result* result)
CODE:
RETVAL = newSVpvn( result->answer_packet, result->answer_len );
OUTPUT:
RETVAL
int
secure(struct ub_result* result)
CODE:
RETVAL = result->secure;
OUTPUT:
RETVAL
int
bogus(struct ub_result* result)
CODE:
RETVAL = result->bogus;
OUTPUT:
RETVAL
SV*
why_bogus(struct ub_result* result)
CODE:
RETVAL = newSVpv( result->why_bogus, 0 );
OUTPUT:
RETVAL
MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::Unbound::Context
Net::DNS::Resolver::Unbound::Context
new(void)
CODE:
RETVAL = ub_ctx_create();
OUTPUT:
RETVAL
void
DESTROY(struct ub_ctx* context)
CODE:
ub_ctx_delete(context);
void
set_option(struct ub_ctx* ctx, SV* opt, SV* val)
CODE:
checkerr( ub_ctx_set_option(ctx, (const char*) SvPVX(opt), (const char*) SvPVX(val)) );
SV*
get_option(struct ub_ctx* ctx, SV* opt)
INIT:
char* value;
CODE:
checkerr( ub_ctx_get_option(ctx, (const char*) SvPVX(opt), &value) );
RETVAL = newSVpv( value, 0 );
free(value);
OUTPUT:
RETVAL
void
config(struct ub_ctx* ctx, const char* fname)
CODE:
checkerr( ub_ctx_config(ctx, fname) );
void
set_fwd(struct ub_ctx* ctx, const char* addr)
CODE:
checkerr( ub_ctx_set_fwd(ctx, addr) );
void
resolv_conf(struct ub_ctx* ctx, const char* fname)
CODE:
checkerr( ub_ctx_resolvconf(ctx, fname) );
void
hosts(struct ub_ctx* ctx, const char* fname)
CODE:
checkerr( ub_ctx_hosts(ctx, fname) );
void
add_ta(struct ub_ctx* ctx, const char* ta)
CODE:
checkerr( ub_ctx_add_ta(ctx, ta) );
void
add_ta_file(struct ub_ctx* ctx, const char* fname)
CODE:
checkerr( ub_ctx_add_ta_file(ctx, fname) );
void
trusted_keys(struct ub_ctx* ctx, const char* fname)
CODE:
checkerr( ub_ctx_trustedkeys(ctx, fname) );
void
debug_out(struct ub_ctx* ctx, const char* out)
CODE:
checkerr( ub_ctx_debugout(ctx, (void*) out) );
void
debug_level(struct ub_ctx* ctx, int d)
CODE:
checkerr( ub_ctx_debuglevel(ctx, d) );
void
async(struct ub_ctx* ctx, int dothread)
CODE:
checkerr( ub_ctx_async(ctx, dothread) );
Net::DNS::Resolver::Unbound::Result
ub_resolve(struct ub_ctx* ctx, SV* name, int rrtype, int rrclass)
CODE:
checkerr( ub_resolve(ctx, (const char*) SvPVX(name), rrtype, rrclass, &RETVAL) );
OUTPUT:
RETVAL
Net::DNS::Resolver::Unbound::Handle
ub_resolve_async(struct ub_ctx* ctx, SV* name, int rrtype, int rrclass, int query_id=0)
CODE:
RETVAL = newAV();
checkerr( ub_resolve_async(ctx, (const char*) SvPVX(name), rrtype, rrclass,
(void*) RETVAL, async_callback, NULL) );
av_push(RETVAL, newSViv(query_id) );
OUTPUT:
RETVAL
void
ub_process(struct ub_ctx* ctx)
CODE:
checkerr( ub_process(ctx) );
void
ub_wait(struct ub_ctx* ctx)
CODE:
checkerr( ub_wait(ctx) );
#if !(UNBOUND_VERSION < 10900)
void
set_stub(struct ub_ctx* ctx, const char* zone, const char* addr, int isprime)
CODE:
checkerr( ub_ctx_set_stub(ctx, zone, addr, isprime) );
void
add_ta_autr(struct ub_ctx* ctx, const char* fname)
CODE:
checkerr( ub_ctx_add_ta_autr(ctx, fname) );
void
set_tls(struct ub_ctx* ctx, int tls)
CODE:
checkerr( ub_ctx_set_tls(ctx, tls) );
#endif
########################
## TEST PURPOSES ONLY ##
########################
Net::DNS::Resolver::Unbound::Result
mock_resolve(struct ub_ctx* ctx, SV* name, int secure, int bogus)
CODE:
checkerr( ub_resolve(ctx, (const char*) SvPVX(name), 1, 1, &RETVAL) );
if (bogus) RETVAL->answer_packet = NULL;
RETVAL->secure = secure;
RETVAL->bogus = bogus;
OUTPUT:
RETVAL
MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::libunbound
SV*
VERSION(void)
CODE:
RETVAL = newSVpv( ub_version(), 0 );
OUTPUT:
RETVAL
Net::DNS::Resolver::Unbound::Handle
emulate_callback(int query_id, int err, struct ub_result* result=NULL)
CODE:
RETVAL = newAV();
av_push(RETVAL, newSViv(query_id) );
async_callback( (void*) RETVAL, err, result );
OUTPUT:
RETVAL
Net::DNS::Resolver::Unbound::Handle
emulate_wait(int query_id)
CODE:
RETVAL = newAV();
av_push(RETVAL, newSViv(query_id) );
OUTPUT:
RETVAL
#ifdef croak_memory_wrap
void
croak_memory_wrap()
#endif
########################