Exemplo n.º 1
0
/*
 * @brief Appends the Prefix PDU pdu to ary.
 */
static int rtr_store_prefix_pdu(struct rtr_socket *rtr_socket, const void *pdu, const unsigned int pdu_size, void **ary,
                                unsigned int *ind, unsigned int *size)
{
    const enum pdu_type type = rtr_get_pdu_type(pdu);
    assert(type  == IPV4_PREFIX || type == IPV6_PREFIX);
    if ((*ind) >= *size) {
        *size += TEMPORARY_PDU_STORE_INCREMENT_VALUE;
        void *tmp = realloc(*ary, *size * pdu_size);
        if (tmp == NULL) {
            const char txt[] = "Realloc failed";
            RTR_DBG("%s", txt);
            rtr_send_error_pdu(rtr_socket, pdu, pdu_size, INTERNAL_ERROR, txt, sizeof(txt));
            rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
            free(*ary);
            ary = NULL;
            return RTR_ERROR;
        }
        *ary = tmp;
    }
    if (type == IPV4_PREFIX) {
        struct pdu_ipv4 *ary_ipv4 = *ary;

        memcpy(ary_ipv4 + *ind, pdu, pdu_size);
    } else if (type == IPV6_PREFIX) {
        struct pdu_ipv6 *ary_ipv6 = *ary;

        memcpy(ary_ipv6 + *ind, pdu, pdu_size);
    }
    (*ind)++;
    return RTR_SUCCESS;
}
Exemplo n.º 2
0
int rtr_send_error_pdu(const struct rtr_socket *rtr_socket, const void *erroneous_pdu, const uint32_t pdu_len, const enum pdu_error_type error, const char *text, const uint32_t text_len)
{
    //dont send errors for erroneous error PDUs
    if (pdu_len >= 2) {
        if (rtr_get_pdu_type(erroneous_pdu) == ERROR)
            return RTR_SUCCESS;
    }

    unsigned int msg_size = 16 + pdu_len + text_len;
    char msg[msg_size];
    struct pdu_header *header = (struct pdu_header *) msg;
    header->ver = rtr_socket->version;
    header->type = 10;
    header->reserved = error;
    header->len = msg_size;

    memcpy(msg+8, &pdu_len, sizeof(pdu_len));
    if (pdu_len > 0)
        memcpy(msg + 12, erroneous_pdu, pdu_len);
    *(msg + 12 + pdu_len) = htonl(text_len);
    if (text_len > 0)
        memcpy(msg+16+pdu_len, text, text_len);

    return rtr_send_pdu(rtr_socket, msg, msg_size);
}
Exemplo n.º 3
0
static void rtr_pdu_footer_to_host_byte_order(void *pdu)
{
    const enum pdu_type type = rtr_get_pdu_type(pdu);
    struct pdu_header *header = pdu;
    struct pdu_error * err_pdu = NULL;

    uint32_t addr6[4];

    switch (type) {
    case SERIAL_NOTIFY:
        ((struct pdu_serial_notify *) pdu)->sn =
            ntohl(((struct pdu_serial_notify *) pdu)->sn);
        break;
    case EOD:
        if (header->ver == RTR_PROTOCOL_VERSION_1) {
            ((struct pdu_end_of_data_v1 *) pdu)->expire_interval =
                ntohl(((struct pdu_end_of_data_v1 *) pdu)->expire_interval);

            ((struct pdu_end_of_data_v1 *) pdu)->refresh_interval =
                ntohl(((struct pdu_end_of_data_v1 *) pdu)->refresh_interval);

            ((struct pdu_end_of_data_v1 *) pdu)->retry_interval =
                ntohl(((struct pdu_end_of_data_v1 *) pdu)->retry_interval);

            ((struct pdu_end_of_data_v1 *) pdu)->sn =
                ntohl(((struct pdu_end_of_data_v1 *) pdu)->sn);
        } else {
            ((struct pdu_end_of_data_v0 *) pdu)->sn =
                ntohl(((struct pdu_end_of_data_v0 *) pdu)->sn);
        }
        break;
    case IPV4_PREFIX:
        ((struct pdu_ipv4 *) pdu)->prefix =
            ntohl(((struct pdu_ipv4 *) pdu)->prefix);
        ((struct pdu_ipv4 *) pdu)->asn =
            ntohl(((struct pdu_ipv4 *) pdu)->asn);
        break;
    case IPV6_PREFIX:
        lrtr_ipv6_addr_to_host_byte_order(((struct pdu_ipv6 *) pdu)->prefix, addr6);
        memcpy(((struct pdu_ipv6 *) pdu)->prefix, addr6, sizeof(addr6));
        ((struct pdu_ipv6 *) pdu)->asn = ntohl(((struct pdu_ipv6 *) pdu)->asn);
        break;
    case ROUTER_KEY:
        ((struct pdu_router_key *) pdu)->asn =
            ntohl(((struct pdu_router_key *) pdu)->asn);
        break;
    case ERROR:
        err_pdu = pdu;

        err_pdu->len_enc_pdu =
            ntohl(err_pdu->len_enc_pdu);
        //The length of the error message
        *((uint32_t *)(err_pdu->rest + err_pdu->len_enc_pdu)) =
            ntohl(*((uint32_t *)(err_pdu->rest + err_pdu->len_enc_pdu)));
        break;
    default:
        break;
    }
}
Exemplo n.º 4
0
static void test_rtr_get_pdu_type(void **state)
{
	struct pdu_header pdu;

	UNUSED(state);

	pdu.type = SERIAL_NOTIFY;
	assert_int_equal(rtr_get_pdu_type(&pdu), SERIAL_NOTIFY);

	pdu.type = SERIAL_QUERY;
	assert_int_equal(rtr_get_pdu_type(&pdu), SERIAL_QUERY);

	pdu.type = RESET_QUERY;
	assert_int_equal(rtr_get_pdu_type(&pdu), RESET_QUERY);

	pdu.type = CACHE_RESPONSE;
	assert_int_equal(rtr_get_pdu_type(&pdu), CACHE_RESPONSE);

	pdu.type = RESERVED;
	assert_int_equal(rtr_get_pdu_type(&pdu), RESERVED);

	pdu.type = IPV6_PREFIX;
	assert_int_equal(rtr_get_pdu_type(&pdu), IPV6_PREFIX);

	pdu.type = EOD;
	assert_int_equal(rtr_get_pdu_type(&pdu), EOD);

	pdu.type = CACHE_RESET;
	assert_int_equal(rtr_get_pdu_type(&pdu), CACHE_RESET);

	pdu.type = ROUTER_KEY;
	assert_int_equal(rtr_get_pdu_type(&pdu), ROUTER_KEY);

	pdu.type = ERROR;
	assert_int_equal(rtr_get_pdu_type(&pdu), ERROR);
}
Exemplo n.º 5
0
/*
 * @brief Removes router_key from the spki_table with flag field == ADD, ADDs router_key PDU to the spki_table with flag
 * field == REMOVE.
 */
