From cb064f84c47b1064cf4111fe76866ec1ace9c5bf Mon Sep 17 00:00:00 2001 From: Pavel Tvrdik Date: Thu, 26 May 2016 13:45:47 +0200 Subject: [PATCH] RPKI: Accept and save BGPsec Router Keys from RPKI Adds support for receiving Router Key PDUs, saving it to disk. The path save repository is configurable by ./configure or BIRD's configuration file. --- Makefile.in | 1 + conf/conf.c | 1 + conf/conf.h | 1 + configure.in | 3 ++ nest/config.Y | 3 ++ proto/rpki/config.Y | 2 +- proto/rpki/packets.c | 70 +++++++++++++++++++++++++++++++++++++++++++- proto/rpki/rpki.h | 4 +++ 8 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 0f3cb36f..552e7a53 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,6 +108,7 @@ $(objdir)/sysdep/paths.h: Makefile echo >$@ "/* Generated by Makefile, don't edit manually! */" echo >>$@ "#define PATH_CONFIG_FILE \"@CONFIG_FILE@\"" echo >>$@ "#define PATH_CONTROL_SOCKET \"@CONTROL_SOCKET@\"" + echo >>$@ "#define PATH_RPKI_STATE_DIR \"@RPKI_STATE_DIR@\"" if test -n "@iproutedir@" ; then echo >>$@ "#define PATH_IPROUTE_DIR \"@iproutedir@\"" ; fi # Finally include the computed dependencies diff --git a/conf/conf.c b/conf/conf.c index 8d4d28e3..9e904858 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -104,6 +104,7 @@ config_alloc(byte *name) c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600}; c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0}; c->gr_wait = DEFAULT_GR_WAIT; + c->rpki_state_dir = PATH_RPKI_STATE_DIR; return c; } diff --git a/conf/conf.h b/conf/conf.h index 03fecd32..421e2b45 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -31,6 +31,7 @@ struct config { ip_addr listen_bgp_addr; /* Listening BGP socket should use this address */ unsigned listen_bgp_port; /* Listening BGP socket should use this port (0 is default) */ u32 listen_bgp_flags; /* Listening BGP socket should use these flags */ + const char *rpki_state_dir; /* File path to save Router Keys for RPKI */ unsigned proto_default_debug; /* Default protocol debug mask */ unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */ struct timeformat tf_route; /* Time format for 'show route' */ diff --git a/configure.in b/configure.in index e5e43e1b..b7dd0420 100644 --- a/configure.in +++ b/configure.in @@ -39,12 +39,15 @@ AC_SUBST(runtimedir) if test "$enable_debug" = yes ; then CONFIG_FILE="bird.conf" CONTROL_SOCKET="bird.ctl" + RPKI_STATE_DIR="rpki" else CONFIG_FILE="\$(sysconfdir)/bird.conf" CONTROL_SOCKET="$runtimedir/bird.ctl" + RPKI_STATE_DIR="\$(localstatedir)/rpki" fi AC_SUBST(CONFIG_FILE) AC_SUBST(CONTROL_SOCKET) +AC_SUBST(RPKI_STATE_DIR) AC_SEARCH_LIBS(clock_gettime, [c rt posix4], , AC_MSG_ERROR([[Function clock_gettime not available.]])) diff --git a/nest/config.Y b/nest/config.Y index 94a67670..04c4415e 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -457,7 +457,10 @@ password_item_params: | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); } ; +/* Overwrite RPKI State Dir for BGPSEC Router Keys */ +CF_ADDTO(conf, rpki_state_dir) +rpki_state_dir: RPKI STATE DIR text ';' { new_config->rpki_state_dir = $4; } /* Core commands */ CF_CLI_HELP(SHOW, ..., [[Show status information]]) diff --git a/proto/rpki/config.Y b/proto/rpki/config.Y index 0811649e..a0af7748 100644 --- a/proto/rpki/config.Y +++ b/proto/rpki/config.Y @@ -24,7 +24,7 @@ rpki_check_unused_hostname(void) CF_DECLS CF_KEYWORDS(RPKI, REMOTE, BIRD, PRIVATE, PUBLIC, KEY, SSH, ENCRYPTION, USER, - RETRY, REFRESH, EXPIRE) + RETRY, REFRESH, EXPIRE, STATE, DIR) CF_GRAMMAR diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c index 839cddd3..f6a5f77b 100644 --- a/proto/rpki/packets.c +++ b/proto/rpki/packets.c @@ -11,6 +11,7 @@ #include #include #include +#include #undef LOCAL_DEBUG @@ -142,6 +143,17 @@ struct pdu_error { uint8_t rest[]; }; +struct pdu_router_key { + uint8_t ver; + uint8_t type; + uint8_t flags; + uint8_t zero; + uint32_t len; + uint8_t ski[RPKI_SKI_SIZE]; + uint32_t asn; + uint8_t spki[RPKI_SPKI_SIZE]; +}; + struct pdu_reset_query { uint8_t ver; uint8_t type; @@ -328,6 +340,12 @@ rpki_pdu_body_to_host_byte_order(void *pdu) } case ROUTER_KEY: + { + struct pdu_router_key *rk = pdu; + rk->asn = ntohl(rk->asn); + break; + } + case SERIAL_QUERY: case RESET_QUERY: case CACHE_RESPONSE: @@ -373,6 +391,16 @@ rpki_log_packet(struct rpki_cache *cache, const void *pdu, const size_t len, con break; } + case ROUTER_KEY: + { + const struct pdu_router_key *rk = pdu; + bsnprintf(detail, sizeof(detail), "(AS%u %02x", rk->asn, rk->ski[0]); + for (const u8 *x = &rk->ski[1]; x < &rk->ski[RPKI_SKI_SIZE]; x++) + bsnprintf(detail+strlen(detail), sizeof(detail)-strlen(detail), ":%02x", *x); + bsnprintf(detail+strlen(detail), sizeof(detail)-strlen(detail), ")"); + break; + } + default: *detail = '\0'; } @@ -741,6 +769,43 @@ rpki_handle_prefix_pdu(struct rpki_cache *cache, const void *pdu) return RPKI_SUCCESS; } +static void +rpki_handle_router_key_pdu(struct rpki_cache *cache, const struct pdu_router_key *pdu) +{ + char file_name[4096]; /* PATH_MAX? */ + char ski_hex[41]; + const char *state_dir = config->rpki_state_dir; + int i; + int fd = -1; + + for (i = 0; i < 20; i++) + bsnprintf(ski_hex + i*2, sizeof(ski_hex) - i*2, "%02X", pdu->ski[i]); + + /* Check buffer size */ + size_t req_size = strlen(state_dir) + 2*sizeof(pdu->ski) + 2 + strlen(RPKI_ROUTER_KEY_EXT); + if (req_size >= sizeof(file_name)) + { + CACHE_TRACE(D_EVENTS, cache, "Buffer too small for %s/%u.%s" RPKI_ROUTER_KEY_EXT, state_dir, pdu->asn, ski_hex); + return; + } + + bsnprintf(file_name, sizeof(file_name), "%s/%u.%s" RPKI_ROUTER_KEY_EXT, state_dir, pdu->asn, ski_hex); + + fd = open(file_name, O_WRONLY|O_CREAT, 0664); + if (fd < 0) + { + CACHE_TRACE(D_EVENTS, cache, "Cannot open file %s for write router key", file_name); + return; + } + + if (write(fd, pdu->spki, RPKI_SPKI_SIZE) < 0) + CACHE_TRACE(D_EVENTS, cache, "Cannot write into %s", file_name); + else + CACHE_TRACE(D_EVENTS, cache, "Wrote router key into file %s", file_name); + + close(fd); +} + static uint rpki_check_interval(struct rpki_cache *cache, const char *(check_fn)(uint), uint interval) { @@ -837,6 +902,10 @@ rpki_rx_packet(struct rpki_cache *cache, void *pdu, uint len) rpki_handle_prefix_pdu(cache, pdu); break; + case ROUTER_KEY: + rpki_handle_router_key_pdu(cache, pdu); + break; + case END_OF_DATA: rpki_handle_end_of_data_pdu(cache, pdu); break; @@ -853,7 +922,6 @@ rpki_rx_packet(struct rpki_cache *cache, void *pdu, uint len) rpki_handle_error_pdu(cache, pdu); break; - case ROUTER_KEY: default: CACHE_TRACE(D_PACKETS, cache, "Received unsupported type of RPKI PDU: %u", type); }; diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h index c0115a92..7ba14cd3 100644 --- a/proto/rpki/rpki.h +++ b/proto/rpki/rpki.h @@ -32,6 +32,10 @@ #define RPKI_MIN_VERSION 0 #define RPKI_MAX_VERSION 1 +#define RPKI_SKI_SIZE 20 +#define RPKI_SPKI_SIZE 91 +#define RPKI_ROUTER_KEY_EXT ".key" + /* * Used in parsing of configuration file */