/* * @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; }
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); }
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; } }
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); }
/* * @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; }
/* * @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; }
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; }
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; }
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; } }
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; }
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; }
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; }
/* * 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; }
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; }