static int rtr_undo_update_spki_table(struct rtr_socket *rtr_socket, void *pdu)
{
    const enum pdu_type type = rtr_get_pdu_type(pdu);
    assert(type == ROUTER_KEY);

    struct spki_record entry;
    rtr_key_pdu_2_spki_record(rtr_socket, pdu, &entry, type);

    int rtval = RTR_ERROR;
    //invert add/remove operation
    if (((struct pdu_router_key*) pdu)->flags == 1)
        rtval = spki_table_remove_entry(rtr_socket->spki_table, &entry);
    else if (((struct pdu_router_key*) pdu)->flags == 0)
        rtval = spki_table_add_entry(rtr_socket->spki_table, &entry);
    return rtval;
}
Exemplo n.º 6
0
/*
 * @brief Removes all Prefix from the pfx_table with flag field == ADD, ADDs all Prefix PDU to the pfx_table with flag
 * field == REMOVE.
 */
static int rtr_undo_update_pfx_table(struct rtr_socket *rtr_socket, void *pdu)
{
    const enum pdu_type type = rtr_get_pdu_type(pdu);
    assert(type == IPV4_PREFIX || type == IPV6_PREFIX);

    struct pfx_record pfxr;
    rtr_prefix_pdu_2_pfx_record(rtr_socket, pdu, &pfxr, type);

    int rtval = RTR_ERROR;
    //invert add/remove operation
    if (((struct pdu_ipv4 *) pdu)->flags == 1)
        rtval = pfx_table_remove(rtr_socket->pfx_table, &pfxr);
    else if (((struct pdu_ipv4 *) pdu)->flags == 0)
        rtval = pfx_table_add(rtr_socket->pfx_table, &pfxr);
    return rtval;
}
Exemplo n.º 7
0
static int rtr_update_spki_table(struct rtr_socket* rtr_socket, const void* pdu)
{
    const enum pdu_type type = rtr_get_pdu_type(pdu);
    assert(type == ROUTER_KEY);

    struct spki_record entry;

    size_t pdu_size = sizeof(struct pdu_router_key);
    rtr_key_pdu_2_spki_record(rtr_socket, pdu, &entry,type);

    int rtval;
    if (((struct pdu_router_key*) pdu)->flags == 1)
        rtval = spki_table_add_entry(rtr_socket->spki_table, &entry);

    else if (((struct pdu_router_key*) pdu)->flags == 0)
        rtval = spki_table_remove_entry(rtr_socket->spki_table, &entry);

    else {
        const char txt[] = "Router Key PDU with invalid flags value received";
        RTR_DBG("%s", txt);
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, CORRUPT_DATA, txt, sizeof(txt));
        return RTR_ERROR;
    }

    if (rtval == SPKI_DUPLICATE_RECORD) {
        //TODO: This debug message isn't working yet, how to display SKI/SPKI without %x?
        RTR_DBG("Duplicate Announcement for router key: ASN: %u received",entry.asn);
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, DUPLICATE_ANNOUNCEMENT , NULL, 0);
        rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
        return RTR_ERROR;
    } else if (rtval == SPKI_RECORD_NOT_FOUND) {
        RTR_DBG1("Withdrawal of unknown router key");
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, WITHDRAWAL_OF_UNKNOWN_RECORD, NULL, 0);
        rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
        return RTR_ERROR;
    } else if (rtval == SPKI_ERROR) {
        const char txt[] = "spki_table Error";
        RTR_DBG("%s", txt);
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, INTERNAL_ERROR, txt, sizeof(txt));
        rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
        return RTR_ERROR;
    }

    return RTR_SUCCESS;
}
Exemplo n.º 8
0
static int rtr_update_pfx_table(struct rtr_socket *rtr_socket, const void *pdu)
{
    const enum pdu_type type = rtr_get_pdu_type(pdu);
    assert(type == IPV4_PREFIX || type == IPV6_PREFIX);

    struct pfx_record pfxr;
    size_t pdu_size = (type == IPV4_PREFIX ? sizeof(struct pdu_ipv4) : sizeof(struct pdu_ipv6));
    rtr_prefix_pdu_2_pfx_record(rtr_socket, pdu, &pfxr, type);

    int rtval;
    if (((struct pdu_ipv4 *) pdu)->flags == 1)
        rtval = pfx_table_add(rtr_socket->pfx_table, &pfxr);
    else if (((struct pdu_ipv4 *) pdu)->flags == 0)
        rtval = pfx_table_remove(rtr_socket->pfx_table, &pfxr);
    else {
        const char txt[] = "Prefix PDU with invalid flags value received";
        RTR_DBG("%s", txt);
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, CORRUPT_DATA, txt, sizeof(txt));
        return RTR_ERROR;
    }

    if (rtval == PFX_DUPLICATE_RECORD) {
        char ip[INET6_ADDRSTRLEN];
        lrtr_ip_addr_to_str(&(pfxr.prefix), ip, INET6_ADDRSTRLEN);
        RTR_DBG("Duplicate Announcement for record: %s/%u-%u, ASN: %u, received", ip, pfxr.min_len, pfxr.max_len, pfxr.asn);
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, DUPLICATE_ANNOUNCEMENT , NULL, 0);
        rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
        return RTR_ERROR;
    } else if (rtval == PFX_RECORD_NOT_FOUND) {
        RTR_DBG1("Withdrawal of unknown record");
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, WITHDRAWAL_OF_UNKNOWN_RECORD, NULL, 0);
        rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
        return RTR_ERROR;
    } else if (rtval == PFX_ERROR) {
        const char txt[] = "PFX_TABLE Error";
        RTR_DBG("%s", txt);
        rtr_send_error_pdu(rtr_socket, pdu, pdu_size, INTERNAL_ERROR, txt, sizeof(txt));
        rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
        return RTR_ERROR;
    }

    return RTR_SUCCESS;
}
Exemplo n.º 9
0
static void rtr_pdu_to_network_byte_order(void *pdu)
{
    struct pdu_header *header = pdu;
    struct pdu_error *err_pdu = NULL;

    header->reserved = htons(header->reserved);
    header->len = htonl(header->len);

    const enum pdu_type type = rtr_get_pdu_type(pdu);
    switch (type) {
    case SERIAL_QUERY:
        ((struct pdu_serial_query *) pdu)->sn = htonl(((struct pdu_serial_query *) pdu)->sn);
        break;
    case ERROR:
        err_pdu = pdu;
        *((uint32_t *)(err_pdu->rest + err_pdu->len_enc_pdu)) =
            htonl(*((uint32_t *)(err_pdu->rest + err_pdu->len_enc_pdu)));
        err_pdu->len_enc_pdu = htonl(err_pdu->len_enc_pdu);
        break;
    default:
        break;
    }
}
Exemplo n.º 10
0
static int rtr_store_router_key_pdu(struct rtr_socket *rtr_socket, const void *pdu, const unsigned int pdu_size,
				    struct pdu_router_key **ary, unsigned int *ind, unsigned int *size)
{
    assert(rtr_get_pdu_type(pdu) == ROUTER_KEY);

