The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/* -*- C -*-
     Validator.xs -- Perl 5 interface to the Dnssec-Tools validating resolver

     written by G. S. Marzot (marz@users.sourceforge.net)

     Copyright (c) 2006-2008 SPARTA, Inc.  All rights reserved.

     Copyright (c) 2006-2007 G. S. Marzot. All rights reserved.

     This program is free software; you can redistribute it and/or
     modify it under the same terms as Perl itself.
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <resolv.h>

#include <arpa/nameser.h>

#include <validator-config.h>
#include <validator/resolver.h>
#include <validator/validator.h>


#define PVAL_BUFSIZE	(16*1024)
#define ADDRINFO_TYPE		0
#define VAL_ADDRINFO_TYPE	1

typedef struct val_context ValContext;

#if 0
static void
print_addrinfo(int type, void *ainfo, char *obuf)
{
    struct sockaddr_in *s_inaddr = NULL;
    struct sockaddr_in6 *s_in6addr = NULL;
    struct addrinfo *a = (struct addrinfo *) ainfo;
    char            buf[INET6_ADDRSTRLEN];

    while (a != NULL) {
        printf("{\n");
        printf("\tFlags:     %d [", a->ai_flags);
        if (a->ai_flags & AI_PASSIVE)
            printf("AI_PASSIVE ");
        if (a->ai_flags & AI_CANONNAME)
            printf("AI_CANONNAME ");
        if (a->ai_flags & AI_NUMERICHOST)
            printf("AI_NUMERICHOST ");
        if (a->ai_flags & AI_V4MAPPED)
            printf("AI_V4MAPPED ");
        if (a->ai_flags & AI_ALL)
            printf("AI_ALL ");
        if (a->ai_flags & AI_ADDRCONFIG)
            printf("AI_ADDRCONFIG ");
        //              if (a->ai_flags & AI_NUMERICSERV) printf("AI_NUMERICSERV ");
        printf("]\n");
        printf("\tFamily:    %d [%s]\n", a->ai_family,
               (a->ai_family == AF_UNSPEC) ? "AF_UNSPEC" :
               (a->ai_family == AF_INET) ? "AF_INET" :
               (a->ai_family == AF_INET6) ? "AF_INET6" : "Unknown");
        printf("\tSockType:  %d [%s]\n", a->ai_socktype,
               (a->ai_socktype == SOCK_STREAM) ? "SOCK_STREAM" :
               (a->ai_socktype == SOCK_DGRAM) ? "SOCK_DGRAM" :
               (a->ai_socktype == SOCK_RAW) ? "SOCK_RAW" : "Unknown");
        printf("\tProtocol:  %d [%s]\n", a->ai_protocol,
               (a->ai_protocol == IPPROTO_IP) ? "IPPROTO_IP" :
               (a->ai_protocol == IPPROTO_TCP) ? "IPPROTO_TCP" :
               (a->ai_protocol == IPPROTO_UDP) ? "IPPROTO_UDP" :
               "Unknown");
        printf("\tAddrLen:   %d\n", a->ai_addrlen);

        if (a->ai_addr != NULL) {
            printf("\tAddrPtr:   %p\n", a->ai_addr);
            if (a->ai_family == AF_INET) {
                s_inaddr = (struct sockaddr_in *) (a->ai_addr);
                printf("\tAddr:      %s\n",
                       inet_ntop(AF_INET,
                                 &(s_inaddr->sin_addr),
                                 buf, INET6_ADDRSTRLEN));
            } else if (a->ai_family == AF_INET6) {
                s_in6addr = (struct sockaddr_in6 *) (a->ai_addr);
                printf("\tAddr:      %s\n",
                       inet_ntop(AF_INET6,
                                 &(s_in6addr->sin6_addr),
                                 buf, INET6_ADDRSTRLEN));
            } else
                printf
                    ("\tAddr:      Cannot parse address. Unknown protocol family\n");
        } else
            printf("\tAddr:      (null)\n");

        if (a->ai_canonname) {
            printf("\tCanonName: %s\n", a->ai_canonname);
	    strcpy(obuf, a->ai_canonname);
        } else {
            printf("\tCanonName: (null)\n");
	    strcpy(obuf, "");
	}

        if (type == VAL_ADDRINFO_TYPE) {
            printf("\tValStatus: %s\n",
                   p_val_error(((struct val_addrinfo *) a)->
                               ai_val_status));
        }
        printf("}\n");

        a = (struct addrinfo *) (a->ai_next);
    }
}

static int
not_here(s)
char *s;
{
    croak("%s not implemented on this architecture", s);
    return -1;
}
#endif


static struct addrinfo *ainfo_sv2c(SV *ainfo_ref, struct addrinfo *ainfo_ptr)
{
  if (ainfo_ptr) {
    bzero(ainfo_ptr, sizeof(struct addrinfo));
    if (ainfo_ref && SvROK(ainfo_ref)) {
      SV **flags_svp = hv_fetch((HV*)SvRV(ainfo_ref), "flags", 5, 1);
      SV **family_svp = hv_fetch((HV*)SvRV(ainfo_ref), "family", 6, 1);
      SV **socktype_svp = hv_fetch((HV*)SvRV(ainfo_ref), "socktype", 8, 1);
      SV **protocol_svp = hv_fetch((HV*)SvRV(ainfo_ref), "protocol", 8, 1);
      SV **addr_svp = hv_fetch((HV*)SvRV(ainfo_ref), "addr", 4, 1);
      SV **canonname_svp = hv_fetch((HV*)SvRV(ainfo_ref), "canonname", 9, 1);

      ainfo_ptr->ai_flags = (SvOK(*flags_svp) ? SvIV(*flags_svp) : 0);
      ainfo_ptr->ai_family = (SvOK(*family_svp) ? SvIV(*family_svp) : 0);
      ainfo_ptr->ai_socktype = (SvOK(*socktype_svp) ? SvIV(*socktype_svp) : 0);
      ainfo_ptr->ai_protocol = (SvOK(*protocol_svp) ? SvIV(*protocol_svp) : 0);
      if (SvOK(*addr_svp)) {
	ainfo_ptr->ai_addr = (struct sockaddr *) SvPV(*addr_svp,PL_na); // borrowed
	ainfo_ptr->ai_addrlen = SvLEN(*addr_svp);
      } else {
	ainfo_ptr->ai_addr = NULL;
	ainfo_ptr->ai_addrlen = 0;
      }
      ainfo_ptr->ai_canonname = (SvOK(*canonname_svp) ? 
				 SvPV(*canonname_svp,PL_na) : NULL); // borrowed

      // fprintf(stderr, "ainfo_ptr->ai_flags = %d\n", ainfo_ptr->ai_flags);
      // fprintf(stderr, "ainfo_ptr->ai_family = %d\n", ainfo_ptr->ai_family);
      // fprintf(stderr, "ainfo_ptr->ai_socktype = %d\n", ainfo_ptr->ai_socktype);
      // fprintf(stderr, "ainfo_ptr->ai_protocol = %d\n", ainfo_ptr->ai_protocol);
      // fprintf(stderr, "ainfo_ptr->ai_addrlen = %d\n", ainfo_ptr->ai_addrlen);
      // fprintf(stderr,"ainfo_ptr->ai_canonname=%s\n",ainfo_ptr->ai_canonname);
    } else {
      ainfo_ptr = NULL;
    }
  }
  return ainfo_ptr;
}

SV *rr_c2sv(char *name, int type, int class, long ttl, size_t len, u_char *data)
{
  dSP ;
  SV *rr = &PL_sv_undef;

  ENTER ;
  SAVETMPS;

  PUSHMARK(SP);
  XPUSHs(sv_2mortal(newSVpv("Net::DNS::RR", 0))) ;
  XPUSHs(sv_2mortal(newSVpv((char*)name, 0))) ;
  XPUSHs(sv_2mortal(newSVpv(p_sres_type(type), 0))) ;
  XPUSHs(sv_2mortal(newSVpv(p_class(class), 0))) ;
  XPUSHs(sv_2mortal(newSViv(ttl))) ;
  XPUSHs(sv_2mortal(newSViv(len))) ;
  XPUSHs(sv_2mortal(newRV(sv_2mortal(newSVpvn((char*)data, len))))) ;
  PUTBACK;

  call_method("new_from_data", G_SCALAR);

  SPAGAIN ;

  rr = newSVsv(POPs);

  PUTBACK ;
  FREETMPS ;
  LEAVE ;
  return rr;
}

SV *rrset_c2sv(struct val_rrset_rec *rrs_ptr)
{
  HV *rrset_hv;
  SV *rrset_hv_ref = &PL_sv_undef;
  AV *rrs_av;
  SV *rrs_av_ref;
  struct val_rr_rec *rr;

  if (rrs_ptr) {
    rrset_hv = newHV();
    rrset_hv_ref = newRV_noinc((SV*)rrset_hv);

    rrs_av = newAV();
    rrs_av_ref = newRV_noinc((SV*)rrs_av);

    for (rr = rrs_ptr->val_rrset_data; rr; rr = rr->rr_next) {
      av_push(rrs_av, 
	      rr_c2sv(rrs_ptr->val_rrset_name,
		      rrs_ptr->val_rrset_type,
		      rrs_ptr->val_rrset_class,
		      rrs_ptr->val_rrset_ttl,
		      rr->rr_rdata_length,
		      rr->rr_rdata)
	      );
    }

    (void)hv_store(rrset_hv, "data", strlen("data"), rrs_av_ref, 0);

    rrs_av = newAV();
    rrs_av_ref = newRV_noinc((SV*)rrs_av);

    for (rr = rrs_ptr->val_rrset_sig; rr; rr = rr->rr_next) {
      av_push(rrs_av, 
	      rr_c2sv(rrs_ptr->val_rrset_name,
		      ns_t_rrsig,
		      rrs_ptr->val_rrset_class,
		      rrs_ptr->val_rrset_ttl,
		      rr->rr_rdata_length,
		      rr->rr_rdata)
	      );
    }

    (void)hv_store(rrset_hv, "sigs", strlen("s"), rrs_av_ref, 0);
  }

  return rrset_hv_ref;
}

SV *ac_c2sv(struct val_authentication_chain *ac_ptr)
{
  HV *ac_hv;
  SV *ac_hv_ref = &PL_sv_undef;

  if (ac_ptr) {
    ac_hv = newHV();
    ac_hv_ref = newRV_noinc((SV*)ac_hv);

    (void)hv_store(ac_hv, "status", strlen("status"), 
	     newSViv(ac_ptr->val_ac_status), 0);

    (void)hv_store(ac_hv, "rrset", strlen("rrset"), 
	     rrset_c2sv(ac_ptr->val_ac_rrset), 0);

    (void)hv_store(ac_hv, "trust", strlen("trust"), 
	       ac_c2sv(ac_ptr->val_ac_trust), 0);
  }

  return ac_hv_ref;
}

SV *rc_c2sv(struct val_result_chain *rc_ptr)
{
  int i;
  AV *rc_av = newAV();
  SV *rc_av_ref = newRV_noinc((SV*)rc_av);
  HV *result_hv;
  SV *result_hv_ref;
  AV *proofs_av;
  SV *proofs_av_ref;

  while (rc_ptr) {
    result_hv = newHV();
    result_hv_ref = newRV_noinc((SV*)result_hv);

    (void)hv_store(result_hv, "status", strlen("status"), 
	     newSViv(rc_ptr->val_rc_status), 0);

    /* fprintf(stderr, "rc status == %d\n", rc_ptr->val_rc_status); XXX */
    
    if (rc_ptr->val_rc_answer != NULL) {
        (void)hv_store(result_hv, "answer", strlen("answer"), 
	        ac_c2sv(rc_ptr->val_rc_answer), 0);
    } else {
        (void)hv_store(result_hv, "rrset", strlen("rrset"),
            rrset_c2sv(rc_ptr->val_rc_rrset), 0);
    }

    proofs_av = newAV();
    proofs_av_ref = newRV_noinc((SV*)proofs_av);
  
    for(i=0; i < rc_ptr->val_rc_proof_count && 
	  rc_ptr->val_rc_proof_count < MAX_PROOFS; i++) {
      av_push(proofs_av, ac_c2sv(rc_ptr->val_rc_proofs[i]));
    }

    (void)hv_store(result_hv, "proofs", strlen("proofs"), proofs_av_ref, 0);

    av_push(rc_av, result_hv_ref);  

    rc_ptr = rc_ptr->val_rc_next;
  }

  return rc_av_ref;
}

