From 6d49b646a1cd4840621e9d07a0431c87eeec2482 Mon Sep 17 00:00:00 2001
From: Daniil Baturin <daniil@baturin.org>
Date: Sun, 16 Dec 2018 23:39:23 +0100
Subject: T865: prototype RPKI implementation.

---
 Makefile.am                                        |  1 +
 scripts/vyos-update-rpki-cache.py                  | 88 ++++++++++++++++++++++
 .../node.tag/rule/node.tag/match/rpki/node.def     | 15 ++++
 templates/protocols/rpki/cache/node.def            |  3 +
 .../protocols/rpki/cache/node.tag/address/node.def |  2 +
 .../protocols/rpki/cache/node.tag/port/node.def    |  3 +
 .../cache/node.tag/ssh/known-hosts-file/node.def   |  5 ++
 .../protocols/rpki/cache/node.tag/ssh/node.def     |  1 +
 .../cache/node.tag/ssh/private-key-file/node.def   |  5 ++
 .../cache/node.tag/ssh/public-key-file/node.def    |  4 +
 .../rpki/cache/node.tag/ssh/username/node.def      |  2 +
 .../rpki/initial-synchronization-timeout/node.def  |  7 ++
 templates/protocols/rpki/node.def                  |  3 +
 templates/protocols/rpki/polling-period/node.def   |  7 ++
 templates/protocols/rpki/preference/node.def       |  2 +
 templates/protocols/rpki/timeout/node.def          |  6 ++
 16 files changed, 154 insertions(+)
 create mode 100644 scripts/vyos-update-rpki-cache.py
 create mode 100644 templates/policy/route-map/node.tag/rule/node.tag/match/rpki/node.def
 create mode 100644 templates/protocols/rpki/cache/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/address/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/port/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/ssh/known-hosts-file/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/ssh/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/ssh/private-key-file/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/ssh/public-key-file/node.def
 create mode 100644 templates/protocols/rpki/cache/node.tag/ssh/username/node.def
 create mode 100644 templates/protocols/rpki/initial-synchronization-timeout/node.def
 create mode 100644 templates/protocols/rpki/node.def
 create mode 100644 templates/protocols/rpki/polling-period/node.def
 create mode 100644 templates/protocols/rpki/preference/node.def
 create mode 100644 templates/protocols/rpki/timeout/node.def

diff --git a/Makefile.am b/Makefile.am
index ec9ca5fc..434de372 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,6 +13,7 @@ sbin_SCRIPTS += scripts/vyatta-gateway-static_route-check.pl
 sbin_SCRIPTS += scripts/vyatta-link-detect
 sbin_SCRIPTS += scripts/vyatta-next-hop-check
 sbin_SCRIPTS += scripts/vyatta-update-static-route.pl
+sbin_SCRIPTS += scripts/vyos-update-rpki-cache.py
 
 bin_sudo_users_SCRIPTS = scripts/vyatta-static-dhcp.pl
 
