Exemple #1
0
struct hostent *
netsnmp_gethostbyname(const char *name)
{
#if HAVE_GETHOSTBYNAME
#ifdef DNSSEC_LOCAL_VALIDATION
    val_status_t val_status;
#endif
    struct hostent *hp = NULL;

    if (NULL == name)
        return NULL;

    DEBUGMSGTL(("dns:gethostbyname", "looking up %s\n", name));

#ifdef DNSSEC_LOCAL_VALIDATION
    hp  = val_gethostbyname(netsnmp_validator_context(), name, &val_status);
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
                val_status, p_val_status(val_status),
                val_istrusted(val_status)));
    if (!val_istrusted(val_status)) {
        snmp_log(LOG_WARNING,
                 "The authenticity of DNS response is not trusted (%s)\n",
                 p_val_status(val_status));
        /** continue anyways if DNSSEC_WARN_ONLY is set */
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
            hp = NULL;
    }
    else if (val_does_not_exist(val_status) && hp)
        hp = NULL;
#else
    hp = gethostbyname(name);
#endif
    if (hp == NULL) {
        DEBUGMSGTL(("dns:gethostbyname",
                    "couldn't resolve %s\n", name));
    } else if (hp->h_addrtype != AF_INET) {
        DEBUGMSGTL(("dns:gethostbyname",
                    "warning: response for %s not AF_INET!\n", name));
    } else {
        DEBUGMSGTL(("dns:gethostbyname",
                    "%s resolved okay\n", name));
    }
    return hp;
#else
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
    return NULL;
#endif /* HAVE_GETHOSTBYNAME */
}
Exemple #2
0
struct hostent *
netsnmp_gethostbyaddr(const void *addr, socklen_t len, int type)
{
#if HAVE_GETHOSTBYADDR
    struct hostent *hp = NULL;
    struct sockaddr_in *saddr_in =
        NETSNMP_REMOVE_CONST(struct sockaddr_in *,addr);

    DEBUGMSGTL(("dns:gethostbyaddr", "resolving { AF_INET, %s:%hu }\n",
                inet_ntoa(saddr_in->sin_addr), ntohs(saddr_in->sin_port)));

#ifdef DNSSEC_LOCAL_VALIDATION
    val_status_t val_status;
    hp = val_gethostbyaddr(netsnmp_validator_context(),
                           (const void*)&saddr_in->sin_addr,
                           sizeof(struct in_addr), AF_INET, &val_status);
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
                val_status, p_val_status(val_status),
                val_istrusted(val_status)));
    if (!val_istrusted(val_status)) {
        snmp_log(LOG_WARNING,
                 "The authenticity of DNS response is not trusted (%s)\n",
                 p_val_status(val_status));
        /** continue anyways if DNSSEC_WARN_ONLY is set */
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
            hp = NULL;
    }
    else if (val_does_not_exist(val_status) && hp)
        hp = NULL;
#else
    hp = gethostbyaddr((const void*) &saddr_in->sin_addr,
                       sizeof(struct in_addr), AF_INET);
#endif
    if (hp == NULL) {
        DEBUGMSGTL(("dns:gethostbyaddr", "couldn't resolve addr\n"));
    } else if (hp->h_addrtype != AF_INET) {
        DEBUGMSGTL(("dns:gethostbyaddr",
                    "warning: response for addr not AF_INET!\n"));
    } else {
        DEBUGMSGTL(("dns:gethostbyaddr", "addr resolved okay\n"));
    }
    return hp;
#else
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyaddr not available"));
    return NULL;