    if ((*ind) >= *size) {
        *size += TEMPORARY_PDU_STORE_INCREMENT_VALUE;
        void *tmp = realloc(*ary, *size * pdu_size);
        if (tmp == NULL) {
            const char txt[] = "Realloc failed";
            RTR_DBG("%s", txt);
            rtr_send_error_pdu(rtr_socket, pdu, pdu_size, INTERNAL_ERROR, txt, sizeof(txt));
            rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
            free(*ary);
            ary = NULL;
            return RTR_ERROR;
        }
        *ary = tmp;
    }

    memcpy((struct pdu_router_key *) *ary + *ind, pdu, pdu_size);
    (*ind)++;
    return RTR_SUCCESS;
}
Exemplo n.º 11
0
int rtr_wait_for_sync(struct rtr_socket *rtr_socket)
{
    char pdu[RTR_MAX_PDU_LEN];

    time_t cur_time;
    lrtr_get_monotonic_time(&cur_time);
    time_t wait = (rtr_socket->last_update +rtr_socket->refresh_interval) - cur_time;
    if (wait < 0)
        wait = 0;

    RTR_DBG("waiting %jd sec. till next sync", (intmax_t) wait);
    const int rtval = rtr_receive_pdu(rtr_socket, pdu, sizeof(pdu), wait);
    if (rtval >= 0) {
        enum pdu_type type = rtr_get_pdu_type(pdu);
        if (type == SERIAL_NOTIFY) {
            RTR_DBG1("Serial Notify received");
            return RTR_SUCCESS;
        }
    } else if (rtval == TR_WOULDBLOCK) {
        RTR_DBG1("Refresh interval expired");
        return RTR_SUCCESS;
    }
    return RTR_ERROR;
}
Exemplo n.º 12
0
int rtr_sync_receive_and_store_pdus(struct rtr_socket *rtr_socket){
    char pdu[RTR_MAX_PDU_LEN];
    enum pdu_type type;
    int retval = RTR_SUCCESS;

    struct pdu_ipv6 *ipv6_pdus = NULL;
    unsigned int ipv6_pdus_nindex = 0; //next free index in ipv6_pdus
    unsigned int ipv6_pdus_size = 0;

    struct pdu_ipv4 *ipv4_pdus = NULL;
    unsigned int ipv4_pdus_size = 0; //next free index in ipv4_pdus
    unsigned int ipv4_pdus_nindex = 0;

    struct pdu_router_key *router_key_pdus = NULL;
    unsigned int router_key_pdus_size = 0;
    unsigned int router_key_pdus_nindex = 0;

    //receive LRTR_IPV4/IPV6 PDUs till EOD
    do {
        retval = rtr_receive_pdu(rtr_socket, pdu, RTR_MAX_PDU_LEN, RTR_RECV_TIMEOUT);
        if (retval == TR_WOULDBLOCK) {
            rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT);
            retval = RTR_ERROR;
            goto cleanup;
        } else if (retval < 0) {
            retval = RTR_ERROR;
            goto cleanup;
        }

        type = rtr_get_pdu_type(pdu);
        if (type == IPV4_PREFIX) {
            if (rtr_store_prefix_pdu(rtr_socket, pdu, sizeof(*ipv4_pdus), (void **) &ipv4_pdus, &ipv4_pdus_nindex, &ipv4_pdus_size) == RTR_ERROR){
                rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                retval = RTR_ERROR;
                goto cleanup;
            }
        } else if (type == IPV6_PREFIX) {
            if (rtr_store_prefix_pdu(rtr_socket, pdu, sizeof(*ipv6_pdus), (void **) &ipv6_pdus, &ipv6_pdus_nindex, &ipv6_pdus_size) == RTR_ERROR){
                rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                retval = RTR_ERROR;
                goto cleanup;
            }
        } else if (type == ROUTER_KEY) {
            if (rtr_store_router_key_pdu(rtr_socket, pdu, sizeof(*router_key_pdus), &router_key_pdus, &router_key_pdus_nindex, &router_key_pdus_size) == RTR_ERROR){
                rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                retval = RTR_ERROR;
                goto cleanup;
            }
        } else if (type == EOD) {
            RTR_DBG1("EOD PDU received.");
            struct pdu_end_of_data_v0 *eod_pdu = (struct pdu_end_of_data_v0 *) pdu;

            if (eod_pdu->session_id != rtr_socket->session_id) {
                char txt[67];
                snprintf(txt, sizeof(txt),"Expected session_id: %u, received session_id. %u in EOD PDU",rtr_socket->session_id, eod_pdu->session_id);
                rtr_send_error_pdu(rtr_socket, pdu, RTR_MAX_PDU_LEN, CORRUPT_DATA, txt, strlen(txt) + 1);
                rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                retval = RTR_ERROR;
                goto cleanup;
            }

            if (eod_pdu->ver == RTR_PROTOCOL_VERSION_1) {
                rtr_socket->expire_interval = ((struct pdu_end_of_data_v1 *) pdu)->expire_interval;
                rtr_socket->refresh_interval = ((struct pdu_end_of_data_v1 *) pdu)->refresh_interval;
                rtr_socket->retry_interval = ((struct pdu_end_of_data_v1 *) pdu)->retry_interval;
                RTR_DBG("New interval values: expire_interval:%u, refresh_interval:%u, retry_interval:%u",
                        rtr_socket->expire_interval, rtr_socket->refresh_interval, rtr_socket->retry_interval);
            }

            int retval = PFX_SUCCESS;
            //add all IPv4 prefix pdu to the pfx_table
            for (unsigned int i = 0; i < ipv4_pdus_nindex; i++) {
                if (rtr_update_pfx_table(rtr_socket, &(ipv4_pdus[i])) == PFX_ERROR) {
                    //undo all record updates, except the last which produced the error
                    RTR_DBG("Error during data synchronisation, recovering Serial Nr. %u state",rtr_socket->serial_number);
                    for (unsigned int j = 0; j < i && retval == PFX_SUCCESS; j++)
                        retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv4_pdus[j]));
                    if (retval == RTR_ERROR) {
                        RTR_DBG1("Couldn't undo all update operations from failed data synchronisation: Purging all records");
                        pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket);
                        rtr_socket->request_session_id = true;
                    }
                    rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                    retval = RTR_ERROR;
                    goto cleanup;
                }
            }
            //add all IPv6 prefix pdu to the pfx_table
            for (unsigned int i = 0; i < ipv6_pdus_nindex; i++) {
                if (rtr_update_pfx_table(rtr_socket, &(ipv6_pdus[i])) == PFX_ERROR) {
                    //undo all record updates if error occured
                    RTR_DBG("Error during data synchronisation, recovering Serial Nr. %u state",rtr_socket->serial_number);
                    for (unsigned int j = 0; j < ipv4_pdus_nindex && retval == PFX_SUCCESS; j++)
                        retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv4_pdus[j]));
                    for (unsigned int j = 0; j < i && retval == PFX_SUCCESS; j++)
                        retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv6_pdus[j]));
                    if (retval == PFX_ERROR) {
                        RTR_DBG1("Couldn't undo all update operations from failed data synchronisation: Purging all records");
                        pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket);
                        rtr_socket->request_session_id = true;
                    }
                    rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                    retval = RTR_ERROR;
                    goto cleanup;
                }
            }

            //add all router key pdu to the spki_table
            for (unsigned int i = 0; i < router_key_pdus_nindex; i++) {
                if (rtr_update_spki_table(rtr_socket, &(router_key_pdus[i])) == SPKI_ERROR) {
                    RTR_DBG("Error during router key data synchronisation, recovering Serial Nr. %u state",rtr_socket->serial_number);
                    for (unsigned int j = 0; j < ipv4_pdus_nindex && retval == PFX_SUCCESS; j++)
                        retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv4_pdus[j]));
                    for (unsigned int j = 0; j < ipv6_pdus_nindex && retval == PFX_SUCCESS; j++)
                        retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv6_pdus[j]));
		     // cppcheck-suppress duplicateExpression
                    for (unsigned int j = 0; j < i && (retval == PFX_SUCCESS || retval == SPKI_SUCCESS); j++)
                        retval = rtr_undo_update_spki_table(rtr_socket, &(router_key_pdus[j]));
		     // cppcheck-suppress duplicateExpression
                    if (retval == RTR_ERROR || retval == SPKI_ERROR) {
                        RTR_DBG1("Couldn't undo all update operations from failed data synchronisation: Purging all key entries");
                        spki_table_src_remove(rtr_socket->spki_table, rtr_socket);
                        rtr_socket->request_session_id = true;
                    }
                    rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
                    retval = RTR_ERROR;
                    goto cleanup;
                }
            }
            rtr_socket->serial_number = eod_pdu->sn;
            RTR_DBG("Sync successfull, received %u Prefix PDUs, %u Router Key PDUs, session_id: %u, SN: %u", (ipv4_pdus_nindex + ipv6_pdus_nindex), router_key_pdus_nindex,rtr_socket->session_id,rtr_socket->serial_number);
            goto cleanup;
        } else if (type == ERROR) {
            rtr_handle_error_pdu(rtr_socket, pdu);
            retval = RTR_ERROR;
            goto cleanup;
        } else if (type == SERIAL_NOTIFY) {
            RTR_DBG1("Ignoring Serial Notify");
        } else {
            RTR_DBG("Received unexpected PDU (Type: %u)", ((struct pdu_header *) pdu)->type);
            const char txt[] = "Unexpected PDU received during data synchronisation";
            rtr_send_error_pdu(rtr_socket, pdu, sizeof(struct pdu_header), CORRUPT_DATA, txt, sizeof(txt));
            retval = RTR_ERROR;
            goto cleanup;
        }
    } while (type != EOD);

    cleanup:
    free(router_key_pdus);
    free(ipv6_pdus);
    free(ipv4_pdus);
    return retval;
}
Exemplo n.º 13
0
/*
 * Check if the PDU is big enough for the PDU type it
 * pretend to be.
 * @param pdu A pointer to a PDU that is at least pdu->len byte large.
 * @return False if the check fails, else true
 */