diff --git a/scripts/vyos-update-rpki-cache.py b/scripts/vyos-update-rpki-cache.py
new file mode 100644
index 00000000..1b5bee96
--- /dev/null
+++ b/scripts/vyos-update-rpki-cache.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+
+import sys
+import subprocess
+
+import vyos.config
+
+
+base_path = "protocols rpki "
+
+def create_cache(c, cache):
+    new_port = c.return_value(base_path + "cache {0} port".format(cache))
+    new_addr = c.return_value(base_path + "cache {0} address".format(cache))
+    new_pref = c.return_value(base_path + "cache {0} preference".format(cache))
+
+    ssh = False
+    if c.exists(base_path + "cache {0} ssh".format(cache)):
+        ssh = True
+        new_user = c.return_value(base_path + "cache {0} ssh username".format(cache))
+        new_pubkey = c.return_value(base_path + "cache {0} ssh public-key-file".format(cache))
+        new_privkey = c.return__value(base_path + "cache {0} ssh private-key-file".format(cache))
+        new_known_hosts = c.return_value(base_path + "cache {0} ssh known-hosts-file".format(cache))
+
+        if (not new_user) or (not new_pubkey) or (not new_privkey) or (not new_known_hosts):
+            print("If SSH is used for RPKI cache, username, public/private keys, and known hosts file must be defined")
+            sys.exit(1)
+
+    if (not new_addr) or (not new_port):
+        print("Address and port must be defined for RPKI cache servers")
+        sys.exit(1)
+
+    if not new_pref:
+        new_pref = 1
+
+    if ssh:
+        subprocess.call(""" vtysh -c 'conf t' -c 'rpki' -c 'rpki cache {0} {1} {2} {3} {4} {5} preference {6}' """.format(new_addr, new_port, new_user, new_privkey, new_pubkey, new_known_hosts, new_pref), shell=True)
+    else:
+        subprocess.call(""" vtysh -c 'conf t' -c 'rpki' -c 'rpki cache {0} {1} preference {2}' """.format(new_addr, new_port, new_pref), shell=True)
+
+def delete_cache(c, cache):
+    ssh = False
+    if c.exists_effective(base_path + "cache {0} ssh".format(cache)):
+        ssh = True
+        user = c.return_effective_value(base_path + "cache {0} ssh username".format(cache))
+        pubkey = c.return_effective_value(base_path + "cache {0} ssh public-key-file".format(cache))
+        privkey = c.return_effective_value(base_path + "cache {0} ssh private-key-file".format(cache))
+        known_hosts = c.return_effective_value(base_path + "cache {0} ssh known-hosts-file".format(cache))
+
+        port = c.return_effective_value(base_path + "cache {0} port".format(cache))
+        addr = c.return_effective_value(base_path + "cache {0} address".format(cache))
+        pref = c.return_effective_value(base_path + "cache {0} preference".format(cache))
+
+        if not pref:
+            pref = 1
+
+        if ssh:
+            subprocess.call(""" vtysh -c 'conf t' -c 'rpki' -c 'no rpki cache {0} {1} {2} {3} {4} {5} preference {6}' """.format(addr, port, user, privkey, pubkey, known_hosts, pref), shell=True)
+        else:
+            subprocess.call(""" vtysh -c 'conf t' -c 'rpki' -c 'no rpki cache {0} {1} preference {2}' """.format(addr, port, pref), shell=True)
+
+
+config = vyos.config.Config()
+
+caches = config.list_nodes(base_path + "cache")
+orig_caches = config.list_effective_nodes(base_path + "cache")
+
+# RPKI caches can only be manipulated when RPKI is stopped
+print("Stopping RPKI")
+subprocess.call(""" vtysh -c 'rpki stop' """, shell=True)
+
+if not caches:
+    for cache in orig_caches:
+        delete_cache(config, cache)
+else:
+    for cache in caches:
+        if cache in orig_caches:
+            delete_cache(config, cache)
+        create_cache(config, cache)
+
+    for cache in orig_caches:
+        if not cache in caches:
+            # No longer exists
+            delete_cache(config, cache)
+
+if caches:
+    print("Starting RPKI")
+    subprocess.call(""" vtysh -c 'rpki start' """, shell=True)
+
diff --git a/templates/policy/route-map/node.tag/rule/node.tag/match/rpki/node.def b/templates/policy/route-map/node.tag/rule/node.tag/match/rpki/node.def
new file mode 100644
index 00000000..3b1f8b47
--- /dev/null
+++ b/templates/policy/route-map/node.tag/rule/node.tag/match/rpki/node.def
@@ -0,0 +1,15 @@
+type: txt
+help: Match RPKI validation result
+
+syntax:expression: $VAR(@) in "notfound", "invalid", "valid"; "Must be either notfound, invalid, or valid"
+
+commit:expression: $VAR(../../action/) != ""; "You must specify an action"
+
+update: vtysh -c "configure terminal" \
+         -c "route-map $VAR(../../../@) $VAR(../../action/@) $VAR(../../@)" \
+         -c "match rpki $VAR(@)"
+
+delete: vtysh -c "configure terminal" \
+         -c "route-map $VAR(../../../@) $VAR(../../action/@) $VAR(../../@)" \
+         -c "no match rpki $VAR(@)"
+
diff --git a/templates/protocols/rpki/cache/node.def b/templates/protocols/rpki/cache/node.def
new file mode 100644
index 00000000..f28cf2c6
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.def
@@ -0,0 +1,3 @@
+tag:
+type: txt
+help: RPKI cache server instance
diff --git a/templates/protocols/rpki/cache/node.tag/address/node.def b/templates/protocols/rpki/cache/node.tag/address/node.def
new file mode 100644
index 00000000..de110206
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/address/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: RPKI cache server address
diff --git a/templates/protocols/rpki/cache/node.tag/port/node.def b/templates/protocols/rpki/cache/node.tag/port/node.def
new file mode 100644
index 00000000..e97c2477
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/port/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: TCP port number
+val_help: u32:1-65535; TCP port number
diff --git a/templates/protocols/rpki/cache/node.tag/ssh/known-hosts-file/node.def b/templates/protocols/rpki/cache/node.tag/ssh/known-hosts-file/node.def
new file mode 100644
index 00000000..40f2c3dc
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/ssh/known-hosts-file/node.def
@@ -0,0 +1,5 @@
+type: txt
+help: RPKI SSH known hosts file
+
+syntax:expression: exec "test -f $VAR(@)"; "Must be an existing file path"
+
diff --git a/templates/protocols/rpki/cache/node.tag/ssh/node.def b/templates/protocols/rpki/cache/node.tag/ssh/node.def
new file mode 100644
index 00000000..2fb48499
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/ssh/node.def
@@ -0,0 +1 @@
+help: RPKI SSH connection settings
diff --git a/templates/protocols/rpki/cache/node.tag/ssh/private-key-file/node.def b/templates/protocols/rpki/cache/node.tag/ssh/private-key-file/node.def
new file mode 100644
index 00000000..8cfb580f
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/ssh/private-key-file/node.def
@@ -0,0 +1,5 @@
+type: txt
+help: RPKI SSH private key file
+
+syntax:expression: exec "test -f $VAR(@)"; "Must be an existing file path"
+
diff --git a/templates/protocols/rpki/cache/node.tag/ssh/public-key-file/node.def b/templates/protocols/rpki/cache/node.tag/ssh/public-key-file/node.def
new file mode 100644
index 00000000..31de9562
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/ssh/public-key-file/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: RPKI SSH public key file path
+
+syntax:expression: exec "test -f $VAR(@)"; "Must be an existing file path"
diff --git a/templates/protocols/rpki/cache/node.tag/ssh/username/node.def b/templates/protocols/rpki/cache/node.tag/ssh/username/node.def
new file mode 100644
index 00000000..4391509d
--- /dev/null
+++ b/templates/protocols/rpki/cache/node.tag/ssh/username/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: RPKI SSH username
diff --git a/templates/protocols/rpki/initial-synchronization-timeout/node.def b/templates/protocols/rpki/initial-synchronization-timeout/node.def
new file mode 100644
index 00000000..43d2016f
--- /dev/null
+++ b/templates/protocols/rpki/initial-synchronization-timeout/node.def
@@ -0,0 +1,7 @@
+type: u32
+help: Initial RPKI cache synchronization timeout
+
+create: vtysh -c 'conf t' -c 'rpki' -c 'rpki initial-synchronisation-timeout $VAR(@)'
+update: vtysh -c 'conf t' -c 'rpki' -c 'rpki initial-synchronisation-timeout $VAR(@)'
+delete: vtysh -c 'conf t' -c 'rpki' -c 'no rpki initial-synchronisation-timeout'
+
diff --git a/templates/protocols/rpki/node.def b/templates/protocols/rpki/node.def
new file mode 100644
index 00000000..28d77a9e
--- /dev/null
+++ b/templates/protocols/rpki/node.def
@@ -0,0 +1,3 @@
+help: BGP prefix origin validation
+
+end: ${vyatta_sbindir}/vyos-update-rpki-cache.py
diff --git a/templates/protocols/rpki/polling-period/node.def b/templates/protocols/rpki/polling-period/node.def
new file mode 100644
index 00000000..ee8d0a2d
--- /dev/null
+++ b/templates/protocols/rpki/polling-period/node.def
@@ -0,0 +1,7 @@
+type: u32
+help: RPKI cache polling period
+val_help: u32:1-1300; Polling period
+
+create: vtysh -c 'conf t' -c 'rpki' -c 'rpki polling_period $VAR(@)'
+update: vtysh -c 'conf t' -c 'rpki' -c 'rpki polling_period $VAR(@)'
+delete: vtysh -c 'conf t' -c 'rpki' -c 'no rpki polling_period'
diff --git a/templates/protocols/rpki/preference/node.def b/templates/protocols/rpki/preference/node.def
new file mode 100644
index 00000000..f946fc0b
--- /dev/null
+++ b/templates/protocols/rpki/preference/node.def
@@ -0,0 +1,2 @@
+type: u32
+help: RPKI cache preference
diff --git a/templates/protocols/rpki/timeout/node.def b/templates/protocols/rpki/timeout/node.def
new file mode 100644
index 00000000..2ea31cbf
--- /dev/null
+++ b/templates/protocols/rpki/timeout/node.def
@@ -0,0 +1,6 @@
+type: u32
+help: RPKI cache reply timeout
+
+create: vtysh -c 'conf t' -c 'rpki' -c 'rpki timeout $VAR(@)'
+update: vtysh -c 'conf t' -c 'rpki' -c 'rpki timeout $VAR(@)'
+delete: vtysh -c 'conf t' -c 'rpki' -c 'no rpki timeout'
-- 
cgit v1.2.3