#endif
}
Exemple #3
0
struct hostent *
dnssec_gethostbyname2(const char *name, int family) {
  	val_status_t          val_status;
  	struct hostent *      res;

  	if (dnssec_init_context())
    	return NULL;

  	LOG(L_INFO, " gethostbyname2(%s) called: wrapper\n", name);

  	res = val_gethostbyname2(libval_ctx, name, family,  &val_status);

  	if (val_istrusted(val_status) && !val_does_not_exist(val_status)) {
      	return res;
  	}
  	return NULL;
}
void
print_val_response(struct val_response *resp)
{
    if (resp == NULL) {
        printf("No answers returned. \n");
        return;
    }

    printf("DNSSEC status: %s [%d]\n",
           p_val_error(resp->vr_val_status), resp->vr_val_status);
    if (val_isvalidated(resp->vr_val_status)) {
        printf("Validated response:\n");
    } else if (val_istrusted(resp->vr_val_status)) {
        printf("Trusted but not validated response:\n");
    } else {
        printf("Untrusted response:\n");
    }
    print_response(resp->vr_response, resp->vr_length);
    printf("\n");
}
Exemple #5
0
int
dnssec_res_search(const char *dname, int class_h, int type_h,
	  unsigned char *answer, int anslen) {
  	val_status_t          val_status;
  	int ret;

  	if (dnssec_init_context())
    	return -1;

  	LOG(L_INFO, "res_query(%s,%d,%d) called: wrapper\n",
	  	dname, class_h, type_h);

  	ret = val_res_search(libval_ctx, dname, class_h, type_h, answer, anslen,
			&val_status);

  	if (val_istrusted(val_status) && !val_does_not_exist(val_status)) {
		return ret;
  	} else {
		LOG(L_INFO, "invalid domain %s reason %s\n", dname, p_val_status(val_status));
	}

 	return -1;
}
Exemple #6
0
int
main(int argc, char *argv[])
{
    char           *node = NULL;
    val_log_t      *logp;
    u_int16_t      type_h = ns_t_a;
    int success = 0;
    int ret;
    val_status_t status;
    u_char buf[1024];

    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, "ho:t:V",
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, "ho:t:V", prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, "ho:t:V");
#endif

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage(argv[0]);
            return -1;
        case 'o':
            logp = val_log_add_optarg(optarg, 1);
            if (NULL == logp) { /* err msg already logged */
                usage(argv[0]);
                return -1;
            }
            break;

        case 't':
            type_h = res_nametotype(optarg, &success);
            if (!success) {
                fprintf(stderr, "Unrecognized type %s\n", optarg);
                usage (argv[0]);
                return -1;
            }
            break;
        case 'V':
            version();
            return 0;

        default:
            fprintf(stderr, "Invalid option %s\n", argv[optind - 1]);
            usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc) {
        node = argv[optind++];
    } else {
        fprintf(stderr, "Error: node name not specified\n");
        usage(argv[0]);
        return -1;
    }

    //ret = val_res_query(NULL, "mail.marzot.net", 1, 15, buf, 1024, &status);
    //ret = val_res_query(NULL, "nosig-A.test.dnssec-tools.org.", 1, 1, buf, 1024, &status);
    //ret = val_res_query(NULL, "good-A.test.dnssec-tools.org", 1, 28, buf, 1024, &status);
    //ret = val_res_query(NULL, "vb.futz.org", 1, 1, buf, 1024, &status);
    
    ret = val_res_query(NULL, node, ns_c_in, type_h, buf, 1024, &status);
    printf("Return value %d\n", ret);
    printf("herrno value %d\n", h_errno);
    printf("Validation Status %s\n", p_val_status(status));
    if (ret > 0) {
        print_response(buf, ret);
    }

    if (val_isvalidated(status))
        return 2;
    else if (val_istrusted(status))
        return 1;
    return 0;
}
Exemple #7
0
int
netsnmp_getaddrinfo(const char *name, const char *service,
                    const struct addrinfo *hints, struct addrinfo **res)
{
#if HAVE_GETADDRINFO
    struct addrinfo *addrs = NULL;
    struct addrinfo hint;
    int             err;
#ifdef DNSSEC_LOCAL_VALIDATION
    val_status_t    val_status;
#endif

    DEBUGMSGTL(("dns:getaddrinfo", "looking up "));
    if (name)
        DEBUGMSG(("dns:getaddrinfo", "\"%s\"", name));
    else
        DEBUGMSG(("dns:getaddrinfo", "<NULL>"));

    if (service)
	DEBUGMSG(("dns:getaddrinfo", ":\"%s\"", service));

    if (hints)
	DEBUGMSG(("dns:getaddrinfo", " with hint ({ ... })"));
    else
	DEBUGMSG(("dns:getaddrinfo", " with no hint"));

    DEBUGMSG(("dns:getaddrinfo", "\n"));

    if (NULL == hints) {
        memset(&hint, 0, sizeof hint);
        hint.ai_flags = 0;
        hint.ai_family = PF_INET;
        hint.ai_socktype = SOCK_DGRAM;
        hint.ai_protocol = 0;
        hints = &hint;
    } else {
        memcpy(&hint, hints, sizeof hint);
    }

#ifndef DNSSEC_LOCAL_VALIDATION
    err = getaddrinfo(name, NULL, &hint, &addrs);
#else /* DNSSEC_LOCAL_VALIDATION */
    err = val_getaddrinfo(netsnmp_validator_context(), name, NULL, &hint,
                          &addrs, &val_status);
    DEBUGMSGTL(("dns:sec:val", "err %d, val_status %d / %s; trusted: %d\n",
                err, val_status, p_val_status(val_status),
                val_istrusted(val_status)));
    if (! val_istrusted(val_status)) {
        int rc;
        if ((err != 0) && VAL_GETADDRINFO_HAS_STATUS(err)) {
            snmp_log(LOG_WARNING,
                     "WARNING: UNTRUSTED error in DNS resolution for %s!\n",
                     name);
            rc = EAI_FAIL;
        } else {
            snmp_log(LOG_WARNING,
                     "The authenticity of DNS response is not trusted (%s)\n",
                     p_val_status(val_status));
            rc = EAI_NONAME;
        }
        /** continue anyways if DNSSEC_WARN_ONLY is set */
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
            return rc;
    }


#endif /* DNSSEC_LOCAL_VALIDATION */
    *res = addrs;
    if ((0 == err) && addrs && addrs->ai_addr) {
        DEBUGMSGTL(("dns:getaddrinfo", "answer { AF_INET, %s:%hu }\n",
                    inet_ntoa(((struct sockaddr_in*)addrs->ai_addr)->sin_addr),
                    ntohs(((struct sockaddr_in*)addrs->ai_addr)->sin_port)));
    }
    return err;
#else
    NETSNMP_LOGONCE((LOG_ERR, "getaddrinfo not available"));
    return EAI_FAIL;
#endif /* getaddrinfo */
}
Exemple #8
0
int
val_get_answer_from_result(val_context_t *context, const char *name, int class_h,
                           int type_h, struct val_result_chain **results,
                           struct val_answer_chain **answers,
                           unsigned int vgafr_flags)
{
    struct val_result_chain *res = NULL;
    struct val_answer_chain *ans = NULL;
    struct val_answer_chain *last_ans = NULL;
    int retval = VAL_NO_ERROR;
    const char *n = NULL;
    int len;
    char *name_alias = NULL;
    int trusted, validated;
    
    if (name == NULL || answers == NULL || results == NULL || answers == NULL) {
        return VAL_BAD_ARGUMENT;
    }

    *answers = NULL;
    last_ans = NULL;
   
    if (*results == NULL) {
        /* Construct a single val_answer_chain with the untrusted status */
        ans = (struct val_answer_chain *) MALLOC (sizeof(struct val_answer_chain));
        if (ans == NULL) {
            return VAL_OUT_OF_MEMORY;
        }
        ans->val_ans_name = strdup(name); 
        if (ans->val_ans_name == NULL) {
            FREE(ans);
            ans = NULL;
            return VAL_OUT_OF_MEMORY;
        } 
        ans->val_ans_status = VAL_UNTRUSTED_ANSWER;
        ans->val_ans_class = class_h;
        ans->val_ans_type = type_h;
        ans->val_ans = NULL;
        ans->val_ans_next = NULL;
        *answers = ans;
        return VAL_NO_ERROR;
    }

    trusted = 1;
    validated = 1;

    /* Construct the val_answer_chain linked list for returned results */
    for (res = *results; res; res=res->val_rc_next) {

        if (!validated || !val_isvalidated(res->val_rc_status))
            validated = 0;
        if (!trusted || !val_istrusted(res->val_rc_status))
            trusted = 0;

        /* 
         * we don't need cnames/dnames in the answer,
         * we only need the name that is being pointed to.
         */
        if (res->val_rc_alias) {
            name_alias = res->val_rc_alias;
            continue;
        }

        ans = (struct val_answer_chain *) MALLOC (sizeof(struct val_answer_chain));
        if (ans == NULL) {
            retval = VAL_OUT_OF_MEMORY;
            goto err;
        }

        /* add to end of chain */
        ans->val_ans_next = NULL;
        if (last_ans) {
            last_ans->val_ans_next = ans;
        } else {
            *answers = ans;
        }
        last_ans = ans;
        
        if (res->val_rc_rrset) {
            /* use values from the rrset */
            n = res->val_rc_rrset->val_rrset_name;
            ans->val_ans_class = res->val_rc_rrset->val_rrset_class; 
            ans->val_ans_type = res->val_rc_rrset->val_rrset_type; 
            ans->val_ans = (struct rr_rec *) (res->val_rc_rrset->val_rrset_data);
            res->val_rc_rrset->val_rrset_data = NULL;
        } else {
            if (name_alias) {
                n = name_alias; /* the last alias target */ 
            } else {
                n = name; /* the name being queried for */
            }
            ans->val_ans_class = class_h; 
            ans->val_ans_type = type_h; 
            ans->val_ans = NULL;
        } 

        /* Convert the name to a string */
        ans->val_ans_name = NULL;    
        len = strlen(n) + 1;
        ans->val_ans_name = (char *) MALLOC (len * sizeof (char));
        if (ans->val_ans_name == NULL) {
            retval = VAL_OUT_OF_MEMORY;
            goto err;
        }
        strcpy(ans->val_ans_name, n);

        /* 
         * if the current answer was validated or 
         * if the current answer was trusted use the exact status
         */
        if (validated || 
            (trusted && !val_isvalidated(res->val_rc_status))) {
           ans->val_ans_status = res->val_rc_status;
        } else if (trusted) {
        /*
         * If the combined answer was trusted but the current answer
         * was validated (implied), use the lower bounds of trust 
         */
            if (val_does_not_exist(res->val_rc_status)) {
                if (res->val_rc_status == VAL_NONEXISTENT_NAME)
                   ans->val_ans_status = VAL_NONEXISTENT_NAME_NOCHAIN; 
                else 
                   ans->val_ans_status = VAL_NONEXISTENT_TYPE_NOCHAIN; 
            } else {
                ans->val_ans_status = VAL_TRUSTED_ANSWER;
            }
        } else {
            ans->val_ans_status = VAL_UNTRUSTED_ANSWER;        
        }

        /* 
         * reset the below values so that we are able to handle different 
         * status values for different answers
         */
        validated = 1;
        trusted = 1;
    } 

    val_free_result_chain(*results);
    *results = NULL;
    return VAL_NO_ERROR;

err:
    val_free_answer_chain(*answers);
    *answers = NULL;
    val_free_result_chain(*results);
    *results = NULL;
    return retval;
} 
Exemple #9
0
int
main(int argc, char *argv[])
{
    const char     *allowed_args =
#ifndef VAL_NO_ASYNC
        "a"
#endif
        "hco:s:Vv:r:i:";
    char           *node = NULL;
    char           *service = NULL;
    struct addrinfo hints;
    struct addrinfo *val_ainfo = NULL;
    int             retval;
    int             getcanonname = 0;
    int             portspecified = 0;
    int             async = 0;
    val_log_t      *logp;
    val_status_t val_status;

    // Parse the command line
    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, allowed_args,
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, allowed_args, prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, allowed_args);
#endif

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage(argv[0]);
            return -1;
        case 'o':
            logp = val_log_add_optarg(optarg, 1);
            if (NULL == logp) { /* err msg already logged */
                usage(argv[0]);
                return -1;
            }
            break;

        case 's':
            portspecified = 1;
            service = optarg;
            break;
        case 'c':
            getcanonname = 1;
            break;

#ifndef VAL_NO_ASYNC
        case 'a':
            async = 1;
            break;
#endif

        case 'v':
            dnsval_conf_set(optarg);
            break;

        case 'i':
            root_hints_set(optarg);
            break;

        case 'r':
            resolv_conf_set(optarg);
            break;

        case 'V':
            version();
            return 0;
        default:
            fprintf(stderr, "Invalid option %s\n", argv[optind - 1]);
            usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc) {
        node = argv[optind++];
    } else {
        fprintf(stderr, "Error: node name not specified\n");
        usage(argv[0]);
        return -1;
    }

    memset(&hints, 0, sizeof(struct addrinfo));
    if (getcanonname) {
        hints.ai_flags |= AI_CANONNAME;
    }

    if (!async) {
        retval = val_getaddrinfo(NULL, node, service, &hints, &val_ainfo, &val_status);
    }
    else {
#ifdef VAL_NO_ASYNC
        fprintf(stderr, "async support not available\n");
#else
        struct getaddr_s cb_data = { &retval, &val_ainfo, &val_status, 0 };
        val_gai_callback my_cb = &_callback;
        val_gai_status *status = NULL;
        struct timeval tv;
        val_context_t *context;
        /*
         * create a new context
         */
        val_create_context("getaddr", &context);
        if (context == NULL)
            return -1;
        /*
         * submit request
         */
        retval = val_getaddrinfo_submit(context, node, service, &hints,
                                        my_cb, &cb_data, 0, &status);
        /*
         * wait for it to complete
         */
        while(0 == cb_data.done) {
            tv.tv_sec = 4;
            tv.tv_usec = 567;
            val_async_check_wait(context, NULL, NULL, &tv, 0);
        }
        val_free_context(context);
#endif
    }

    printf("Return code = %d\n", retval);
    printf("Validator status code = %d (%s)\n", val_status,
           p_val_status(val_status));

    if (retval != 0) {
#ifdef HAVE_GAI_STRERROR
        printf("Error in val_getaddrinfo(): %s\n", gai_strerror(retval));
#else
        printf("Error in val_getaddrinfo(): %d\n", retval);
#endif
        return -1;
    }

    print_addrinfo(VAL_ADDRINFO_TYPE, val_ainfo);

    /*
     * cleanup 
     */
    val_freeaddrinfo(val_ainfo);
    if (val_isvalidated(val_status)) {
        return 2; 
    } 
    if (val_istrusted(val_status)) {
        return 1; 
    } 

    return 0;
}
/*
 * Returns:
 *   0  expected results
 *   1  untrusted / unexpected result
 *  -1  bad parameter 
 */
