/*!
 * \brief Ensure that a nonce on an incoming request is sane.
 *
 * The nonce in an incoming Authorization header needs to pass some scrutiny in order
 * for us to consider accepting it. What we do is re-build a nonce based on request
 * data and a realm and see if it matches the nonce they sent us.
 * \param candidate The nonce on an incoming request
 * \param rdata The incoming request
 * \param auth The auth credentials we are trying to match against.
 * \retval 0 Nonce does not pass validity checks
 * \retval 1 Nonce passes validity check
 */
static int check_nonce(const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
{
	char *copy = ast_strdupa(candidate);
	char *timestamp = strsep(&copy, "/");
	int timestamp_int;
	time_t now = time(NULL);
	struct ast_str *calculated = ast_str_alloca(64);

	if (!copy) {
		/* Clearly a bad nonce! */
		return 0;
	}

	if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
		return 0;
	}

	if ((int) now - timestamp_int > auth->nonce_lifetime) {
		return 0;
	}

	build_nonce(&calculated, timestamp, rdata, auth->realm);
	ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
	if (strcmp(ast_str_buffer(calculated), candidate)) {
		return 0;
	}
	return 1;
}
/*!
 * \brief astobj2 callback for adding digest challenges to responses
 *
 * \param realm An auth's realm to build a challenge from
 * \param tdata The response to add the challenge to
 * \param rdata The request the challenge is in response to
 * \param is_stale Indicates whether nonce on incoming request was stale
 */