static bool rtr_pdu_check_size (const struct pdu_header *pdu) {
  const enum pdu_type type = rtr_get_pdu_type(pdu);
  const struct pdu_error * err_pdu = NULL;
  bool retval = false;
  uint64_t min_size = 0;

  switch (type) {
  case SERIAL_NOTIFY:
    if (sizeof(struct pdu_serial_notify) == pdu->len)
      retval = true;
  case CACHE_RESPONSE:
    if (sizeof(struct pdu_cache_response) == pdu->len)
      retval = true;
    break;
  case IPV4_PREFIX:
    if (sizeof(struct pdu_ipv4) == pdu->len)
      retval = true;
    break;
  case IPV6_PREFIX:
    if (sizeof(struct pdu_ipv6) == pdu->len)
      retval = true;
    break;
  case EOD:
    if ((pdu->ver == RTR_PROTOCOL_VERSION_0
         && (sizeof(struct pdu_end_of_data_v0) == pdu->len))
         ||
         (pdu->ver == RTR_PROTOCOL_VERSION_1
         && (sizeof(struct pdu_end_of_data_v1) == pdu->len)
         )){
        retval = true;
    }
    break;
  case CACHE_RESET:
    if (sizeof(struct pdu_header) == pdu->len)
      retval = true;
    break;
  case ROUTER_KEY:
    if (sizeof(struct pdu_router_key) == pdu->len)
        retval = true;
    break;
  case ERROR:
    err_pdu = (const struct pdu_error *) pdu;
    // +4 because of the "Length of Error Text" field
    min_size = 4 + sizeof(struct pdu_error);
    if (err_pdu->len < min_size) {
      RTR_DBG1("PDU is too small to contain \"Length of Error Text\" field!");
      break;
    }

    //Check if the PDU really contains the error PDU
    uint32_t enc_pdu_len = ntohl(err_pdu->len_enc_pdu);
    RTR_DBG("enc_pdu_len: %u", enc_pdu_len);
    min_size += enc_pdu_len;
    if (err_pdu->len < min_size) {
      RTR_DBG1("PDU is too small to contain erroneous PDU!");
      break;
    }

    //Check if the the PDU really contains the error msg
    uint32_t err_msg_len = ntohl(*((uint32_t *)(err_pdu->rest + enc_pdu_len)));
    RTR_DBG("err_msg_len: %u", err_msg_len);
    min_size += err_msg_len;
    if (err_pdu->len != min_size) {
      RTR_DBG1("PDU is too small to contain error_msg!");
      break;
    }

    if ((err_msg_len > 0) && (((uint8_t*)err_pdu)[min_size-1] != 0)) {
        RTR_DBG1("Error msg is not null terminated!");
        break;
    }
    retval = true;
    break;
  case SERIAL_QUERY:
    if (sizeof(struct pdu_serial_query) == pdu->len)
      retval = true;
    break;
  case RESET_QUERY:
    if (sizeof(struct pdu_reset_query) == pdu->len)
      retval = true;
    break;
  case RESERVED:
  default:
    RTR_DBG1("PDU type is unknown or reserved!");
    retval = false;
    break;
  }

#ifndef NDEBUG
  if (!retval) {
    RTR_DBG1("Received malformed PDU!");
  }
#endif

  return retval;
}
Exemplo n.º 14
0
int rtr_sync(struct rtr_socket *rtr_socket)
{
    char pdu[RTR_MAX_PDU_LEN];
    int rtval = rtr_receive_pdu(rtr_socket, pdu, RTR_MAX_PDU_LEN, RTR_RECV_TIMEOUT);
    //If the cache has closed the connection and we dont have a session_id
    //(no packages where exchanged) we should downgrade.
    if(rtval == TR_CLOSED && rtr_socket->request_session_id){
        RTR_DBG1("The cache server closed the connection and we have no session_id!");
        if (rtr_socket->version > RTR_PROTOCOL_MIN_SUPPORTED_VERSION)
        {
            RTR_DBG("Downgrading from %i to version %i", rtr_socket->version, rtr_socket->version-1);
            rtr_socket->version = rtr_socket->version - 1;
            rtr_change_socket_state(rtr_socket, RTR_FAST_RECONNECT);
            return RTR_ERROR;
        }
    }
    if (rtval == TR_WOULDBLOCK) {
        rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT);
        return RTR_ERROR;
    } else if (rtval < 0)
        return RTR_ERROR;

    enum pdu_type type = rtr_get_pdu_type(pdu);
    //ignore serial_notify PDUs, we already sent a serial_query, must be old messages
    while (type == SERIAL_NOTIFY) {
        RTR_DBG1("Ignoring Serial Notify");
        rtval = rtr_receive_pdu(rtr_socket, pdu, RTR_MAX_PDU_LEN, RTR_RECV_TIMEOUT);
        if (rtval == TR_WOULDBLOCK) {
            rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT);
            return RTR_ERROR;
        } else if (rtval < 0)
            return RTR_ERROR;
        type = rtr_get_pdu_type(pdu);
    }

    if (type == ERROR) {
        rtr_handle_error_pdu(rtr_socket, pdu);
        return RTR_ERROR;
    } else if (type == CACHE_RESET) {
        RTR_DBG1("Cache Reset PDU received");
        rtr_change_socket_state(rtr_socket, RTR_ERROR_NO_INCR_UPDATE_AVAIL);
        return RTR_ERROR;
    } else if (type == CACHE_RESPONSE) {
        rtr_handle_cache_response_pdu(rtr_socket,pdu);
    } else if (type == ERROR) {
        rtr_handle_error_pdu(rtr_socket, pdu);
        return RTR_ERROR;
    } else {
        RTR_DBG("Expected Cache Response PDU but received PDU Type (Type: %u)", ((struct pdu_header *) pdu)->type);
        const char txt[] = "Unexpected PDU received in data synchronisation";
        rtr_send_error_pdu(rtr_socket, pdu, sizeof(struct pdu_header), CORRUPT_DATA, txt, sizeof(txt));
        return RTR_ERROR;
    }

    //Receive all PDUs until EOD PDU
    if(rtr_sync_receive_and_store_pdus(rtr_socket) == RTR_ERROR){
        return RTR_ERROR;
    }

    rtr_socket->request_session_id = false;
    if (rtr_set_last_update(rtr_socket) == RTR_ERROR)
        return RTR_ERROR;
    return RTR_SUCCESS;
}