int
check_results(val_context_t * context, const char *desc, char * name,
              const u_int16_t class_h, const u_int16_t type_h,
              const int *result_ar, struct val_result_chain *results,
              int trusted_only, struct timeval *start)
{
    int             result_array[MAX_TEST_RESULTS];
    int             extra_res[MAX_TEST_RESULTS];
    int             err = 0, i, extra = 0, missing = 0, untrusted = 0;
    struct timeval  now, duration;
    struct val_result_chain *res;

#define CR_EXPECTED  -1
#define CR_UNTRUSTED -2
#define CR_MISSING   -3

    if (NULL == result_ar || NULL == start)
        return -1;

    /** calculate query duration */
    gettimeofday(&now, NULL);
    timersub(&now, start, &duration);

    /*
     * make a local copy of result array 
     */
    for (i = 0; result_ar[i] != 0; ++i)
        result_array[i] = result_ar[i];

    result_array[i] = 0;

    /* 
     * if we don't have any answers, the result type is VAL_UNTRUSTED_ANSWER */
    if (results == NULL) {
        for (i = 0; result_array[i] != 0; ++i) {
            if (VAL_UNTRUSTED_ANSWER != result_array[i])
                continue;
            /* Mark this as done */
            if (trusted_only) {
                ++untrusted;
                result_array[i] = CR_UNTRUSTED;
            }
            else
                result_array[i] = CR_EXPECTED;
        }
    }

    /** check for any untrusted results, if reqested */
    if (trusted_only) {
        for (res = results; res; res = res->val_rc_next) {
            if (!val_istrusted(res->val_rc_status))
                ++untrusted;
        }
    }
    /** compare results we do have against what we expect */
    fprintf(stderr, "%s: \t", desc);
    if (result_array[0]) {
        for (res = results; res; res = res->val_rc_next) {
            for (i = 0; result_array[i] != 0; i++) {
                if (res->val_rc_status != result_array[i])
                    continue;
                /* Mark this as done */
                if (trusted_only && !val_istrusted(res->val_rc_status))
                    result_array[i] = CR_UNTRUSTED;
                else
                    result_array[i] = CR_EXPECTED;
                break;
            }
            if (result_array[i] == 0) /* didn't expect this result */
                extra_res[extra++] = res->val_rc_status;
        }
    }

    /*
     * Check if any values were missing
     */
    for (i = 0; result_array[i] != 0; ++i)
        if (result_array[i] > 0)
            ++missing;

    /*
     * print results
     */
    err = untrusted + extra + missing;
    if (!err) {
        fprintf(stderr, "OK\n");
    } else {
        fprintf(stderr, "FAILED: received results did not match expectations\n");

        /** print extra */
        if (extra) {
            fprintf(stderr, "   Some results were not expected\n");
            for (i = 0; i < extra; ++i)
                fprintf(stderr,         "     UNEXPECTED %s(%d)\n",
                        p_val_error(extra_res[i]), extra_res[i]);
        }

        /** print missing/untrusted */
        if (trusted_only && untrusted)
            fprintf(stderr, "   Some results were not validated successfully\n");
        if (missing)
            fprintf(stderr, "   Some results were not received\n");
        if (missing || (trusted_only && untrusted))
            for (i = 0; result_array[i] != 0; i++)
                if (result_array[i] > 0)
                    fprintf(stderr, "     MISSING    %s(%d)\n",
                            p_val_error(result_array[i]), result_array[i]);
                else if (result_array[i] == CR_UNTRUSTED)
                    fprintf(stderr, "     UNTRUSTED  %s(%d)\n",
                            p_val_error(result_ar[i]), result_ar[i]);

    }

    fprintf(stderr, "%s: ****END**** %ld.%ld sec\n", desc,
            (long) duration.tv_sec, (long) duration.tv_usec);

    return err;
}
Exemple #11
0
/*
 * A thread-safe, re-entrant version of val_gethostbyaddr 
 */