static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
{
	pj_str_t qop;
	pj_str_t pj_nonce;
	pjsip_auth_srv auth_server;
	struct ast_str *nonce = ast_str_alloca(256);
	char time_buf[32];
	time_t timestamp = time(NULL);
	snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);

	build_nonce(&nonce, time_buf, rdata, realm);

	setup_auth_srv(tdata->pool, &auth_server, realm);

	pj_cstr(&pj_nonce, ast_str_buffer(nonce));
	pj_cstr(&qop, "auth");
	pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce, NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
}
Esempio n. 3
0
uint8_t *build_map_request_pkt(
        lispd_mapping_elt       *requested_mapping,
        lisp_addr_t             *src_eid,
        uint8_t                 encap,
        uint8_t                 probe,
        uint8_t                 solicit_map_request,/* boolean really */
        uint8_t                 smr_invoked,
        int                     *len,               /* return length here */
        uint64_t                *nonce)             /* return nonce here */
{

    uint8_t                                     *packet                 = NULL;
    uint8_t                                     *mr_packet              = NULL;
    lispd_pkt_map_request_t                     *mrp                    = NULL;
    lispd_pkt_mapping_record_t                  *rec                    = NULL;
    lispd_pkt_map_request_itr_rloc_t            *itr_rloc               = NULL;
    lispd_pkt_map_request_eid_prefix_record_t   *request_eid_record     = NULL;
    uint8_t                                     *cur_ptr                = NULL;

    int                     map_request_msg_len = 0;
    int                     ctr                 = 0;
    int                     cpy_len             = 0;
    int                     locators_ctr        = 0;

    lispd_mapping_elt       *src_mapping        = NULL;
    lispd_locators_list     *locators_list[2]   = {NULL,NULL};
    lispd_locator_elt       *locator            = NULL;
    lisp_addr_t             *ih_src_ip          = NULL;

    /*
     * Lookup the local EID prefix from where we generate the message.
     * src_eid is null for RLOC probing and refreshing map_cache -> Source-EID AFI = 0
     */
    if (src_eid != NULL){
        src_mapping = lookup_eid_in_db(*src_eid);
        if (!src_mapping){
            lispd_log_msg(LISP_LOG_DEBUG_2,"build_map_request_pkt: Source EID address not found in local data base - %s -",
                    get_char_from_lisp_addr_t(*src_eid));
            return (NULL);
        }

    }

    /* Calculate the packet size and reserve memory */
    map_request_msg_len = get_map_request_length(requested_mapping,src_mapping);
    *len = map_request_msg_len;

    if ((packet = malloc(map_request_msg_len)) == NULL){
        lispd_log_msg(LISP_LOG_WARNING,"build_map_request_pkt: Unable to allocate memory for Map Request (packet_len): %s", strerror(errno));
        return (NULL);
    }
    memset(packet, 0, map_request_msg_len);


    cur_ptr = packet;

    mrp = (lispd_pkt_map_request_t *)cur_ptr;

    mrp->type                      = LISP_MAP_REQUEST;
    mrp->authoritative             = 0;
    if (src_eid != NULL)
        mrp->map_data_present      = 1;
    else
        mrp->map_data_present      = 0;

    if (probe)
        mrp->rloc_probe            = 1;
    else
        mrp->rloc_probe            = 0;

    if (solicit_map_request)
        mrp->solicit_map_request   = 1;
    else
        mrp->solicit_map_request   = 0;

    if (smr_invoked)
        mrp->smr_invoked           = 1;
    else
        mrp->smr_invoked           = 0;

    mrp->additional_itr_rloc_count = 0;     /* To be filled later  */
    mrp->record_count              = 1;     /* XXX: assume 1 record */
    mrp->nonce = build_nonce((unsigned int) time(NULL));
    *nonce                         = mrp->nonce;

    if (src_eid != NULL){
        cur_ptr = pkt_fill_eid(&(mrp->source_eid_afi),src_mapping);

        /* Add itr-rlocs */
        locators_list[0] = src_mapping->head_v4_locators_list;
        locators_list[1] = src_mapping->head_v6_locators_list;

        for (ctr=0 ; ctr < 2 ; ctr++){
            while (locators_list[ctr]){
                locator = locators_list[ctr]->locator;
                if (*(locator->state)==DOWN){
                    locators_list[ctr] = locators_list[ctr]->next;
                    continue;
                }
                /* Remove ITR locators behind NAT: No control message (4342) can be received in these interfaces */
                if (((lcl_locator_extended_info *)locator->extended_info)->rtr_locators_list != NULL){
                    locators_list[ctr] = locators_list[ctr]->next;
                    continue;
                }

                itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)cur_ptr;
                itr_rloc->afi = htons(get_lisp_afi(locator->locator_addr->afi,NULL));
                /* Add rloc address */
                cur_ptr = CO(itr_rloc,sizeof(lispd_pkt_map_request_itr_rloc_t));
                cpy_len = copy_addr((void *) cur_ptr ,locator->locator_addr, 0);
                cur_ptr = CO(cur_ptr, cpy_len);
                locators_ctr ++;
                locators_list[ctr] = locators_list[ctr]->next;
            }
        }
    }else {
        // XXX If no source EID is used, then we only use one ITR-RLOC for IPv4 and one for IPv6-> Default control RLOC
        mrp->source_eid_afi = 0;
        cur_ptr = CO(mrp, sizeof(lispd_pkt_map_request_t));
        if (default_ctrl_iface_v4 != NULL){
            itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)cur_ptr;
            itr_rloc->afi = htons((uint16_t)LISP_AFI_IP);
            cur_ptr = CO(itr_rloc,sizeof(lispd_pkt_map_request_itr_rloc_t));
            cpy_len = copy_addr((void *) cur_ptr ,default_ctrl_iface_v4->ipv4_address, 0);
            cur_ptr = CO(cur_ptr, cpy_len);
            locators_ctr ++;
        }
        if (default_ctrl_iface_v6 != NULL){
            itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)cur_ptr;
            itr_rloc->afi = htons(get_lisp_afi(AF_INET6,NULL));
            cur_ptr = CO(itr_rloc,sizeof(lispd_pkt_map_request_itr_rloc_t));
            cpy_len = copy_addr((void *) cur_ptr ,default_ctrl_iface_v6->ipv6_address, 0);
            cur_ptr = CO(cur_ptr, cpy_len);
            locators_ctr ++;
        }
    }
    mrp->additional_itr_rloc_count = locators_ctr - 1; /* IRC = 0 --> 1 ITR-RLOC */
    if (locators_ctr == 0){
        lispd_log_msg(LISP_LOG_DEBUG_2,"build_map_request_pkt: No ITR RLOCs.");
        free(packet);
        return (NULL);
    }


    /* Requested EID record */
    request_eid_record = (lispd_pkt_map_request_eid_prefix_record_t *)cur_ptr;
    request_eid_record->eid_prefix_length = requested_mapping->eid_prefix_length;

    cur_ptr = pkt_fill_eid(&(request_eid_record->eid_prefix_afi),requested_mapping);

    if (mrp->map_data_present == 1){
        /* Map-Reply Record */
        rec = (lispd_pkt_mapping_record_t *)cur_ptr;
        if ((pkt_fill_mapping_record(rec, src_mapping, NULL))== NULL) {
            lispd_log_msg(LISP_LOG_DEBUG_2,"build_map_request_pkt: Couldn't buil map reply record for map request. "
                    "Map Request will not be send");
            free(packet);
            return(NULL);
        }
    }

    /* Add Encapsulated (Inner) control header*/
    if (encap){

        /*
         * If no source EID is included (Source-EID-AFI = 0), The default RLOC address is used for
         * the source address in the inner IP header
         */
        if (src_eid != NULL){
            ih_src_ip = &(src_mapping->eid_prefix);;
        }else{
            if (requested_mapping->eid_prefix.afi == AF_INET){
                ih_src_ip = get_main_eid (AF_INET);
            }else{
                ih_src_ip = get_main_eid (AF_INET6);
            }
        }

        mr_packet = packet;
        packet = build_control_encap_pkt(mr_packet, map_request_msg_len, ih_src_ip, &(requested_mapping->eid_prefix), LISP_CONTROL_PORT, LISP_CONTROL_PORT, len);

        if (packet == NULL){
            lispd_log_msg(LISP_LOG_DEBUG_1,"build_map_request_pkt: Couldn't encapsulate the map request");
            free (mr_packet);
            return (NULL);
        }
    }

    return (packet);
}