From 043cff5286f63dd62b7aaf9f4a0d7deaef5659db Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 16 May 2024 23:27:34 +0300 Subject: [PATCH] bgpd: Split `rpki cache` command into separate per SSH/TCP Current command (bundled two into one) is absolutely wrong. When you configure TCP session with the source, the command thinks, that it's a SSH session with a username. It's much better to split this into two separate commands where it's much easier to do the changes in the future (if more options comes in). Yes, this is a breaking change, but there is no other proper way to overcome this. Bonus note how it looks, which also can lead to crashes (due to port 0x0): ``` (gdb) p *cache->tr_config.ssh_config $11 = {host = 0x5555562f9cd0 "1.1.1.1", port = 0, bindaddr = 0x0, username = 0x55555629ad00 "", server_hostkey_path = 0x7ffff53667a0 "Uf\017\357\300H\211\345AWAVAUATSH\201", , client_privkey_path = 0x0, data = 0x0, new_socket = 0x51, connect_timeout = 4143762592, password = 0x7ffff6fccca0 "\300\"0VUU"} (gdb) p *cache->tr_config.tcp_config $12 = {host = 0x5555562f9cd0 "1.1.1.1", port = 0x0, bindaddr = 0x0, data = 0x55555629ad00, new_socket = 0x7ffff53667a0 , connect_timeout = 0} ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_rpki.c | 165 +++++++++++++++++- doc/user/rpki.rst | 25 +-- tests/topotests/bgp_rpki_topo1/r2/bgpd.conf | 2 +- .../bgp_rpki_topo1/test_bgp_rpki_topo1.py | 6 +- 4 files changed, 173 insertions(+), 25 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 67f59edb93..08a7e1896f 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1621,7 +1621,7 @@ static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) #endif case TCP: tcp_config = cache->tr_config.tcp_config; - vty_out(vty, "%s rpki cache %s %s ", sep, + vty_out(vty, "%s rpki cache tcp %s %s ", sep, tcp_config->host, tcp_config->port); if (tcp_config->bindaddr) vty_out(vty, "source %s ", @@ -1630,7 +1630,7 @@ static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) #if defined(FOUND_SSH) case SSH: ssh_config = cache->tr_config.ssh_config; - vty_out(vty, "%s rpki cache %s %u %s %s %s ", sep, + vty_out(vty, "%s rpki cache ssh %s %u %s %s %s ", sep, ssh_config->host, ssh_config->port, ssh_config->username, ssh_config->client_privkey_path, @@ -1918,6 +1918,9 @@ DEFUN (no_rpki_retry_interval, return CMD_SUCCESS; } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove rpki_cache_cmd") +#endif DEFPY(rpki_cache, rpki_cache_cmd, "rpki cache [source $bindaddr] preference (1-255)", RPKI_OUTPUT_STRING @@ -1990,12 +1993,136 @@ DEFPY(rpki_cache, rpki_cache_cmd, return CMD_SUCCESS; } +DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd, + "rpki cache tcp $cache TCPPORT [source $bindaddr] preference (1-255)", + RPKI_OUTPUT_STRING + "Install a cache server to current group\n" + "Use TCP\n" + "IP address of cache server\n" + "Hostname of cache server\n" + "TCP port number\n" + "Configure source IP address of RPKI connection\n" + "Define a Source IP Address\n" + "Preference of the cache server\n" + "Preference value\n") +{ + int return_value; + struct listnode *cache_node; + struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { + if (current_cache->preference == preference) { + vty_out(vty, + "Cache with preference %ld is already configured\n", + preference); + return CMD_WARNING; + } + } + + return_value = add_tcp_cache(rpki_vrf, cache, tcpport, preference, + bindaddr_str); + + if (return_value == ERROR) { + vty_out(vty, "Could not create new rpki cache\n"); + return CMD_WARNING; + } + + if (init) + start(rpki_vrf); + + return CMD_SUCCESS; +} + +DEFPY(rpki_cache_ssh, rpki_cache_ssh_cmd, + "rpki cache ssh $cache (1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY] [source $bindaddr] preference (1-255)", + RPKI_OUTPUT_STRING + "Install a cache server to current group\n" + "Use SSH\n" + "IP address of cache server\n" + "Hostname of cache server\n" + "SSH port number\n" + "SSH user name\n" + "Path to own SSH private key\n" + "Path to Public key of cache server\n" + "Configure source IP address of RPKI connection\n" + "Define a Source IP Address\n" + "Preference of the cache server\n" + "Preference value\n") +{ + int return_value; + struct listnode *cache_node; + struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { + if (current_cache->preference == preference) { + vty_out(vty, + "Cache with preference %ld is already configured\n", + preference); + return CMD_WARNING; + } + } + +#if defined(FOUND_SSH) + return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, + ssh_privkey, server_pubkey, preference, + bindaddr_str); +#else + return_value = SUCCESS; + vty_out(vty, + "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n"); +#endif + + if (return_value == ERROR) { + vty_out(vty, "Could not create new rpki cache\n"); + return CMD_WARNING; + } + + if (init) + start(rpki_vrf); + + return CMD_SUCCESS; +} + DEFPY (no_rpki_cache, no_rpki_cache_cmd, - "no rpki cache [source $bindaddr] preference (1-255)", + "no rpki cache [source $bindaddr] preference (1-255)", NO_STR RPKI_OUTPUT_STRING "Install a cache server to current group\n" + "Use TCP\n" + "Use SSH\n" "IP address of cache server\n" "Hostname of cache server\n" "TCP port number\n" @@ -2257,10 +2384,16 @@ DEFPY (show_rpki_cache_server, if (cache->type == TCP) { if (!json) { vty_out(vty, - "host: %s port: %s, preference: %hhu\n", + "host: %s port: %s, preference: %hhu, protocol: tcp", cache->tr_config.tcp_config->host, cache->tr_config.tcp_config->port, cache->preference); + if (cache->tr_config.tcp_config->bindaddr) + vty_out(vty, ", source: %s\n", + cache->tr_config.tcp_config + ->bindaddr); + else + vty_out(vty, "\n"); } else { json_server = json_object_new_object(); json_object_string_add(json_server, "mode", @@ -2273,6 +2406,12 @@ DEFPY (show_rpki_cache_server, cache->tr_config.tcp_config->port); json_object_int_add(json_server, "preference", cache->preference); + if (cache->tr_config.tcp_config->bindaddr) + json_object_string_add(json_server, + "source", + cache->tr_config + .tcp_config + ->bindaddr); json_object_array_add(json_servers, json_server); } @@ -2281,7 +2420,7 @@ DEFPY (show_rpki_cache_server, } else if (cache->type == SSH) { if (!json) { vty_out(vty, - "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s, preference: %hhu\n", + "host: %s, port: %d, username: %s, server_hostkey_path: %s, client_privkey_path: %s, preference: %hhu, protocol: ssh", cache->tr_config.ssh_config->host, cache->tr_config.ssh_config->port, cache->tr_config.ssh_config->username, @@ -2290,6 +2429,12 @@ DEFPY (show_rpki_cache_server, cache->tr_config.ssh_config ->client_privkey_path, cache->preference); + if (cache->tr_config.ssh_config->bindaddr) + vty_out(vty, ", source: %s\n", + cache->tr_config.ssh_config + ->bindaddr); + else + vty_out(vty, "\n"); } else { json_server = json_object_new_object(); json_object_string_add(json_server, "mode", @@ -2313,6 +2458,12 @@ DEFPY (show_rpki_cache_server, ->client_privkey_path); json_object_int_add(json_server, "preference", cache->preference); + if (cache->tr_config.ssh_config->bindaddr) + json_object_string_add(json_server, + "source", + cache->tr_config + .ssh_config + ->bindaddr); json_object_array_add(json_servers, json_server); } @@ -2665,6 +2816,8 @@ static void install_cli_commands(void) install_element(RPKI_NODE, &no_rpki_retry_interval_cmd); /* Install rpki cache commands */ + install_element(RPKI_NODE, &rpki_cache_tcp_cmd); + install_element(RPKI_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_NODE, &rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd); @@ -2687,6 +2840,8 @@ static void install_cli_commands(void) install_element(RPKI_VRF_NODE, &no_rpki_retry_interval_cmd); /* Install rpki cache commands */ + install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd); + install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_VRF_NODE, &rpki_cache_cmd); install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index fe9e407ca9..394327e2ff 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -131,19 +131,13 @@ The following commands are available for independent of a specific cache server. The default value is 600 seconds. -.. clicmd:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [KNOWN_HOSTS_PATH] [source A.B.C.D] preference (1-255) +.. clicmd:: rpki cache tcp HOST PORT [source A.B.C.D] preference (1-255) + Add a TCP cache server to the socket. - Add a cache server to the socket. By default, the connection between router - and cache server is based on plain TCP. Protecting the connection between - router and cache server by SSH is optional. Deleting a socket removes the - associated cache server and terminates the existing connection. +.. clicmd:: rpki cache ssh HOST PORT SSH_USERNAME SSH_PRIVKEY_PATH [SERVER_PUBKEY] [source A.B.C.D] preference (1-255) - A.B.C.D|WORD - Address of the cache server. - - PORT - Port number to connect to the cache server + Add a SSH cache server to the socket. SSH_USERNAME SSH username to establish an SSH connection to the cache server. @@ -151,7 +145,7 @@ The following commands are available for independent of a specific cache server. SSH_PRIVKEY_PATH Local path that includes the private key file of the router. - KNOWN_HOSTS_PATH + SERVER_PUBKEY Local path that includes the known hosts file. The default value depends on the configuration of the operating system environment, usually :file:`~/.ssh/known_hosts`. @@ -159,7 +153,6 @@ The following commands are available for independent of a specific cache server. source A.B.C.D Source address of the RPKI connection to access cache server. - .. _validating-bgp-updates: Validating BGP Updates @@ -267,9 +260,9 @@ RPKI Configuration Example rpki polling_period 1000 rpki timeout 10 ! SSH Example: - rpki cache example.com 22 rtr-ssh ./ssh_key/id_rsa preference 1 + rpki cache ssh example.com 22 rtr-ssh ./ssh_key/id_rsa preference 1 ! TCP Example: - rpki cache rpki-validator.realmv6.org 8282 preference 2 + rpki cache tcp rpki-validator.realmv6.org 8282 preference 2 exit ! exit-vrf @@ -278,9 +271,9 @@ RPKI Configuration Example rpki polling_period 1000 rpki timeout 10 ! SSH Example: - rpki cache example.com source 198.51.100.223 22 rtr-ssh ./ssh_key/id_rsa preference 1 + rpki cache ssh example.com source 198.51.100.223 22 rtr-ssh ./ssh_key/id_rsa preference 1 ! TCP Example: - rpki cache rpki-validator.realmv6.org 8282 preference 2 + rpki cache tcp rpki-validator.realmv6.org 8282 preference 2 exit ! router bgp 65001 diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf index 87d7214972..4de177dc25 100644 --- a/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf +++ b/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf @@ -21,5 +21,5 @@ router bgp 65002 vrf vrf10 ! rpki rpki retry_interval 5 - rpki cache 192.0.2.1 15432 preference 1 + rpki cache tcp 192.0.2.1 15432 preference 1 exit diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py index a12204f240..f52b28a062 100644 --- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py +++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py @@ -189,7 +189,7 @@ def test_show_bgp_rpki_prefixes_no_rpki_cache(): """ configure rpki - no rpki cache 192.0.2.1 15432 preference 1 + no rpki cache tcp 192.0.2.1 15432 preference 1 exit """ ) @@ -219,7 +219,7 @@ def test_show_bgp_rpki_prefixes_reconnect(): """ configure rpki - rpki cache 192.0.2.1 15432 preference 1 + rpki cache tcp 192.0.2.1 15432 preference 1 exit """ ) @@ -319,7 +319,7 @@ def test_show_bgp_rpki_prefixes_vrf(): configure vrf vrf10 rpki - rpki cache 192.0.2.3 15432 preference 1 + rpki cache tcp 192.0.2.3 15432 preference 1 exit exit """ -- 2.39.5