int
val_gethostbyaddr_r(val_context_t * context,
                    const char *addr,
                    int len,
                    int type,
                    struct hostent *ret,
                    char *buf,
                    int buflen,
                    struct hostent **result,
                    int *h_errnop, val_status_t * val_status)
{

    char            domain_string[NS_MAXDNAME];
    int             ret_status = 0, bufused = 0;
    struct val_answer_chain *val_res = NULL;
    struct val_answer_chain *res;
    int retval;
    val_context_t *ctx = NULL;
    
    /*
     * check misc parameters exist 
     */
    if (!addr || !ret || !buf || (buflen <= 0) ||
        !result || !h_errnop || !val_status) {
        if (h_errnop)
            *h_errnop = NO_RECOVERY;
        return (NO_RECOVERY);
    }

    /*
     * default the input parameters 
     */
    *result = NULL;
    ret->h_name = NULL;
    ret->h_aliases = NULL;
    ret->h_addr_list = NULL;
    *h_errnop = 0;
    *val_status = VAL_UNTRUSTED_ANSWER;

    /*
     * get the address values, only support IPv4 and IPv6 
     */
    if (AF_INET == type && len >= sizeof(struct in_addr)) {
        ret->h_addrtype = type;
        ret->h_length = sizeof(struct in_addr);
    } 
#ifdef VAL_IPV6
    else if (AF_INET6 == type && len >= sizeof(struct in6_addr)) {
        ret->h_addrtype = type;
        ret->h_length = sizeof(struct in6_addr);
    } 
#endif
    else {
        *h_errnop = NO_RECOVERY;
        return (NO_RECOVERY);
    }

    memset(domain_string, 0, sizeof(domain_string));

    if (0 !=
        (ret_status = address_to_reverse_domain(addr, type,
                                                domain_string, sizeof(domain_string)))
        ) {
        *h_errnop = ret_status;
        return ret_status;
    }

    /*
     * if there is memory, add the address to hostent's address list 
     */
    if ((buflen > bufused) && 
        ((buflen - bufused) >= (ret->h_length + (sizeof(char *) * 2)))) {
        ret->h_addr_list = (char **) (buf + bufused);
        bufused = bufused + (sizeof(char *) * 2);
        ret->h_addr_list[0] = buf + bufused;
        ret->h_addr_list[1] = NULL;
        bufused = bufused + ret->h_length;
        memcpy(ret->h_addr_list[0], addr, ret->h_length);
    } else {                    /* no memory, fail */
        *h_errnop = NO_RECOVERY;
        return (NO_RECOVERY);
    }

    ctx = val_create_or_refresh_context(context); /* does CTX_LOCK_POL_SH */
    if (ctx == NULL) {
        *h_errnop = NO_RECOVERY;
        return (NO_RECOVERY);
    }

    if (VAL_NO_ERROR != (retval = val_get_rrset(ctx,   /* val_context_t *  */
                                                domain_string, /* domain name */ 
                                                ns_c_in,   /* const u_int16_t q_class */
                                                ns_t_ptr,  /* const u_int16_t type */
                                                0,
                                                &val_res))) { /* struct val_answer_chain **results */
        val_log(ctx, LOG_ERR, 
                "val_gethostbyaddr_r(): val_get_rrset failed - %s", p_val_err(retval));
        CTX_UNLOCK_POL(ctx);
        *h_errnop = NO_RECOVERY;
        return NO_RECOVERY;
    }

    CTX_UNLOCK_POL(ctx);

    if (!val_res) {
        *h_errnop = NO_RECOVERY;
        return NO_RECOVERY;
    }

    for (res = val_res; res; res=res->val_ans_next) {

        struct rr_rec  *rr = res->val_ans;
        if (rr) {
            struct rr_rec  *rr_it = NULL;
            int             count = 0;
            int aliases_sz = 0;
            /*
             * if the buffer has enough room add the first host address 
             */
            if (rr->rr_length < (buflen - bufused - 1)) {
                /*
                 * setup hostent 
                 */
                ret->h_name = buf + bufused;
                ns_name_ntop(rr->rr_data, ret->h_name,
                             (buflen - bufused));
                bufused = bufused + strlen(ret->h_name) + 1;

                rr_it = rr->rr_next;
                /*
                 * are there other hostnames? 
                 */
                if (rr_it) {
                    /*
                     * calculate the amount of memory we need for aliases. 
                     */
                    do {
                        count++;
                        aliases_sz = aliases_sz + rr_it->rr_length + 1;
                    } while (NULL != (rr_it = rr_it->rr_next));

                    /*
                     * check that we have the space in the buffer 
                     */
                    if (buflen >=
                        (bufused + (sizeof(char *) * (count + 1)) +
                        aliases_sz)) {
                        /*
                         * assign the string pointer array 
                         */
                        ret->h_aliases = (char **) (buf + bufused);
                        bufused = bufused + (sizeof(char *) * (count + 1));

                        /*
                         * assign the strings 
                         */
                        rr_it = rr->rr_next;
                        count = 0;
                        do {
                            ret->h_aliases[count] = buf + bufused;
                            ns_name_ntop(rr_it->rr_data,
                                         ret->h_aliases[count],
                                        (buflen - bufused));
                            bufused =
                                bufused + strlen(ret->h_aliases[count]) + 1;
                            count++;
                        } while (NULL != (rr_it = rr_it->rr_next));
                        /*
                         * mark end of array 
                         */
                        ret->h_aliases[count] = NULL;
                    }
                    /*
                     * else we didn't have enough memory for the aliases.  They
                     * will be ignored with only one hostname returned 
                     */
                }                   /* else there are no other hostnames/aliases */

            } else {                /* else there is not enough room for even one host name, fail */
                ret->h_name = NULL;
                *h_errnop = NO_RECOVERY;
                return NO_RECOVERY;
            }
            break;

        } else if  (val_does_not_exist(res->val_ans_status)) {
                    
            if ((res->val_ans_status == VAL_NONEXISTENT_TYPE) ||
                (res->val_ans_status == VAL_NONEXISTENT_TYPE_NOCHAIN)) {
                    *h_errnop = NO_DATA;
            } else if ((res->val_ans_status == VAL_NONEXISTENT_NAME) ||
                       (res->val_ans_status == VAL_NONEXISTENT_NAME_NOCHAIN)) {
                    *h_errnop = HOST_NOT_FOUND;
            }

            *result = ret;
            return *h_errnop;
        }
    }

    if (!res) { /* no rrset, but a succesful return from the query?, fail */
        ret->h_name = NULL;
        *h_errnop = NO_RECOVERY;
        return NO_RECOVERY;
    }

    /* set the value of merged trusted and validated status values */
    if (val_isvalidated(res->val_ans_status))
        *val_status = VAL_VALIDATED_ANSWER; 
    else if (val_istrusted(res->val_ans_status))
        *val_status = VAL_TRUSTED_ANSWER; 

    /*
     * no error, set result 
     */
    *result = ret;
    return *h_errnop;

}                               /* val_getthostbyaddr_r */
Exemple #12
0
/*
 * Function: get_hostent_from_response
 *
 * Purpose: Converts the linked list of val_result_chain structures obtained
 *          as a result from the validator into a hostent structure.
 *
 * Parameters:
 *              ctx -- The validation context.
 *               af -- The address family: AF_INET or AF_INET6.
 *              ret -- Pointer to a hostent structure to return the result.
 *                     This parameter must not be NULL.
 *          results -- Pointer to a linked list of val_result_chain structures.
 *         h_errnop -- Pointer to an integer variable to store the h_errno value.
 *              buf -- A buffer to store auxiliary data.  This parameter must not be NULL.
 *           buflen -- Length of the buffer 'buf'.
 *           offset -- Pointer to an integer variable that contains the offset in the buffer
 *                     'buf', where data can be written.  When this function writes any data
 *                     in the auxiliary data, the offset is incremented accordingly.  This
 *                     parameter must not be NULL.
 *
 * Return value: Returns NULL on failure and 'ret' on success.
 *
 * See also: get_hostent_from_etc_hosts()
 */
