From fa65e063721d963a29749ad63e47c97b52ce98d8 Mon Sep 17 00:00:00 2001 From: Katerina Kubecova Date: Fri, 8 Nov 2024 15:26:37 +0100 Subject: [PATCH] RPKI: protocol version 2, loading ASPA Implemented draft-ietf-sidrops-8210bis-16, interoperable with StayRTR development branches. --- proto/rpki/packets.c | 113 +++++++++++++++++++++++++++++++++++++++++-- proto/rpki/packets.h | 6 ++- proto/rpki/rpki.c | 42 +++++++++++++++- proto/rpki/rpki.h | 7 ++- 4 files changed, 158 insertions(+), 10 deletions(-) diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c index d246dd500..de9e86195 100644 --- a/proto/rpki/packets.c +++ b/proto/rpki/packets.c @@ -62,6 +62,7 @@ enum pdu_type { CACHE_RESET = 8, ROUTER_KEY = 9, ERROR = 10, + ASPA = 11, PDU_TYPE_MAX }; @@ -76,7 +77,8 @@ static const char *str_pdu_type_[] = { [END_OF_DATA] = "End of Data", [CACHE_RESET] = "Cache Reset", [ROUTER_KEY] = "Router Key", - [ERROR] = "Error" + [ERROR] = "Error", + [ASPA] = "ASPA", }; static const char *str_pdu_type(uint type) { @@ -193,6 +195,35 @@ struct pdu_error { * Error Diagnostic Message */ } PACKED; +/* + *0 8 16 24 31 + * .-------------------------------------------. + * | Protocol | PDU | | | + * | Version | Type | Flags | zero | + * | 2 | 11 | | | + * +-------------------------------------------+ + * | | + * | Length | + * | | + * +-------------------------------------------+ + * | | + * | Customer Autonomous System Number | + * | | + * +-------------------------------------------+ + * | | + * ~ Provider Autonomous System Numbers ~ + * | | + * ~-------------------------------------------~ */ +struct pdu_aspa { + u8 ver; + u8 type; + u8 flags; + u8 zero; + u32 len; + u32 customer_as_num; + u32 provider_as_nums[0]; +} PACKED; + struct pdu_reset_query { u8 ver; u8 type; @@ -230,9 +261,13 @@ static const size_t min_pdu_size[] = { [END_OF_DATA] = sizeof(struct pdu_end_of_data_v0), [CACHE_RESET] = sizeof(struct pdu_cache_response), [ROUTER_KEY] = sizeof(struct pdu_header), /* FIXME */ + [ASPA] = sizeof(struct pdu_aspa), [ERROR] = 16, }; +static inline int rpki_pdu_aspa_provider_asn_count(const struct pdu_aspa *pdu) +{ return (pdu->len - sizeof(struct pdu_aspa)) / (sizeof(u32)); } + static int rpki_send_error_pdu(struct rpki_cache *cache, const enum pdu_error_type error_code, const u32 err_pdu_len, const struct pdu_header *erroneous_pdu, const char *fmt, ...); static void @@ -293,7 +328,7 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu) struct pdu_end_of_data_v0 *eod0 = (void *) pdu; eod0->serial_num = ntohl(eod0->serial_num); /* Same either for version 1 */ - if (pdu->ver == RPKI_VERSION_1) + if (pdu->ver > RPKI_VERSION_0) { struct pdu_end_of_data_v1 *eod1 = (void *) pdu; eod1->expire_interval = ntohl(eod1->expire_interval); @@ -329,6 +364,21 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu) break; } + case ASPA: + { + struct pdu_aspa *aspa = (void *) pdu; + int provider_asn_count = rpki_pdu_aspa_provider_asn_count(aspa); + + /* Convert customer ASN */ + aspa->customer_as_num = ntohl(aspa->customer_as_num); + + /* Convert provider ASNs */ + for (int i = 0; i < provider_asn_count ; i++) + aspa->provider_as_nums[i] = ntohl(aspa->provider_as_nums[i]); + + break; + } + case ROUTER_KEY: /* Router Key PDU is not supported yet */ @@ -354,6 +404,9 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu) static struct pdu_header * rpki_pdu_back_to_network_byte_order(struct pdu_header *out, const struct pdu_header *in) { + /* Only valid for fixed-length PDUs */ + ASSERT_DIE(in->type != ERROR && in->type != ASPA); + memcpy(out, in, in->len); rpki_pdu_to_host_byte_order(out); return out; @@ -387,7 +440,7 @@ rpki_log_packet(struct rpki_cache *cache, const struct pdu_header *pdu, const en case END_OF_DATA: { const struct pdu_end_of_data_v1 *eod = (void *) pdu; - if (eod->ver == RPKI_VERSION_1) + if (eod->ver > RPKI_VERSION_0) SAVE(bsnprintf(detail, sizeof(detail), "(session id: %u, serial number: %u, refresh: %us, retry: %us, expire: %us)", eod->session_id, eod->serial_num, eod->refresh_interval, eod->retry_interval, eod->expire_interval)); else SAVE(bsnprintf(detail, sizeof(detail), "(session id: %u, serial number: %u)", eod->session_id, eod->serial_num)); @@ -455,6 +508,25 @@ rpki_log_packet(struct rpki_cache *cache, const struct pdu_header *pdu, const en break; } + case ASPA: + { + const struct pdu_aspa *aspa = (void *) pdu; + int provider_asn_count = rpki_pdu_aspa_provider_asn_count(aspa); + + if (provider_asn_count <= 0) + SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), + "%u transit", aspa->customer_as_num)); + else + { + SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), + "%u (providers", aspa->customer_as_num)); + for (int i = 0; i < provider_asn_count; i++) + SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), + " %u%c", aspa->provider_as_nums[i], (i == provider_asn_count-1) ? ')' : ',')); + } + break; + } + default: *detail = '\0'; } @@ -571,7 +643,9 @@ rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu } } - if ((pdu->type >= PDU_TYPE_MAX) || (pdu->ver == RPKI_VERSION_0 && pdu->type == ROUTER_KEY)) + if ((pdu->type >= PDU_TYPE_MAX) || + (pdu->ver < RPKI_VERSION_1 && pdu->type == ROUTER_KEY) || + (pdu->ver < RPKI_VERSION_2 && pdu->type == ASPA)) { rpki_send_error_pdu(cache, UNSUPPORTED_PDU_TYPE, pdu_len, pdu, "Unsupported PDU type %u received", pdu->type); return RPKI_ERROR; @@ -797,6 +871,29 @@ rpki_handle_prefix_pdu(struct rpki_cache *cache, const struct pdu_header *pdu) return RPKI_SUCCESS; } +static int +rpki_handle_aspa_pdu(struct rpki_cache *cache, const struct pdu_header *pdu) +{ + struct pdu_aspa *aspa = (void *) pdu; + struct channel *channel = cache->p->aspa_channel; + uint providers_length = aspa->len - sizeof(struct pdu_aspa); + + if (!channel) + { + CACHE_TRACE(D_ROUTES, cache, "Skip AS%u, missing aspa channel", aspa->customer_as_num); + return RPKI_ERROR; + } + + cache->last_rx_prefix = current_time(); + + if (aspa->flags & RPKI_ADD_FLAG) + rpki_table_add_aspa(cache, channel, aspa->customer_as_num, aspa->provider_as_nums, providers_length); + else + rpki_table_remove_aspa(cache, channel, aspa->customer_as_num); + + return RPKI_SUCCESS; +} + static uint rpki_check_interval(struct rpki_cache *cache, const char *(check_fn)(uint), uint interval) { @@ -822,7 +919,7 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da return; } - if (pdu->ver == RPKI_VERSION_1) + if (pdu->ver > RPKI_VERSION_0) { if (!cf->keep_refresh_interval && rpki_check_interval(cache, rpki_check_refresh_interval, pdu->refresh_interval)) cache->refresh_interval = pdu->refresh_interval; @@ -849,6 +946,8 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da rt_refresh_end(cache->p->roa4_channel->table, cache->p->roa4_channel); if (cache->p->roa6_channel) rt_refresh_end(cache->p->roa6_channel->table, cache->p->roa6_channel); + if (cache->p->aspa_channel) + rt_refresh_end(cache->p->aspa_channel->table, cache->p->aspa_channel); } cache->last_update = current_time(); @@ -913,6 +1012,10 @@ rpki_rx_packet(struct rpki_cache *cache, struct pdu_header *pdu) /* TODO: Implement Router Key PDU handling */ break; + case ASPA: + rpki_handle_aspa_pdu(cache, (void *) pdu); + break; + default: CACHE_TRACE(D_PACKETS, cache, "Received unsupported type (%u)", pdu->type); }; diff --git a/proto/rpki/packets.h b/proto/rpki/packets.h index d6f8a249b..f7897d9af 100644 --- a/proto/rpki/packets.h +++ b/proto/rpki/packets.h @@ -23,8 +23,10 @@ * +4 bytes (Length of inserted text) * +800 bytes (UTF-8 text 400*2 bytes) * ------------ - * = 848 bytes (Maximal expected PDU size) */ -#define RPKI_PDU_MAX_LEN 848 + * = 848 bytes (Maximal expected PDU size) + * + * Received ASPA PDU can have any size, so let's start with 4k */ +#define RPKI_PDU_MAX_LEN 4096 /* RX buffer size has a great impact to scheduler granularity */ #define RPKI_RX_BUFFER_SIZE 4096 diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index cbd94492d..e9d2a60aa 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -140,6 +140,37 @@ rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const n rte_update2(channel, &pfxr->n, NULL, p->p.main_source); } +void +rpki_table_add_aspa(struct rpki_cache *cache, struct channel *channel, + u32 customer, void *providers, uint providers_length) +{ + struct rpki_proto *p = cache->p; + + net_addr_union n = { .aspa = NET_ADDR_ASPA(customer) }; + rta a0 = { + .pref = channel->preference, + .source = RTS_RPKI, + .scope = SCOPE_UNIVERSE, + .dest = RTD_NONE, + }; + + ea_set_attr_data(&a0.eattrs, tmp_linpool, EA_ASPA_PROVIDERS, 0, + EAF_TYPE_INT_SET, providers, providers_length); + + rta *a = rta_lookup(&a0); + rte *e = rte_get_temp(a, p->p.main_source); + + rte_update2(channel, &n.n, e, e->src); +} + +void +rpki_table_remove_aspa(struct rpki_cache *cache, struct channel *channel, u32 customer) +{ + struct rpki_proto *p = cache->p; + net_addr_union n = { .aspa = NET_ADDR_ASPA(customer) }; + rte_update2(channel, &n.n, NULL, p->p.main_source); +} + /* * RPKI Protocol Logic @@ -773,7 +804,8 @@ rpki_reconfigure(struct proto *P, struct proto_config *CF) struct rpki_cache *cache = p->cache; if (!proto_configure_channel(&p->p, &p->roa4_channel, proto_cf_find_channel(CF, NET_ROA4)) || - !proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6))) + !proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6)) || + !proto_configure_channel(&p->p, &p->aspa_channel, proto_cf_find_channel(CF, NET_ASPA))) return NEED_RESTART; if (rpki_reconfigure_cache(p, cache, new, old) != SUCCESSFUL_RECONF) @@ -795,6 +827,7 @@ rpki_init(struct proto_config *CF) proto_configure_channel(&p->p, &p->roa4_channel, proto_cf_find_channel(CF, NET_ROA4)); proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6)); + proto_configure_channel(&p->p, &p->aspa_channel, proto_cf_find_channel(CF, NET_ASPA)); return P; } @@ -908,6 +941,11 @@ rpki_show_proto_info(struct proto *P) channel_show_info(p->roa6_channel); else cli_msg(-1006, " No roa6 channel"); + + if (p->aspa_channel) + channel_show_info(p->aspa_channel); + else + cli_msg(-1006, " No aspa channel"); } } @@ -979,7 +1017,7 @@ struct protocol proto_rpki = { .init = rpki_init, .start = rpki_start, .postconfig = rpki_postconfig, - .channel_mask = (NB_ROA4 | NB_ROA6), + .channel_mask = (NB_ROA4 | NB_ROA6 | NB_ASPA), .show_proto_info = rpki_show_proto_info, .shutdown = rpki_shutdown, .copy_config = rpki_copy_config, diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h index e67eb0e3b..307ec315a 100644 --- a/proto/rpki/rpki.h +++ b/proto/rpki/rpki.h @@ -29,7 +29,8 @@ #define RPKI_VERSION_0 0 #define RPKI_VERSION_1 1 -#define RPKI_MAX_VERSION RPKI_VERSION_1 +#define RPKI_VERSION_2 2 +#define RPKI_MAX_VERSION RPKI_VERSION_2 /* @@ -83,6 +84,9 @@ const char *rpki_cache_state_to_str(enum rpki_cache_state state); void rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr); void rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr); +void rpki_table_add_aspa(struct rpki_cache *cache, struct channel *channel, u32 customer, void *providers, uint providers_length); +void rpki_table_remove_aspa(struct rpki_cache *cache, struct channel *channel, u32 customer); + /* * RPKI Protocol Logic @@ -110,6 +114,7 @@ struct rpki_proto { struct channel *roa4_channel; struct channel *roa6_channel; + struct channel *aspa_channel; u8 refresh_channels; /* For non-incremental updates using rt_refresh_begin(), rt_refresh_end() */ }; -- 2.47.2