SV *ainfo_c2sv(struct addrinfo *ainfo_ptr)
{
  AV *ainfo_av = newAV();
  SV *ainfo_av_ref = newRV_noinc((SV*)ainfo_av);

  for (;ainfo_ptr != NULL; ainfo_ptr = ainfo_ptr->ai_next) {
    HV *ainfo_hv = newHV();
    SV *ainfo_hv_ref = newRV_noinc((SV*)ainfo_hv);
         
    sv_bless(ainfo_hv_ref, gv_stashpv("Net::addrinfo",0));

    // fprintf(stderr,"::ainfo_ptr->ai_flags=%d\n", ainfo_ptr->ai_flags);
    // fprintf(stderr,"::ainfo_ptr->ai_family=%d\n", ainfo_ptr->ai_family);
    // fprintf(stderr,"::ainfo_ptr->ai_socktype=%d\n", ainfo_ptr->ai_socktype);
    // fprintf(stderr,"::ainfo_ptr->ai_protocol=%d\n", ainfo_ptr->ai_protocol);
    // fprintf(stderr,"::ainfo_ptr->ai_addrlen=%d\n", ainfo_ptr->ai_addrlen);
    //fprintf(stderr,"::ainfo_ptr->ai_canonname=%s\n",ainfo_ptr->ai_canonname);
    (void)hv_store(ainfo_hv, "flags", strlen("flags"), 
	     newSViv(ainfo_ptr->ai_flags), 0);
    (void)hv_store(ainfo_hv, "family", strlen("family"), 
	     newSViv(ainfo_ptr->ai_family), 0);
    (void)hv_store(ainfo_hv, "socktype", strlen("socktype"), 
	     newSViv(ainfo_ptr->ai_socktype), 0);
    (void)hv_store(ainfo_hv, "protocol", strlen("protocol"), 
	     newSViv(ainfo_ptr->ai_protocol), 0);
    (void)hv_store(ainfo_hv, "addr", strlen("addr"), 
	     newSVpv((char*)ainfo_ptr->ai_addr, 
		     ainfo_ptr->ai_addrlen), 0);
    (void)hv_store(ainfo_hv, "canonname", strlen("canonname"), 
	     (ainfo_ptr->ai_canonname ?
	      newSVpv(ainfo_ptr->ai_canonname, 
		      strlen(ainfo_ptr->ai_canonname)) :
	     &PL_sv_undef), 0);

    av_push(ainfo_av, ainfo_hv_ref);
  }  
  return ainfo_av_ref;
}