static struct hostent *
get_hostent_from_response(val_context_t * ctx, int af, struct hostent *ret,
                          struct val_result_chain *results, int *h_errnop,
                          char *buf, int buflen, int *offset, 
                          val_status_t * val_status)
{
    int             alias_count = 0;
    int             alias_index = 0;
    int             addr_count = 0;
    int             addr_index = 0;
    int             orig_offset = 0;
    struct val_result_chain *res;
    int validated = 1;
    int trusted = 1;
    struct val_rrset_rec *rrset;
    char *alias_target = NULL;

    /*
     * Check parameter sanity 
     */
    if (!results || !h_errnop || !buf || !offset || !ret || !val_status) {
        return NULL;
    }

    *val_status = VAL_DONT_KNOW;
    *h_errnop = 0;
    
    orig_offset = *offset;
    memset(ret, 0, sizeof(struct hostent));

    /*
     * Count the number of aliases and addresses in the result 
     */
    for (res = results; res != NULL; res = res->val_rc_next) {
        rrset = res->val_rc_rrset;

        if (res->val_rc_alias && rrset) {
            val_log(ctx, LOG_DEBUG,
                    "get_hostent_from_response(): type of record = CNAME");
            alias_count++;
            continue;
        }

        // Get a count of aliases and addresses
        if (rrset) {
            struct val_rr_rec  *rr = rrset->val_rrset_data;

            while (rr) {

                if ((af == AF_INET)
                           && (rrset->val_rrset_type == ns_t_a)) {
                    val_log(ctx, LOG_DEBUG,
                            "get_hostent_from_response(): type of record = A");
                    addr_count++;
                } else if ((af == AF_INET6)
                           && (rrset->val_rrset_type == ns_t_aaaa)) {
                    val_log(ctx, LOG_DEBUG,
                            "get_hostent_from_response(): type of record = AAAA");
                    addr_count++;
                }

                rr = rr->rr_next;
            }
        }
    }

    ret->h_aliases =
        (char **) bufalloc(buf, buflen, offset,
                           (alias_count + 1) * sizeof(char *));
    if (ret->h_aliases == NULL) {
        goto err;
    }
    ret->h_aliases[alias_count] = NULL;

    ret->h_addr_list =
        (char **) bufalloc(buf, buflen, offset,
                           (addr_count + 1) * sizeof(char *));
    if (ret->h_addr_list == NULL) {
        goto err;
    }
    ret->h_addr_list[addr_count] = NULL;

    alias_index = alias_count - 1;

    if (results == NULL) {
        *val_status = VAL_UNTRUSTED_ANSWER;
        *h_errnop = HOST_NOT_FOUND; 
        goto err;
    } 
   
    /*
     * Process the result 
     */
    for (res = results; res != NULL; res = res->val_rc_next) {

        rrset = res->val_rc_rrset;

        if (!(validated && val_isvalidated(res->val_rc_status))) 
            validated = 0;
        if (!(trusted && val_istrusted(res->val_rc_status)))
            trusted = 0;

        /* save the non-existence state */
        if (val_does_not_exist(res->val_rc_status)) {
            *val_status = res->val_rc_status;
            if (res->val_rc_status == VAL_NONEXISTENT_NAME ||
                res->val_rc_status == VAL_NONEXISTENT_NAME_NOCHAIN) {

                *h_errnop = HOST_NOT_FOUND;
            } else { 
                *h_errnop = NO_DATA;
            }
            break;
        }

        if (res->val_rc_alias && rrset) {
            // Handle CNAME RRs
            if (alias_index >= 0) {
                ret->h_aliases[alias_index] =
                    (char *) bufalloc(buf, buflen, offset,
                                      (strlen(rrset->val_rrset_name) + 1) * sizeof(char));
                if (ret->h_aliases[alias_index] == NULL) {
                    goto err;
                }
                memcpy(ret->h_aliases[alias_index], rrset->val_rrset_name,
                       strlen(rrset->val_rrset_name) + 1);
                alias_index--;
            }

            /* save the alias target for later use */
            alias_target = res->val_rc_alias; 
        } else if (rrset) {

            if (((af == AF_INET)
                      && (rrset->val_rrset_type == ns_t_a))
                || ((af == AF_INET6)
                      && (rrset->val_rrset_type == ns_t_aaaa))) {

                struct val_rr_rec  *rr = rrset->val_rrset_data;

                if (!ret->h_name) {
                    ret->h_name =
                            (char *) bufalloc(buf, buflen, offset,
                                              (strlen(rrset->val_rrset_name) +
                                               1) * sizeof(char));
                    if (ret->h_name == NULL) {
                        goto err;
                    }
                    memcpy(ret->h_name, rrset->val_rrset_name, strlen(rrset->val_rrset_name) + 1);
                }

                while (rr) {
                    // Handle A and AAAA RRs
                    ret->h_length = rr->rr_rdata_length;
                    ret->h_addrtype = af;
                    ret->h_addr_list[addr_index] =
                            (char *) bufalloc(buf, buflen, offset,
                                              rr->rr_rdata_length *
                                              sizeof(char));
                    if (ret->h_addr_list[addr_index] == NULL) {
                        goto err;
                    }

                    memcpy(ret->h_addr_list[addr_index], rr->rr_rdata,
                               rr->rr_rdata_length);
                    addr_index++;

                    rr = rr->rr_next;
                }
            }
        }
    }
    /* pick up official name from the alias target */
    if (!ret->h_name && alias_target) {
        ret->h_name = (char *) bufalloc(buf, buflen, offset,
                          (strlen(alias_target) + 1) * sizeof(char));
        if (ret->h_name == NULL) {
            goto err;
        }
        memcpy(ret->h_name, alias_target, strlen(alias_target) + 1);
    }

    if (addr_count > 0) {
        *h_errnop = NETDB_SUCCESS;
        if (validated)
            *val_status = VAL_VALIDATED_ANSWER;
        else if (trusted)
            *val_status = VAL_TRUSTED_ANSWER;
        else 
            *val_status = VAL_UNTRUSTED_ANSWER; 
    } else if (alias_count == 0) {
        goto err;
    } else if (*h_errnop == 0)   {
        /* missing a proof of non-existence for alias */
        *val_status = VAL_UNTRUSTED_ANSWER;
        *h_errnop = NO_DATA;
    } 
    return ret;

err:
    *offset = orig_offset;
    return NULL;
    
}                               /* get_hostent_from_response() */
Exemple #13
0
char *
AddrToAddrStr(char *const dst, size_t dsize, struct sockaddr_in * const saddrp, int dns, const char *fmt)
{
    char addrName[128];
    char *addrNamePtr;
    struct hostent *hp;
    char str[128];
    char s_name[64];
    char *dlim, *dp;
    const char *cp;

    if (dsize == 0)
        return NULL;
    memset(dst, 0, dsize);

    addrNamePtr = NULL;
    if (dns == 0)
    {
        InetNtoA(addrName, &saddrp->sin_addr, sizeof(addrName));
        addrNamePtr = addrName;
    }
    else
    {
#ifdef DNSSEC_LOCAL_VALIDATION
        val_status_t val_status;
        hp = val_gethostbyaddr(NULL, (const char*)&saddrp->sin_addr, sizeof(struct in_addr), AF_INET, &val_status);
        if ((hp != NULL) && (!val_istrusted(val_status)))
            hp = NULL;
#else
        hp = gethostbyaddr((gethost_addrptr_t) &saddrp->sin_addr, sizeof(struct in_addr), AF_INET);
#endif
        if ((hp != NULL) && (hp->h_name != NULL) && (hp->h_name[0] != '\0'))
        {
            addrNamePtr = hp->h_name;
        }
        else
        {
            InetNtoA(addrName, &saddrp->sin_addr, sizeof(addrName));
            addrNamePtr = addrName;
        }
    }
    if (fmt == NULL)
        fmt = "%h:%p";
    for (dp = dst, dlim = dp + dsize - 1; ; fmt++)
    {
        if (*fmt == '\0')
        {
            break;	/* done */
        }
        else if (*fmt == '%')
        {
            fmt++;
            if (*fmt == '%')
            {
                if (dp < dlim)
                    *dp++ = '%';
            }
            else if (*fmt == 'p')
            {
                sprintf(str, "%u", (unsigned int) ntohs(saddrp->sin_port));
                for (cp = str; *cp != '\0'; cp++)
                    if (dp < dlim)
                        *dp++ = *cp;
                *dp = '\0';
            }
            else if (*fmt == 'h')
            {
                if (addrNamePtr != NULL)
                {
                    cp = addrNamePtr;
                }
                else
                {
                    cp = "unknown";
                }
                for ( ; *cp != '\0'; cp++)
                    if (dp < dlim)
                        *dp++ = *cp;
                *dp = '\0';
            }
            else if (*fmt == 's')
            {
                cp = s_name;
                (void) ServicePortNumberToName(ntohs(saddrp->sin_port), s_name, sizeof(s_name), 0);
                for ( ; *cp != '\0'; cp++)
                    if (dp < dlim)
                        *dp++ = *cp;
                /* endservent(); */
                *dp = '\0';
            }
            else if ((*fmt == 't') || (*fmt == 'u'))
            {
                cp = s_name;
                (void) ServicePortNumberToName(ntohs(saddrp->sin_port), s_name, sizeof(s_name), (int) *fmt);
                for ( ; *cp != '\0'; cp++)
                    if (dp < dlim)
                        *dp++ = *cp;
                /* endservent(); */
                *dp = '\0';
            }
            else if (*fmt == '\0')
            {
                break;
            }
            else
            {
                if (dp < dlim)
                    *dp++ = *fmt;
            }
        }
        else if (dp < dlim)
        {
            *dp++ = *fmt;
        }
    }
    *dp = '\0';
    return (dst);
}	/* AddrToAddrStr */
Exemple #14
0
int
AddrStrToAddr(const char * const s, struct sockaddr_in * const sa, const int defaultport)
{
    char portstr[128];
    unsigned int ipnum;
    unsigned int port;
    struct hostent *hp;
    char *hostcp, *atsign, *colon, *cp, *p2;

    memset(sa, 0, sizeof(struct sockaddr_in));
    strncpy(portstr, s, sizeof(portstr));
    portstr[sizeof(portstr) - 1] = '\0';

    if ((colon = strchr(portstr, ':')) != NULL)
    {
        /* Does it look like a URL?  http://host ? */
        if ((colon[1] == '/') && (colon[2] == '/'))
        {
            *colon = '\0';
            port = 0;
            hostcp = colon + 3;
            for (cp = hostcp; *cp != '\0'; cp++)
            {
                if ((!ISALNUM(*cp)) && (*cp != '.'))
                {
                    /* http://host:port */
                    if ((*cp == ':') && (isdigit((int) cp[1])))
                    {
                        *cp++ = '\0';
                        p2 = cp;
                        while (isdigit((int) *cp))
                            cp++;
                        *cp = '\0';
                        port = atoi(p2);
                    }
                    *cp = '\0';
                    break;
                }
            }
            if (port == 0)
                port = ServiceNameToPortNumber(portstr, 0);
        }
        else
        {
            /* Look for host.name.domain:port */
            *colon = '\0';
            hostcp = portstr;
            port = (unsigned int) atoi(colon + 1);
        }
    }
    else if ((atsign = strchr(portstr, '@')) != NULL)
    {
        /* Look for [email protected] */
        *atsign = '\0';
        hostcp = atsign + 1;
        port = (unsigned int) atoi(portstr);
    }
    else if (defaultport > 0)
    {
        /* Have just host.name.domain, use that w/ default port. */
        port = (unsigned int) defaultport;
        hostcp = portstr;
    }
    else
    {
        /* If defaultport <= 0, they must supply a port number
         * in the host/port string.
         */
        errno = EADDRNOTAVAIL;
        return (kAddrStrToAddrMiscErr);
    }

    sa->sin_port = htons((short) port);

    ipnum = inet_addr(hostcp);
    if (ipnum != INADDR_NONE)
    {
        sa->sin_family = AF_INET;
        sa->sin_addr.s_addr = ipnum;
    }
    else
    {
#ifdef DNSSEC_LOCAL_VALIDATION
        val_status_t val_status;
        errno = 0;
        hp = val_gethostbyname(NULL,hostcp,&val_status);
        if ((hp != NULL) && (!val_istrusted(val_status)))
            hp = NULL;
#else
        errno = 0;
        hp = gethostbyname(hostcp);
#endif
        if (hp == NULL)
        {
            if (errno == 0)
                errno = ENOENT;
            return (kAddrStrToAddrBadHost);
        }
        sa->sin_family = hp->h_addrtype;
        memcpy(&sa->sin_addr.s_addr, hp->h_addr_list[0],
               (size_t) hp->h_length);
    }
    return (0);
}	/* AddrStrToAddr */
Exemple #15
0
/* gets the DNS records for name:type
 * returns a dyn. alloc'ed struct rdata linked list with the parsed responses
 * or 0 on error
 * see rfc1035 for the query/response format */