SV *hostent_c2sv(struct hostent *hent_ptr)
{
  AV *hent_av;
  SV *hent_av_ref;
  AV *hent_aliases_av;
  SV *hent_aliases_av_ref;
  AV *hent_addrs_av;
  SV *hent_addrs_av_ref;
  int i;

  if (hent_ptr == NULL) return &PL_sv_undef;
  
  hent_av = newAV();
  hent_av_ref = newRV_noinc((SV*)hent_av);
  

  sv_bless(hent_av_ref, gv_stashpv("Net::hostent",0));

  av_push(hent_av, newSVpv(hent_ptr->h_name,0));

  hent_aliases_av = newAV();
  hent_aliases_av_ref = newRV_noinc((SV*)hent_aliases_av);

  av_push(hent_av, hent_aliases_av_ref);

  if (hent_ptr->h_aliases) {
    for (i = 0; hent_ptr->h_aliases[i] != 0; i++) {
      av_push(hent_aliases_av, newSVpv(hent_ptr->h_aliases[i],0));
    }
  }

  av_push(hent_av, newSViv(hent_ptr->h_addrtype));

  av_push(hent_av, newSViv(hent_ptr->h_length));

  hent_addrs_av = newAV();
  hent_addrs_av_ref = newRV_noinc((SV*)hent_addrs_av);

  av_push(hent_av, hent_addrs_av_ref);

  for (i = 0; hent_ptr->h_addr_list[i] != 0; i++) {
    av_push(hent_addrs_av, newSVpvn(hent_ptr->h_addr_list[i],
				    hent_ptr->h_length));
  }

  return hent_av_ref;
}


#include "const-c.inc"

MODULE = Net::DNS::SEC::Validator	PACKAGE = Net::DNS::SEC::Validator	PREFIX = pval

INCLUDE: const-xs.inc

ValContext *
pval_create_context(policy)
	char * policy
	CODE:
	{
	ValContext *vc_ptr=NULL;

	int result = val_create_context(policy, &vc_ptr);

	RETVAL = (result ? NULL : vc_ptr);
	}
	OUTPUT:
	RETVAL

ValContext *
pval_create_context_with_conf(policy,dnsval_conf,resolv_conf,root_hints)
	char * policy = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : NULL);
        char *	dnsval_conf = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : NULL);
	char *	resolv_conf = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : NULL);
	char *	root_hints = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : NULL);
	CODE:
	{
	ValContext *vc_ptr=NULL;
	//	fprintf(stderr,"pval_create_context_with_conf:%s:%s:%s\n",dnsval_conf,resolv_conf,root_hints);

	//val_log_add_optarg("7:stderr", 1); /* XXX */

	int result = val_create_context_with_conf(policy, 
						  dnsval_conf,
						  resolv_conf,
						  root_hints,
						  &vc_ptr);
	//	fprintf(stderr,"pval_create_context_with_confresult=%d):%lx\n",result,vc_ptr);

	RETVAL = (result ? NULL : vc_ptr);
	}
	OUTPUT:
	RETVAL