struct rdata* get_record(char* name, int type, int flags)
{
	int size;
	int skip;
	int qno, answers_no;
	int i, r;
	static union dns_query buff;
	unsigned char* p;
	unsigned char* end;
	unsigned char* rd_end;
	static char rec_name[MAX_DNS_NAME]; /* placeholder for the record name */
	int rec_name_len;
	unsigned short rtype, class, rdlength;
	unsigned int ttl;
	struct rdata* head;
	struct rdata** crt;
	struct rdata** last;
	struct rdata* rd;
	struct srv_rdata* srv_rd;
	struct srv_rdata* crt_srv;
	int search_list_used;
	int name_len;
	struct rdata* fullname_rd;
	char c;
	
#ifdef USE_DNSSEC
	val_status_t val_status;
#endif

	name_len=strlen(name);

	for (i = 0; i < name_len; i++) {
	    c = name[i];
	    if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ||
		((c >= '0') && (c <= '9')) || (name[i] == '.') ||
		(name[i] == '-') || (name[i] == '_'))
			continue;
	    LM_DBG("'%s' is not domain name\n", name);
	    return 0;
	}

	if (cfg_get(core, core_cfg, dns_search_list)==0) {
		search_list_used=0;
		name_len=0;
	} else {
		search_list_used=1;
	}
	fullname_rd=0;

#ifndef USE_DNSSEC
	size=res_search(name, C_IN, type, buff.buff, sizeof(buff));
#else
	size=val_res_query((val_context_t *) NULL,
                      (char *) name, 
                      (int) C_IN,
		      (int) type, 
                      (unsigned char *) buff.buff, 
		      (int) sizeof(buff),
                      &val_status);	
	if(!val_istrusted(val_status)){
		LOG(L_INFO, "INFO: got not trusted record when resolving %s\n",name);
	}
#endif

	if (unlikely(size<0)) {
		DBG("get_record: lookup(%s, %d) failed\n", name, type);
		goto not_found;
	}
	else if (unlikely(size > sizeof(buff))) size=sizeof(buff);
	head=rd=0;
	last=crt=&head;
	
	p=buff.buff+DNS_HDR_SIZE;
	end=buff.buff+size;
	if (unlikely(p>=end)) goto error_boundary;
	qno=ntohs((unsigned short)buff.hdr.qdcount);

	for (r=0; r<qno; r++){
		/* skip the name of the question */
		if (unlikely((p=dns_skipname(p, end))==0)) {
			LOG(L_ERR, "ERROR: get_record: skipname==0\n");
			goto error;
		}
		p+=2+2; /* skip QCODE & QCLASS */
	#if 0
		for (;(p<end && (*p)); p++);
		p+=1+2+2; /* skip the ending  '\0, QCODE and QCLASS */
	#endif
		if (unlikely(p>end)) {
			LOG(L_ERR, "ERROR: get_record: p>=end\n");
			goto error;
		}
	};
	answers_no=ntohs((unsigned short)buff.hdr.ancount);
again:
	for (r=0; (r<answers_no) && (p<end); r++){
#if 0
		/*  ignore it the default domain name */
		if ((p=dns_skipname(p, end))==0) {
			LOG(L_ERR, "ERROR: get_record: skip_name=0 (#2)\n");
			goto error;
		}
#else
		if (unlikely((skip=dn_expand(buff.buff, end, p, rec_name,
							MAX_DNS_NAME-1))==-1)){
			LOG(L_ERR, "ERROR: get_record: dn_expand(rec_name) failed\n");
			goto error;
		}
#endif
		p+=skip;
		rec_name_len=strlen(rec_name);
		if (unlikely(rec_name_len>255)){
			LOG(L_ERR, "ERROR: get_record: dn_expand(rec_name): name too"
					" long  (%d)\n", rec_name_len);
			goto error;
		}
		/* check if enough space is left for type, class, ttl & size */
		if (unlikely((p+2+2+4+2)>end)) goto error_boundary;
		/* get type */
		memcpy((void*) &rtype, (void*)p, 2);
		rtype=ntohs(rtype);
		p+=2;
		/* get  class */
		memcpy((void*) &class, (void*)p, 2);
		class=ntohs(class);
		p+=2;
		/* get ttl*/
		memcpy((void*) &ttl, (void*)p, 4);
		ttl=ntohl(ttl);
		p+=4;
		/* get size */
		memcpy((void*)&rdlength, (void*)p, 2);
		rdlength=ntohs(rdlength);
		p+=2;
		rd_end=p+rdlength;
		if (unlikely((rd_end)>end)) goto error_boundary;
		if ((flags & RES_ONLY_TYPE) && (rtype!=type)){
			/* skip */
			p=rd_end;
			continue;
		}
		/* expand the "type" record  (rdata)*/
		
		rd=(struct rdata*) local_malloc(sizeof(struct rdata)+rec_name_len+
										1-1);
		if (rd==0){
			LOG(L_ERR, "ERROR: get_record: out of memory\n");
			goto error;
		}
		rd->type=rtype;
		rd->pclass=class;
		rd->ttl=ttl;
		rd->next=0;
		memcpy(rd->name, rec_name, rec_name_len);
		rd->name[rec_name_len]=0;
		rd->name_len=rec_name_len;
		/* check if full name matches */
		if ((search_list_used==1)&&(fullname_rd==0)&&
				(rec_name_len>=name_len)&&
				(strncasecmp(rec_name, name, name_len)==0)) {
			/* now we have record whose name is the same (up-to the
			 * name_len with the searched one):
			 * if the length is the same - we found full match, no fake
			 *  cname needed, just clear the flag
			 * if the length of the name differs - it has matched using
			 *  search list remember the rd, so we can create fake CNAME
			 *  record when all answers are used and no better match found
			 */
			if (rec_name_len==name_len)
				search_list_used=0;
			/* this is safe.... here was rec_name_len > name_len */
			else if (rec_name[name_len]=='.') {
#ifdef HAVE_RESOLV_RES
				if ((cfg_get(core, core_cfg, dns_search_fmatch)==0) ||
						(match_search_list(&_res, rec_name+name_len+1)!=0))
#endif
					fullname_rd=rd;
			}
		}
		switch(rtype){
			case T_SRV:
				srv_rd= dns_srv_parser(buff.buff, end, rd_end, p);
				rd->rdata=(void*)srv_rd;
				if (unlikely(srv_rd==0)) goto error_parse;
				
				/* insert sorted into the list */
				for (crt=&head; *crt; crt= &((*crt)->next)){
					if ((*crt)->type!=T_SRV)
						continue;
					crt_srv=(struct srv_rdata*)(*crt)->rdata;
					if ((srv_rd->priority <  crt_srv->priority) ||
					   ( (srv_rd->priority == crt_srv->priority) && 
							 (srv_rd->weight > crt_srv->weight) ) ){
						/* insert here */
						goto skip;
					}
				}
				last=&(rd->next); /*end of for => this will be the last
									element*/
			skip:
				/* insert here */
				rd->next=*crt;
				*crt=rd;
				break;
			case T_A:
				rd->rdata=(void*) dns_a_parser(p, rd_end);
				if (unlikely(rd->rdata==0)) goto error_parse;
				*last=rd; /* last points to the last "next" or the list
							 	head*/
				last=&(rd->next);
				break;
			case T_AAAA:
				rd->rdata=(void*) dns_aaaa_parser(p, rd_end);
				if (unlikely(rd->rdata==0)) goto error_parse;
				*last=rd;
				last=&(rd->next);
				break;
			case T_CNAME:
				rd->rdata=(void*) dns_cname_parser(buff.buff, end, p);
				if(unlikely(rd->rdata==0)) goto error_parse;
				*last=rd;
				last=&(rd->next);
				break;
			case T_NAPTR:
				rd->rdata=(void*)dns_naptr_parser(buff.buff, end, rd_end, p);
				if(unlikely(rd->rdata==0)) goto error_parse;
				*last=rd;
				last=&(rd->next);
				break;
			case T_TXT:
				rd->rdata= dns_txt_parser(buff.buff, rd_end, p);
				if (rd->rdata==0) goto error_parse;
				*last=rd;
				last=&(rd->next);
				break;
			case T_EBL:
				rd->rdata= dns_ebl_parser(buff.buff, end, rd_end, p);
				if (rd->rdata==0) goto error_parse;
				*last=rd;
				last=&(rd->next);
				break;
			case T_PTR:
				rd->rdata=(void*) dns_ptr_parser(buff.buff, end, p);
				if(unlikely(rd->rdata==0)) goto error_parse;
				*last=rd;
				last=&(rd->next);
				break;
			default:
				LOG(L_ERR, "WARNING: get_record: unknown type %d\n", rtype);
				rd->rdata=0;
				*last=rd;
				last=&(rd->next);
		}
		
		p+=rdlength;
		
	}
	if (flags & RES_AR){
		flags&=~RES_AR;
		answers_no=ntohs((unsigned short)buff.hdr.nscount);
#ifdef RESOLVE_DBG
		DBG("get_record: skipping %d NS (p=%p, end=%p)\n", answers_no, p,
				end);
#endif
		for (r=0; (r<answers_no) && (p<end); r++){
			/* skip over the ns records */
			if ((p=dns_skipname(p, end))==0) {
				LOG(L_ERR, "ERROR: get_record: skip_name=0 (#3)\n");
				goto error;
			}
			/* check if enough space is left for type, class, ttl & size */
			if (unlikely((p+2+2+4+2)>end)) goto error_boundary;
			memcpy((void*)&rdlength, (void*)p+2+2+4, 2);
			p+=2+2+4+2+ntohs(rdlength);
		}
		answers_no=ntohs((unsigned short)buff.hdr.arcount);
#ifdef RESOLVE_DBG
		DBG("get_record: parsing %d ARs (p=%p, end=%p)\n", answers_no, p,
				end);
#endif
		goto again; /* add also the additional records */
	}

	/* if the name was expanded using DNS search list
	 * create fake CNAME record to convert the short name
	 * (queried) to long name (answered)
	 */
	if ((search_list_used==1)&&(fullname_rd!=0)) {
		rd=(struct rdata*) local_malloc(sizeof(struct rdata)+name_len+1-1);
		if (unlikely(rd==0)){
			LOG(L_ERR, "ERROR: get_record: out of memory\n");
			goto error;
		}
		rd->type=T_CNAME;
		rd->pclass=fullname_rd->pclass;
		rd->ttl=fullname_rd->ttl;
		rd->next=head;
		memcpy(rd->name, name, name_len);
		rd->name[name_len]=0;
		rd->name_len=name_len;
		/* alloc sizeof struct + space for the null terminated name */
		rd->rdata=(void*)local_malloc(sizeof(struct cname_rdata)-1+
										head->name_len+1);
		if(unlikely(rd->rdata==0)){
			LOG(L_ERR, "ERROR: get_record: out of memory\n");
			goto error_rd;
		}
		((struct cname_rdata*)(rd->rdata))->name_len=fullname_rd->name_len;
		memcpy(((struct cname_rdata*)(rd->rdata))->name, fullname_rd->name,
				fullname_rd->name_len);
		((struct cname_rdata*)(rd->rdata))->name[head->name_len]=0;
		head=rd;
	}

	return head;