SV *
pval_getaddrinfo(self,node=NULL,service=NULL,hints_ref=NULL)
	SV *	self
        char *	node = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : NULL);
	char *	service = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : NULL);
	SV *	hints_ref = (SvOK($arg) ? $arg : NULL);
	CODE:
	{
	ValContext *		ctx;
	SV **			ctx_ref;
	SV **			error_svp;
        SV **			error_str_svp;
        SV **			val_status_svp;
	SV **			val_status_str_svp;
	struct addrinfo		hints;
	struct addrinfo *	hints_ptr = NULL;
	struct addrinfo *	ainfo_ptr = NULL;
	val_status_t            val_status;
	int res;

	ctx_ref = hv_fetch((HV*)SvRV(self), "_ctx_ptr", 8, 1);
	ctx = (ValContext *)SvIV((SV*)SvRV(*ctx_ref));

	error_svp = hv_fetch((HV*)SvRV(self), "error", 5, 1);
        error_str_svp = hv_fetch((HV*)SvRV(self), "errorStr", 8, 1);
	val_status_svp = hv_fetch((HV*)SvRV(self), "valStatus", 9, 1);
        val_status_str_svp = hv_fetch((HV*)SvRV(self), "valStatusStr", 12, 1);
        
        sv_setiv(*error_svp, 0);
        sv_setpv(*error_str_svp, "");
        sv_setiv(*val_status_svp, 0);
        sv_setpv(*val_status_str_svp, "");

	hints_ptr = ainfo_sv2c(hints_ref, &hints);

	res = val_getaddrinfo(ctx, node, service, hints_ptr, 
			      &ainfo_ptr, &val_status);

	sv_setiv(*val_status_svp, val_status);
	sv_setpv(*val_status_str_svp, p_val_status(val_status));

	if (res == 0) {
	  RETVAL = ainfo_c2sv(ainfo_ptr);
	} else {
	  sv_setiv(*error_svp, res);
	  sv_setpv(*error_str_svp, gai_strerror(res));
	  RETVAL = &PL_sv_undef;
	}

	freeaddrinfo(ainfo_ptr);
	}
	OUTPUT:
	RETVAL


SV *
pval_gethostbyname(self,name,af=AF_INET)
	SV *	self
	char *	name = (SvOK($arg) ? (char *)SvPV($arg,PL_na) : "localhost");
	int	af = (SvOK($arg) ? SvIV($arg) : AF_INET);
	CODE:
	{
	ValContext     *ctx;
	SV **		ctx_ref;
	SV **		error_svp;
        SV **		error_str_svp;
        SV **		val_status_svp;
	SV **		val_status_str_svp;
	char	        buf[PVAL_BUFSIZE];
	struct hostent *result = NULL;
	struct hostent  hentry;
	int             herrno = 0;
	val_status_t    val_status;
	int		res;

	bzero(&hentry, sizeof(struct hostent));
	bzero(buf, PVAL_BUFSIZE);

	ctx_ref = hv_fetch((HV*)SvRV(self), "_ctx_ptr", 8, 1);
	ctx = (ValContext *)SvIV((SV*)SvRV(*ctx_ref));

	error_svp = hv_fetch((HV*)SvRV(self), "error", 5, 1);
        error_str_svp = hv_fetch((HV*)SvRV(self), "errorStr", 8, 1);
	val_status_svp = hv_fetch((HV*)SvRV(self), "valStatus", 9, 1);
        val_status_str_svp = hv_fetch((HV*)SvRV(self), "valStatusStr", 12, 1);
        
        sv_setiv(*error_svp, 0);
        sv_setpv(*error_str_svp, "");
        sv_setiv(*val_status_svp, 0);
        sv_setpv(*val_status_str_svp, "");

	res = val_gethostbyname2_r(ctx, name, af, &hentry, buf, PVAL_BUFSIZE,
				  &result, &herrno, &val_status);

	sv_setiv(*val_status_svp, val_status);
	sv_setpv(*val_status_str_svp, p_val_status(val_status));

	if (res) {
	   RETVAL = &PL_sv_undef;
	   sv_setiv(*error_svp, herrno);
	   sv_setpv(*error_str_svp, hstrerror(herrno));
	} else {
	   RETVAL = hostent_c2sv(result);
	}
	}
	OUTPUT:
	RETVAL

SV *
pval_res_query(self,dname,class,type)
	SV *	self
	char *	dname
	int	class
	int	type
	CODE:
	{
	ValContext     *ctx;
	SV **		error_svp;
        SV **		error_str_svp;
        SV **		val_status_svp;
	SV **		val_status_str_svp;
	SV **		ctx_ref;
	int		res;
	unsigned char	buf[PVAL_BUFSIZE];
	val_status_t	val_status;

	bzero(buf, PVAL_BUFSIZE);

	ctx_ref = hv_fetch((HV*)SvRV(self), "_ctx_ptr", 8, 1);
	ctx = (ValContext *)SvIV((SV*)SvRV(*ctx_ref));

	error_svp = hv_fetch((HV*)SvRV(self), "error", 5, 1);
        error_str_svp = hv_fetch((HV*)SvRV(self), "errorStr", 8, 1);
	val_status_svp = hv_fetch((HV*)SvRV(self), "valStatus", 9, 1);
        val_status_str_svp = hv_fetch((HV*)SvRV(self), "valStatusStr", 12, 1);
        
        sv_setiv(*error_svp, 0);
        sv_setpv(*error_str_svp, "");
        sv_setiv(*val_status_svp, 0);
        sv_setpv(*val_status_str_svp, "");
	
	//  fprintf(stderr,"before:%p:%s:%d:%d:%d:%d\n",ctx,dname,class,type,res,val_status);

	res = val_res_query(ctx, dname, class, type, buf, PVAL_BUFSIZE,
                            &val_status);

	//  fprintf(stderr,"after:%p:%s:%d:%d:%d:%d:%d:%s\n",ctx,dname,class,type,res,val_status,h_errno,hstrerror(h_errno));
        
	sv_setiv(*val_status_svp, val_status);
        sv_setpv(*val_status_str_svp, p_val_status(val_status));

	if (res == -1) {
	  RETVAL = &PL_sv_undef;
	  sv_setiv(*error_svp, h_errno); // this is not thread safe
          sv_setpv(*error_str_svp, hstrerror(h_errno));
	} else {
	  RETVAL =newSVpvn((char*)buf, res);
	}
	}
	OUTPUT:
	RETVAL