error_boundary:
		LOG(L_ERR, "ERROR: get_record: end of query buff reached\n");
		if (head) free_rdata_list(head);
		return 0;
error_parse:
		LOG(L_ERR, "ERROR: get_record: rdata parse error (%s, %d), %p-%p"
						" rtype=%d, class=%d, ttl=%d, rdlength=%d \n",
				name, type,
				p, end, rtype, class, ttl, rdlength);
error_rd:
		if (rd) local_free(rd); /* rd->rdata=0 & rd is not linked yet into
								   the list */
error:
		LOG(L_ERR, "ERROR: get_record \n");
		if (head) free_rdata_list(head);
not_found:
	/* increment error counter */
	counter_inc(dns_cnts_h.failed_dns_req);
	return 0;
}
static int
get_results(val_context_t * context, const char *desc, char *name,
            int class_h, int type_h, u_char *response,
            int *response_size, int trusted_only)
{
    int             response_size_max, ret_val, err = 0;
    struct val_result_chain *results = NULL;
    struct val_response resp;

    if ((NULL == desc) || (NULL == name) || (NULL == response) ||
        (NULL == response_size))
        return -1;

    response_size_max = *response_size;
    *response_size = 0;

    fprintf(stderr, "%s: ****START**** \n", desc);

    /*
     * Query the validator
     */
    ret_val = val_resolve_and_check(context, name, class_h, type_h, 
                                    VAL_QUERY_AC_DETAIL, &results);

    if (ret_val == VAL_NO_ERROR) {

        ret_val = compose_answer(name, type_h, class_h, results, &resp);
        val_free_result_chain(results);

        if (VAL_NO_ERROR != ret_val) {
            fprintf(stderr, "%s: \t", desc);
            fprintf(stderr, "FAILED: Error in compose_answer(): %d\n",
                    ret_val);
        }
        else {
            if (resp.vr_response == NULL) {
                fprintf(stderr, "FAILED: No response\n");
            } else {
                printf("DNSSEC status: %s [%d]\n",
                       p_val_error(resp.vr_val_status), resp.vr_val_status);
                if (val_isvalidated(resp.vr_val_status)) {
                    printf("Validated response:\n");
                } else if (val_istrusted(resp.vr_val_status)) {
                    printf("Trusted but not validated response:\n");
                } else {
                    printf("Non-validated response:\n");
                }
                if (resp.vr_length > response_size_max) {
                    err = 1;
                }
                else {
                    print_response(resp.vr_response, resp.vr_length);
                    memcpy(response, resp.vr_response, resp.vr_length);
                    *response_size = resp.vr_length;
                }

                FREE(resp.vr_response);
            }
        }

    } else {
        fprintf(stderr, "%s: \t", desc);
        fprintf(stderr, "FAILED: Error in val_resolve_and_check(): %d, %s\n",
                ret_val, p_val_err(ret_val));
    }

    fprintf(stderr, "%s: ****END**** \n", desc);

    return (err != 0);          /* 0 success, 1 error */
}
Exemple #17
0
void
val_log_authentication_chain(const val_context_t * ctx, int level,
                             const char * name_p, int class_h,
                             int type_h,
                             struct val_result_chain *results)
{
    struct val_result_chain *next_result;
    int real_type_h;
    int real_class_h;

    if (results == NULL) { 
        return;
    } 
    
    for (next_result = results; next_result;
         next_result = next_result->val_rc_next) {
        struct val_authentication_chain *next_as;
        int             i;

        /* Display the correct owner name, class,type for the record */
        if (next_result->val_rc_rrset) {
            real_type_h = next_result->val_rc_rrset->val_rrset_type; 
            real_class_h = next_result->val_rc_rrset->val_rrset_class; 
        } else {
            real_type_h = type_h;
            real_class_h = class_h;
        }

        if (val_isvalidated(next_result->val_rc_status)) {
            val_log(ctx, level, "Validation result for {%s, %s(%d), %s(%d)}: %s:%d (Validated)",
                    name_p, p_class(real_class_h), real_class_h,
                    p_type(real_type_h), real_type_h,
                    p_val_status(next_result->val_rc_status),
                    next_result->val_rc_status);
        } else if (val_istrusted(next_result->val_rc_status)) {
            val_log(ctx, level, "Validation result for {%s, %s(%d), %s(%d)}: %s:%d (Trusted but not Validated)",
                    name_p, p_class(real_class_h), real_class_h,
                    p_type(real_type_h), real_type_h,
                    p_val_status(next_result->val_rc_status),
                    next_result->val_rc_status);
        } else {
            val_log(ctx, level, "Validation result for {%s, %s(%d), %s(%d)}: %s:%d (Untrusted)",
                    name_p, p_class(real_class_h), real_class_h,
                    p_type(real_type_h), real_type_h,
                    p_val_status(next_result->val_rc_status),
                    next_result->val_rc_status);
        }

        for (next_as = next_result->val_rc_answer; next_as;
             next_as = next_as->val_ac_trust) {

            if (next_as->val_ac_rrset == NULL) {
                val_log(ctx, level, "    Assertion status = %s:%d",
                        p_ac_status(next_as->val_ac_status),
                        next_as->val_ac_status);
            } else {
                const char   *t_name;
                t_name = next_as->val_ac_rrset->val_rrset_name;
                if (t_name == NULL)
                    t_name = (const char *) "NULL_DATA";

                val_log_assertion_pfx(ctx, level, "    ", t_name,
                                      next_as);
                //                val_log_val_rrset_pfx(ctx, level, "     ",
                //                                  next_as->val_ac_rrset);
            }
        }

        for (i = 0; i < next_result->val_rc_proof_count; i++) {
            val_log(ctx, level, "    Proof of non-existence [%d of %d]", 
                    i+1, next_result->val_rc_proof_count);
            for (next_as = next_result->val_rc_proofs[i]; next_as;
                 next_as = next_as->val_ac_trust) {
                if (next_as->val_ac_rrset == NULL) {
                    val_log(ctx, level, "      Assertion status = %s:%d",
                            p_ac_status(next_as->val_ac_status),
                            next_as->val_ac_status);
                } else {
                    const char   *t_name;
                    t_name = next_as->val_ac_rrset->val_rrset_name;
                    if (t_name == NULL)
                        t_name = (const char *) "NULL_DATA";

                    val_log_assertion_pfx(ctx, level, "      ", t_name,
                                          next_as);
                }
            }
        }
    }
}
int
main(int argc, char *argv[])
{
    const char     *allowed_args = "hl:x:p:o:sv:i:r:V";
    char           *node = NULL;
    int             retval;
    int             async = 1;
    val_log_t      *logp;
    char           *label_str = NULL;
    struct val_daneparams daneparams;
    struct val_danestatus *danestatus = NULL;
    struct val_ssl_data *ssl_dane_data = NULL;
    int port = 443;
    int proto = DANE_PARAM_PROTO_TCP;
    val_context_t *context = NULL;
    val_status_t val_status;
    struct addrinfo *val_ainfo = NULL;
    struct addrinfo hints;
    int ret = 0;
    int dane_retval = VAL_DANE_INTERNAL_ERROR;
    int ai_retval = 0;
    int err;

    /* Parse the command line */
    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, allowed_args,
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, allowed_args, prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, allowed_args);
#endif

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage(argv[0]);
            return -1;
        case 'l':
            label_str = optarg;
            break;
        case 'o':
            logp = val_log_add_optarg(optarg, 1);
            if (NULL == logp) { /* err msg already logged */
                usage(argv[0]);
                return -1;
            }
            break;

        case 's':
            async = 0;
            break;

        case 'p':
            port = atoi(optarg);
            break;

        case 'x':
            if(strncmp(optarg, DANE_PARAM_PROTO_STR_TCP,
                       strlen(DANE_PARAM_PROTO_STR_TCP)))
                proto = DANE_PARAM_PROTO_TCP;
            else if (strncmp(optarg, DANE_PARAM_PROTO_STR_UDP,
                        strlen(DANE_PARAM_PROTO_STR_UDP)))
                proto = DANE_PARAM_PROTO_UDP;
            else if (strncmp(optarg, DANE_PARAM_PROTO_STR_SCTP, 
                        strlen(DANE_PARAM_PROTO_STR_SCTP)))
                proto = DANE_PARAM_PROTO_SCTP;
            else {
                usage(argv[0]);
                return -1;
            }
            break;

        case 'v':
            dnsval_conf_set(optarg);
            break;

        case 'i':
            root_hints_set(optarg);
            break;

        case 'r':
            resolv_conf_set(optarg);
            break;

        case 'V':
            version();
            return 0;
        default:
            fprintf(stderr, "Invalid option %s\n", argv[optind - 1]);
            usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc) {
        node = argv[optind++];
    } else {
        fprintf(stderr, "Error: node name not specified\n");
        usage(argv[0]);
        return -1;
    }

    if (VAL_NO_ERROR != (retval = 
                val_create_context(label_str, &context))) {
        fprintf(stderr, "Cannot create context %s(%d)\n", 
                p_val_error(retval), retval);
        return -1;
    }

    daneparams.port = port;
    daneparams.proto = proto;
    memset(&hints, 0, sizeof(struct addrinfo));