SV *
pval_resolve_and_check(self,domain,type,class,flags)
	SV * self
	char * domain
        int type
        int class
        int flags
	CODE:
	{
	ValContext *		ctx;
	SV **			ctx_ref;
	SV **			error_svp;
        SV **			error_str_svp;
        SV **			val_status_svp;
	SV **			val_status_str_svp;
	struct val_result_chain * val_rc_ptr = NULL;
	int res;
	//fprintf(stderr, "here we are at the start\n");

	ctx_ref = hv_fetch((HV*)SvRV(self), "_ctx_ptr", 8, 1);
	ctx = (ValContext *)SvIV((SV*)SvRV(*ctx_ref));

	error_svp = hv_fetch((HV*)SvRV(self), "error", 5, 1);
        error_str_svp = hv_fetch((HV*)SvRV(self), "errorStr", 8, 1);
	val_status_svp = hv_fetch((HV*)SvRV(self), "valStatus", 9, 1);
        val_status_str_svp = hv_fetch((HV*)SvRV(self), "valStatusStr", 12, 1);
        
        sv_setiv(*error_svp, 0);
        sv_setpv(*error_str_svp, "");
        sv_setiv(*val_status_svp, 0);
        sv_setpv(*val_status_str_svp, "");

	RETVAL = &PL_sv_undef;
	//fprintf(stderr, "here we are way before\n");


	  //fprintf(stderr, "here we are before\n");
	  res = val_resolve_and_check(ctx, domain, 
				      class, 
				      type, 
				      (u_int32_t) flags, 
				      &val_rc_ptr);
	  //fprintf(stderr, "here we are after\n");
	  val_log_authentication_chain(ctx, LOG_DEBUG,
				       domain, 
				       class, 
				       type, 
				       val_rc_ptr);
	  if (res == 0) {
	    RETVAL = rc_c2sv(val_rc_ptr);
	  } else {
	    sv_setiv(*error_svp, res);
	    sv_setpv(*error_str_svp, gai_strerror(res));
	  }

	  val_free_result_chain(val_rc_ptr);
	}
	OUTPUT:
	RETVAL

const char *
pval_ac_status(err)
	int err
	CODE:
	{
	  RETVAL = p_ac_status(err);
	}
	OUTPUT:
	RETVAL

const char *
pval_val_status(err)
	int err
	CODE:
	{
	  RETVAL = p_val_status(err);
	}
	OUTPUT:
	RETVAL

int
pval_istrusted(err)
	int err
	CODE:
	{
	  RETVAL = val_istrusted(err);
	}
	OUTPUT:
	RETVAL


int
pval_isvalidated(err)
	int err
	CODE:
	{
	  RETVAL = val_isvalidated(err);
	}
	OUTPUT:
	RETVAL


char *
pval_gai_strerror(err)
	int err
	CODE:
	{
	  RETVAL = (char*)gai_strerror(err);
	}
	OUTPUT:
	RETVAL

char *
pval_resolv_conf_get()
	CODE:
	{
	  RETVAL = resolv_conf_get();
	}
	OUTPUT:
	RETVAL

int
pval_resolv_conf_set(file)
	char *file
	CODE:
	{
	  RETVAL = resolv_conf_set(file);
	}
	OUTPUT:
	RETVAL

char *
pval_root_hints_get()
	CODE:
	{
	  RETVAL = root_hints_get();
	}
	OUTPUT:
	RETVAL

int
pval_root_hints_set(file)
	char *file
	CODE:
	{
	  RETVAL = root_hints_set(file);
	}
	OUTPUT:
	RETVAL

char *
pval_dnsval_conf_get()
	CODE:
	{
	  RETVAL = dnsval_conf_get();
	}
	OUTPUT:
	RETVAL

int
pval_dnsval_conf_set(file)
	char *file
	CODE:
	{
	  RETVAL = dnsval_conf_set(file);
	}
	OUTPUT:
	RETVAL

MODULE = Net::DNS::SEC::Validator PACKAGE = ValContextPtr PREFIX = vc_

void
vc_DESTROY(vc_ptr)
	ValContext *vc_ptr
	CODE:
	{
	  val_free_context( vc_ptr );
	}