#ifdef AI_ADDRCONFIG
    hints.ai_flags = AI_ADDRCONFIG;
#endif

    if (!async) {
        /* synchronous lookup and validation */
        ai_retval = val_getaddrinfo(context, node, NULL, &hints,
                                    &val_ainfo, &val_status);
        dane_retval = val_getdaneinfo(context, node, &daneparams, &danestatus); 
    }
    else {
#ifdef VAL_NO_ASYNC
        fprintf(stderr, "async support not available\n");
#else
        struct dane_cb cb_data_dane = { &dane_retval, &danestatus, 0 };
        val_dane_callback my_dane_cb = &_danecallback;
        struct timeval tv;
        val_async_status *das = NULL; /* helps us cancel the lookup if we need to */

        struct getaddr_s cb_data_ai = { &ai_retval, &val_ainfo, &val_status, 0 };
        val_gai_callback my_ai_cb = &_aicallback;
        val_gai_status *status = NULL;

        /*
         * submit requests
         */
        if (VAL_NO_ERROR != val_dane_submit(context, node, &daneparams,
                                 my_dane_cb, &cb_data_dane, &das) ||
            VAL_NO_ERROR != val_getaddrinfo_submit(context, node, NULL,
                                &hints, my_ai_cb, &cb_data_ai, 0, &status)) {
            dane_retval = VAL_DANE_INTERNAL_ERROR; 
            goto done;
        }

        /*
         * wait for it to complete
         */
#if 0
        while(0 == cb_data_dane.done ||
              0 == cb_data_ai.done) {
            tv.tv_sec = 10;
            tv.tv_usec = 0;
            val_async_check_wait(context, NULL, NULL, &tv, 0);
        }
#endif

#if 1
        while(0 == cb_data_dane.done || 
              0 == cb_data_ai.done) {
            fd_set  activefds;
            int nfds = 0;
            int ready;

            FD_ZERO(&activefds);

            tv.tv_sec = 10; /* 10 sec */
            tv.tv_usec = 0;

            val_async_select_info(context, &activefds, &nfds, &tv);
            ready = select(nfds+1, &activefds, NULL, NULL, &tv);
            if (ready < 0) {
                continue;
            } 
            val_async_check(context, &activefds, &nfds, 0);
        }
#endif

#endif
    }

done:
    if (ai_retval != 0) {
        fprintf(stderr, "Error in val_getaddrinfo(): %d\n", ai_retval);
        return -1;
    }

    if (!val_istrusted(val_status)) {
        fprintf(stderr, 
                "Address lookup information could not be validated: %s\n", 
                p_val_status(val_status));

    } else if(dane_retval == VAL_DANE_NOERROR && 
              proto == DANE_PARAM_PROTO_TCP) {

        /* Set up the SSL connection */
        SSL_library_init();
        SSL_load_error_strings();

        const SSL_METHOD *meth = SSLv23_client_method();
        SSL_CTX *sslctx = SSL_CTX_new(meth);

        struct addrinfo *ai = NULL;
        int presetup_okay;

        /*
         * OpenSSL only does protocol negotiation on SSLv23_client_method;
         * we need to set SNI to get the correct certificate from many
         * modern browsers, so we disable both SSLv2 and SSLv3 if we can.
         * That leaves (currently) TLSv1.0 TLSv1.1 TLSv1.2
         */
        long ssl_options = 0
#ifdef SSL_OP_NO_SSLv2
            | SSL_OP_NO_SSLv2
#endif
#ifdef SSL_OP_NO_SSLv3
            | SSL_OP_NO_SSLv3
#endif
            ;

        if (!SSL_CTX_set_options(sslctx, ssl_options)) {
            fprintf(stderr, "Failed to set SSL context options (%ld): %s\n",
              ssl_options, ssl_error());
            presetup_okay = 0;
        } else {
            presetup_okay = 1;
        }

        if (VAL_NO_ERROR != (err = val_enable_dane_ssl(context, sslctx, node,
                                        danestatus, &ssl_dane_data))) {
            fprintf(stderr,
                    "Could not set danestatus for SSL connection %s\n",
                    p_val_error(err));
        }

        ai = val_ainfo;
        while(presetup_okay && ai && (ai->ai_protocol == IPPROTO_TCP) && 
             (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)) {

            int sock;
            char buf[INET6_ADDRSTRLEN];
            size_t buflen = sizeof(buf);
            const char *addr = NULL;

            if (ai->ai_family == AF_INET) {
                sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = htons(port);
            } else {
                sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
                ((struct sockaddr_in6 *)(ai)->ai_addr)->sin6_port = htons(port);
            }

            INET_NTOP(ai->ai_family, ai->ai_addr, sizeof(ai->ai_addr), buf, buflen, addr);
            fprintf(stderr, "Connecting to %s\n", addr);

            if (0 == connect(sock, ai->ai_addr, ai->ai_addrlen)) {
                SSL *ssl = SSL_new(sslctx);
                BIO * sbio = BIO_new_socket(sock,BIO_NOCLOSE);


#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
                SSL_set_tlsext_host_name(ssl, node);
#endif

                SSL_set_bio(ssl,sbio,sbio);

                if ((err = SSL_connect(ssl)) != 1) {
                    fprintf(stderr, "SSL Connect to %s failed: %d\n", node, err);
                } 
                SSL_shutdown(ssl);
                SSL_free(ssl);
            } else {
                fprintf(stderr, "TCP Connect to %s failed\n", node);
            }

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

    } else if (dane_retval == VAL_DANE_IGNORE_TLSA) {
        fprintf(stderr, "TLSA is either provably non-existant or provably insecure. It will be ignored.\n");
    } else {
        fprintf(stderr, "TLSA record could not be validated.\n");
        ret = 1;
    }

    if (danestatus != NULL)
        val_free_dane(danestatus);

    if (val_ainfo != NULL)
        val_freeaddrinfo(val_ainfo);    

    val_free_dane_ssl(ssl_dane_data);/* MUST happen before we free the context*/
    val_free_context(context);
    val_free_validator_state();

    return ret;
}