*.rar
*.tar
*.zip
+*.asc
# Check Framework
*.test
An RPKI Validator and RTR Server.
-**This software is in beta**
-
## Installation
Dependencies:
-1. libcrypto ([LibreSSL](http://www.libressl.org/) or [OpenSSL](https://www.openssl.org/))
+1. libcrypto ([LibreSSL](http://www.libressl.org/) or [OpenSSL](https://www.openssl.org/) >= 1.1)
2. [jansson](https://github.com/akheron/jansson)
3. [rsync](http://rsync.samba.org/)
+The validator is currently supported in *64-bit* OS. A 32-bit OS may face the [Year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) when handling dates at certificates.
+
After all the dependencies are installed, run:
```
AC_PREREQ([2.69])
# TODO change the bug report address
-AC_INIT([fort], [0.0.2], [ydahhrk@gmail.com])
+AC_INIT([fort], [1.0.0], [fort-validator@nic.mx])
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([subdir-objects])
AC_SEARCH_LIBS([pthread_create], [pthread], [],
[AC_MSG_ERROR([unable to find the pthread() function])]
)
-AC_SEARCH_LIBS([d2i_X509_bio], [crypto], [],
- [AC_MSG_ERROR([unable to find the d2i_X509_bio() function])]
+AC_SEARCH_LIBS([X509_get_version], [crypto], [],
+ [AC_MSG_ERROR([unable to find the X509_get_version() function])]
)
AC_SEARCH_LIBS([backtrace],[execinfo],[],
[AC_MSG_ERROR([unable to find backtrace() function])]
values:
layout: "default"
-fort-latest-version: 0.0.2
+fort-latest-version: 1.0.0
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<!-- Styles -->
- <link href="../css/screen.css" rel="stylesheet" type="text/css">
- <link href="../css/fort_project.css" rel="stylesheet" type="text/css">
- <link href="../css/fort_validator.css" rel="stylesheet" type="text/css">
+ <link href="{% if page.url == '/' %}./css/screen.css{% else %}../css/screen.css{% endif %}" rel="stylesheet" type="text/css">
<!-- Site is still under construction, so don't index it -->
<meta name="robots" content="noindex,nofollow">
<!-- Header -->
<header class="site-header">
<div class="container">
- <div class="row align-items-end">
+ <div class="row align-items-center">
<div class="col">
<div class="logo">
- <a href="../index.html" title="" class="d-flex">
- <img src="../img/logo_validador_fort.svg" alt="Fort">
- </a>
+ {% if page.url == '/' %}
+ <a href="./index.html" title="" class="d-flex">
+ <img src="./img/logo_validador_fort.svg" alt="Fort" width="125px">
+ </a>
+ {% else %}
+ <a href="../index.html" title="" class="d-flex">
+ <img src="../img/logo_validador_fort.svg" alt="Fort" width="125px">
+ </a>
+ {% endif %}
</div>
</div>
<div class="col-auto">
<div class="navigation">
<nav class="site-nav">
<ul>
- <li>
- <a class="" href="../index.html">
- Home
- </a>
- </li>
- <li><a href="./index.html">
- Documentation
- </a></li>
+ {% if page.url == '/' %}
+ <li>
+ <a class="active-item" href="./index.html">Home</a>
+ </li>
+ <li>
+ <a href="./doc/index.html">Documentation</a>
+ </li>
+ {% else %}
+ <li>
+ <a href="../index.html">Home</a>
+ </li>
+ <li><a class="active-item" href="./index.html">Documentation</a>
+ </li>
+ {% endif %}
+
</ul>
</nav>
</div>
</header>
-<section class="site-section">
+<section class="site-section section-h-full">
<div class="container">
+ <div class="row">
+ {% if (page.url.size} > 5 %}
+ <div class="col-lg-3">
+ <aside class="site-aside">
+ <ul class="list-bullet">
- {{ content }}
+ <li>
+ <a class="item-menu{% if page.url == '/doc/intro-rpki.html' %} active{% endif %}" href="intro-rpki.html">Introduction to RPKI</a>
+ </li>
+ <li>
+ <a class="item-menu{% if page.url == '/doc/intro-fort.html' %} active{% endif %}" href="intro-fort.html">Introduction to Fort</a>
+ </li>
+ <li>
+ <a class="item-menu{% if page.url == '/doc/installation.html' %} active{% endif %}" href="installation.html">Compilation and Installation</a>
+ </li>
+ <li>
+ <a class="item-menu{% if page.url == '/doc/run.html' %} active{% endif %}" href="run.html">Running Fort</a>
+ </li>
+ <li>
+ <a class="item-menu{% if page.url == '/doc/usage.html' %} active{% endif %}" href="usage.html">Fort usage</a>
+ </li>
+ <li>
+ <a class="item-menu{% if page.url == '/doc/slurm.html' %} active{% endif %}" href="slurm.html">SLURM</a>
+ </li>
+ <li>
+ <a class="item-menu{% if page.url == '/doc/incidence.html' %} active{% endif %}" href="incidence.html">Incidences</a>
+ </li>
+ </ul>
+ </aside>
+ </div>
+ {% endif %}
+ <div class="col">
+ <article class="article-section">
+ {{ content }}
+ </article>
+ </div>
+ </div>
</div>
</section>
<!-- Footer -->
<footer class="site-footer">
<div class="container">
<div class="row">
- <div class="col justify-content-center">
- <a href="https://github.com/NICMx/FORT-validator" target="_blank" title="" class="d-flex">
- <img src="../img/GitHub-Mark-Light-120px-plus.png" alt="Git">
+ <div class="col">
+ <a href="https://github.com/NICMx/FORT-validator" target="_blank" title="" class="d-flex justify-content-center">
+ <img src="{% if page.url == '/' %}./img/GitHub-Mark-Light-120px-plus.png{% else %}../img/GitHub-Mark-Light-120px-plus.png{% endif %}" alt="Git" width="40">
</a>
</div>
</div>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<!-- APP JS -->
-<script src="../js/metodos.js" type="text/javascript"></script>
+<script src="{% if page.url == '/' %}./js/metodos.js{% else %}../js/metodos.js{% endif %}" type="text/javascript"></script>
</body>
+++ /dev/null
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
- <title>{{ page.title }}</title>
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <!-- Bootstrap CSS -->
- <!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">-->
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
-
- <!-- Styles -->
- <link href="./css/screen.css" rel="stylesheet" type="text/css">
- <link href="./css/fort_project.css" rel="stylesheet" type="text/css">
- <link href="./css/fort_validator.css" rel="stylesheet" type="text/css">
-
- <!-- Site is still under construction, so don't index it -->
- <meta name="robots" content="noindex,nofollow">
-</head>
-
-<body>
-<!-- Header -->
-<header class="site-header">
- <div class="container">
- <div class="row align-items-end">
- <div class="col">
- <div class="logo">
- <a href="./index.html" title="" class="d-flex">
- <img src="./img/logo_validador_fort.svg" alt="Fort">
- </a>
- </div>
- </div>
- <div class="col-auto">
- <div class="menu-open">
- <span></span>
- <span></span>
- <span></span>
- </div>
- <div class="navigation">
- <nav class="site-nav">
- <ul>
- <li>
- <a class="" href="./index.html">
- Home
- </a>
- </li>
- <li><a href="./doc/index.html">
- Documentation
- </a></li>
- </ul>
- </nav>
-
- </div>
- </div>
- </div>
- </div>
-</header>
-
-<section class="site-section">
- <div class="container">
-
- {{ content }}
- </div>
-</section>
-<!-- Footer -->
-<footer class="site-footer">
- <div class="container">
- <div class="row">
- <div class="col justify-content-center">
- <a href="https://github.com/NICMx/FORT-validator" target="_blank" title="" class="d-flex">
- <img src="./img/GitHub-Mark-Light-120px-plus.png" alt="Git">
- </a>
- </div>
- </div>
- </div>
-</footer>
-
-<div class="js-overlay overlay-content"></div>
-
-<!-- Bootstrap js -->
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
-<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
-
-<!-- APP JS -->
-<script src="./js/metodos.js" type="text/javascript"></script>
-
-
-</body>
-</html>
+++ /dev/null
-@import url("https://fonts.googleapis.com/css?family=Roboto:400,700,900");
-.bg-grey {
- background: #f5f5f5; }
-
-.bg-blue-dark {
- background: #10242d; }
-
-.site-nav ul,
-.site-nav ul li {
- margin: 0;
- padding: 0;
- list-style-type: none; }
-ul.list-bullet li,
-ul li.list-bullet li {
- margin-bottom: 5px; }
-ul.list-bullet li:before,
-ul li.list-bullet li:before {
- content: "•";
- color: #3389ff;
- margin-right: 5px;
- margin-left: 10px;
- font-size: 16px; }
-
-.text-white,
-.text-white * {
- color: white; }
-
-.text-blue-light,
-.text-blue-light * {
- color: #3389ff !important; }
-
-.text-blue-dark,
-.text-blue-dark * {
- color: #10242d !important; }
-
-figure img {
- max-width: 100%; }
-
-* {
- color: white;
- font-family: "Roboto", sans-serif;
-}
-
-h1, h2, h3, h4,
-h1 *, h2 *, h3 *, h4 * {
- color: white;
- font-weight: 300;
- margin-bottom: .5rem;}
-
-h2.text-blue-light, h2.text-blue-light * {
- font-size: 4.4rem; }
-
-strong {
- font-weight: 700; }
-
-.text-high,
-.text-high * {
- font-size: 1.38rem;
- font-weight: 300;
- line-height: normal; }
-@media (max-width: 768px) {
- .text-high,
- .text-high * {
- font-size: 1rem; } }
-
-.text-high {
- margin: 40px 0; }
-@media (max-width: 768px) {
- .text-high {
- margin: 20px 0; } }
-
-@media (max-width: 1024px) {
- .text-right {
- text-align: left !important; } }
-
-a , a*{
- color: #3389ff;
- transition: all 0.5s ease;
- -moz-transition: all 0.5s ease;
- -ms-transition: all 0.5s ease;
- -webkit-transition: all 0.5s ease; }
-a:hover, a:focus {
- text-decoration: none; }
-
-body {
- background: #152c38;
- padding-top: 120px;
- margin: 0;
- margin-bottom: 120px;}
-@media (max-width: 768px) {
- body {
- padding-top: 60px; } }
-
-.site-header {
- position: fixed;
- top: 0;
- right: 0;
- height: 120px;
- width: 100%;
- background-color: #152c38;
- transition: all 0.5s ease;
- -moz-transition: all 0.5s ease;
- -ms-transition: all 0.5s ease;
- -webkit-transition: all 0.5s ease;
- z-index: 2;
- padding: 40px 0; }
-.site-header .logo a {
- align-items: flex-end; }
-.site-header .logo a img {
- margin-right: 20px;
- /*width: 150px; }*/
- height: 70px;}
-.site-header .logo a h1 {
- margin: 0; }
-.site-header.small-header {
- background: #10242d;
- height: 80px;
- padding: 10px 0; }
-.site-header.small-header .logo a img {
- /*width: 100px;*/
- height: 60px;}
-.site-header.small-header .small-nav {
- margin-bottom: 0; }
-@media (max-width: 768px) {
- .site-header {
- background: #10242d;
- height: 80px;
- padding: 20px 0; }
- .site-header .logo a img {
- /*width: 100px; }*/
- height: 60px;}
- .site-header .small-nav {
- margin-bottom: 0; }
- .site-header.small-header {
- padding: 20px 0; } }
-
-.site-footer {
- position: absolute;
- bottom: 0;
- width: 100%;
- height: 120px;
- background: #09181e;
- padding: 30px 0; }
-.site-footer p {
- margin: 0; }
-
-.site-section {
- padding: 80px 0; }
-@media (max-width: 768px) {
- .site-section {
- padding: 40px 0; } }
-
-.site-aside {
- background: #10242d;
- padding: 40px;
-}
-.site-aside a {
- color: white; }
-@media (min-width: 1024px) {
- .site-aside{position: fixed;}
-}
-.box {
- border: 3px solid #3389ff;
- border-radius: 15px;
- -moz-border-radius: 15px;
- -ms-border-radius: 15px;
- -webkit-border-radius: 15px;
- height: 320px;
- padding: 40px; }
-.box h3, .box h3 * {
- font-size: 14px;
- font-weight: 700;
- text-transform: uppercase; }
-.box h4, .box h4 * {
- color: #3389ff; }
-@media (max-width: 1024px) {
- .box {
- border: none;
- border-bottom: 3px solid #3389ff;
- border-radius: 0;
- padding: 0 0 20px 0;
- height: auto;
- margin: 20px 0; }
- .box.last {
- border: none;
- padding: 0; } }
-
-.site-nav ul {
- display: flex; }
-.site-nav ul li a {
- color: white;
- font-size: 16px;
- font-weight: 400;
- letter-spacing: 1px;
- padding: 0 15px;
- text-transform: uppercase; }
-.site-nav ul li a:hover, .site-nav ul li a:focus {
- color: #3389ff; }
-.site-nav ul li a.active-item {
- position: relative; }
-.site-nav ul li a.active-item:after {
- background: #3389ff;
- content: "";
- position: absolute;
- bottom: -10px;
- left: 50%;
- height: 2px;
- width: 30px;
- transform: translateX(-50%); }
-
-.small-nav {
- margin-right: 10px;
- margin-bottom: 30px; }
-.small-nav ul li a, .small-nav ul li a * {
- color: rgba(245, 245, 245, 0.5);
- font-size: 12px;
- font-weight: 300;
- padding: 0 3px; }
-.small-nav ul li a.active-item, .small-nav ul li a *.active-item {
- color: #3389ff; }
-.small-nav ul li a.active-item:after, .small-nav ul li a *.active-item:after {
- display: none; }
-
-@media (max-width: 1024px) {
- .navigation {
- display: none;
- background: #10242d;
- padding: 40px;
- position: fixed;
- top: 0;
- left: 0;
- height: 100%;
- width: 100%;
- z-index: 2; }
- .navigation ul {
- flex-direction: column; }
- .navigation ul li {
- border-bottom: 1px solid rgba(51, 137, 255, 0.2); }
- .navigation ul li a {
- display: block;
- font-size: 18px;
- text-align: center;
- padding: 20px 0; }
- .navigation ul li a.active-item {
- color: #3389ff; }
- .navigation ul li a.active-item:after {
- display: none; }
- .navigation ul li:last-child {
- border: none; }
- .navigation .small-nav ul {
- flex-direction: row; }
- .navigation .small-nav ul li {
- border: none; }
- .navigation .small-nav ul li a {
- font-size: 12px;
- padding: 0 3px; } }
-
-.menu-open {
- display: none; }
-@media (max-width: 1024px) {
- .menu-open {
- display: block;
- cursor: pointer;
- position: fixed;
- top: 35px;
- right: 20px;
- height: 25px;
- width: 25px;
- transform: rotate(0deg);
- -moz-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- -webkit-transform: rotate(0deg);
- transition: 0.5s ease-in-out;
- -moz-transition: 0.5s ease-in-out;
- -ms-transition: 0.5s ease-in-out;
- -webkit-transition: 0.5s ease-in-out;
- z-index: 20; }
- .menu-open span {
- background: white;
- display: block;
- opacity: 1;
- position: absolute;
- top: 0;
- left: 0;
- height: 3px;
- width: 100%;
- transition: 0.25s ease-in-out;
- -moz-transition: 0.25s ease-in-out;
- -ms-transition: 0.25s ease-in-out;
- -webkit-transition: 0.25s ease-in-out;
- transform: rotate(0deg);
- -moz-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- -webkit-transform: rotate(0deg); }
- .menu-open span:nth-child(1), .menu-open span:nth-child(2), .menu-open span:nth-child(3) {
- transform-origin: left center;
- -moz-transform-origin: left center;
- -ms-transform-origin: left center;
- -webkit-transform-origin: left center; }
- .menu-open span:nth-child(1) {
- top: 0px; }
- .menu-open span:nth-child(2) {
- top: 6px; }
- .menu-open span:nth-child(3) {
- top: 12px; }
- .menu-open span:hover, .menu-open span:focus {
- background: #006cff; }
- .menu-open.clic span:nth-child(1) {
- transform: rotate(45deg);
- -moz-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- -webkit-transform: rotate(45deg);
- position: absolute;
- top: 0;
- left: 0; }
- .menu-open.clic span:nth-child(2) {
- width: 0%;
- opacity: 0; }
- .menu-open.clic span:nth-child(3) {
- transform: rotate(-45deg);
- -moz-transform: rotate(-45deg);
- -ms-transform: rotate(-45deg);
- -webkit-transform: rotate(-45deg);
- position: absolute;
- top: 17px;
- left: 0; } }
-
-.container {
- max-width: 1250px;
- padding-left: 30px;
- padding-right: 30px; }
-
-.btn {
- background: #66d394;
- border-radius: 30px;
- -moz-border-radius: 30px;
- -ms-border-radius: 30px;
- -webkit-border-radius: 30px;
- color: white;
- padding: 10px 30px;
- text-transform: uppercase;
- font-size: 13px;
- font-weight: 700;
- letter-spacing: 1px; }
-.btn:hover, .btn:focus {
- background: #3ec878;
- color: white; }
-.btn * {
- font-size: 13px;
- font-weight: 700;
- text-transform: uppercase; }
-
-.i-black {
- background: #5b5b5b; }
-
-.i-white {
- background: white; }
-
-.sponsor{
- display: flex;
- align-items: center;}
-
-.sponsor a img{
- max-height: 100px;
- max-width: 224px;
-}
-
-html {
- min-height: 100%;
- position: relative;
-}
-
-footer figure img {
- max-width: 22rem; }
-
-.alert-fort {
- color: #383d41;
- background-color: #b1b3b7;
- border-color: #d6d8db;
-}
-
-.card-team {
- background-color: unset;
-}
-
-ul.list-bullet-top > li,
-ul li.list-bullet-top >li {
- margin-bottom: 10px; }
-ul.list-bullet-top > li:before,
-ul li.list-bullet-top > li:before {
- content: "o";
- color: #3389ff;
- margin-right: 5px;
- font-size: 16px; }
-
-.about-section{
- margin-top: -120px;
- padding-top: 120px;
-}
-
-/*# sourceMappingURL=app.css.map */
+++ /dev/null
-/** {
- font-size: 1rem;
-}*/
-
-body {
- margin-bottom: 80px;
-}
-
-.site-footer {
- height: 80px;
- padding: 20px 0; }
-
-
-blockquote {
- background-color: #b1b3b7;
- margin: 0 1.5em 1.5em 1.5em;
-}
-
-code, code span {
- color: white;
- font-family: monospace;
- font-size: inherit;
- background-color: unset;
-}
-
-pre code{
- color: white;
- background-color: black;
- font-size: 1rem;
-}
-pre code.terminal {
- color: white;
-}
-
-.language-bash > .nb {
- color: white;
-}
-
-p img {
- background-color: #b1b3b7;
-}
-
-.site-footer a img {
- margin: auto;
- max-height: 40px;
-}
-
-
-h2{
- margin-top: 2.5rem;
-}
-h3{
- margin-top: 2.5rem;
-}
-h4{
- margin-top: 1.5rem;
-}
-p{
- margin-bottom: 0.5rem;
-}
-
-td, th {
- text-align: center;
- border-width: 1px;
- border-style: solid;
- border-color: #b1b3b7;
- border-image: initial;
- padding: 0.5rem;
-}
-
-pre code a{
- color: #00bfFF;
-}
-
-figure {
- margin-block-start: 1em;
- margin-block-end: 1em;
- margin-inline-start: 1.5em;
- margin-inline-end: 1.5em;
-}
-
-blockquote {
- padding: 1em;
- border-radius: 3px;
- border: 1px solid #ddd;
- color: #404040;
- background-color: #f0f6ff;
- margin-left: 3em;
- margin-right: 3em;
+@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700,900|Roboto+Mono:400,500&display=swap");
+* {
+ color: white;
+ font-family: "Roboto", sans-serif;
+ font-size: 16px; }
+
+h1, h2, h3, h4,
+h1 *, h2 *, h3 *, h4 * {
+ color: white;
+ font-weight: 400;}
+
+h1, h1 * {
+ font-size: 35px;
+ margin-bottom: 20px; }
+@media (max-width: 768px) {
+ h1, h1 * {
+ font-size: 30px; } }
+h1.title-big, h1.title-big *, h1 *.title-big, h1 *.title-big * {
+ margin: 0;
+ font-size: 70px;
+ font-weight: 300; }
+h1.title-big strong, h1.title-big * strong, h1 *.title-big strong, h1 *.title-big * strong {
+ font-weight: 700; }
+@media (max-width: 768px) {
+ h1.title-big, h1.title-big *, h1 *.title-big, h1 *.title-big * {
+ font-size: 30px; } }
+
+h2, h2 * {
+ font-size: 26px;
}
+@media (max-width: 768px) {
+ h2, h2 * {
+ font-size: 22px; } }
-code {
- background-color: #f8f8f8;
+h3, h3 * {
+ font-size: 20px;
+}
+@media (max-width: 768px) {
+ h3, h3 * {
+ font-size: 18px; } }
+
+h4, h4 * {
+ font-size: 18px; }
+
+strong {
+ font-weight: 700; }
+
+.text-high,
+.text-high * {
+ font-size: 22px;
+ font-weight: 300;
+ line-height: normal; }
+@media (max-width: 768px) {
+ .text-high,
+ .text-high * {
+ font-size: 16px; } }
+
+.text-high {
+ margin: 40px 0; }
+@media (max-width: 768px) {
+ .text-high {
+ margin: 20px 0; } }
+
+@media (max-width: 1024px) {
+ .text-right {
+ text-align: left !important; } }
+
+a {
+ color: #009DCB;
+ transition: all 0.5s ease;
+ -moz-transition: all 0.5s ease;
+ -ms-transition: all 0.5s ease;
+ -webkit-transition: all 0.5s ease; }
+a:hover, a:focus {
+ text-decoration: none; }
+
+body {
+ background: #152c38;
+ padding-top: 120px; }
+@media (max-width: 768px) {
+ body {
+ padding-top: 60px; } }
+
+.site-header {
+ background: #10242d;
+ position: fixed;
+ top: 0;
+ right: 0;
+ height: 100px;
+ width: 100%;
+ transition: all 0.5s ease;
+ -moz-transition: all 0.5s ease;
+ -ms-transition: all 0.5s ease;
+ -webkit-transition: all 0.5s ease;
+ z-index: 2;
+ padding: 20px 0; }
+.site-header .logo a {
+ align-items: flex-end; }
+.site-header .logo a img {
+ margin-right: 20px;
+ height: 60px; }
+.site-header .logo a h1 {
+ margin: 0; }
+.site-header.small-header {
+ background: #10242d;
+ height: 80px;
+ padding: 10px 0; }
+.site-header.small-header .small-nav {
+ margin-bottom: 0; }
+@media (max-width: 768px) {
+ .site-header {
+ background: #10242d;
+ height: 80px;
+ padding: 20px 0; }
+ .site-header .logo a img {
+ height: 40px; }
+ .site-header .small-nav {
+ margin-bottom: 0; }
+ .site-header.small-header {
+ padding: 20px 0; } }
+
+.site-footer {
+ background: #09181e;
+ height: 100px;
+ padding: 20px 0; }
+.site-footer p {
+ margin: 0; }
+.site-footer .logos-fort {
+ max-width: 300px; }
+@media (max-width: 768px) {
+ .site-footer {
+ height: auto;
+ text-align: center; }
+ .site-footer .text-right {
+ text-align: center !important; } }
+.site-footer a.d-flex {
+ margin: 15px 0 10px 0; }
+
+.site-section {
+ padding: 80px 0; }
+@media (max-width: 768px) {
+ .site-section {
+ padding: 40px 0; } }
+@media (min-width: 768px) {
+ .site-section.section-h-full {
+ min-height: calc(100vh - (120px + 100px)); } }
+
+.article-section {
+ margin-bottom: 40px;
}
+.article-section .about-section {
+ margin: 40px 0; }
+.article-section .about-section:last-child {
+ margin: 0; }
+
+.site-aside {
+ background: #10242d;
+ padding: 40px;
+ position: sticky;
+ top: 120px;
+ margin-bottom: 20px; }
+.site-aside a {
+ color: white; }
+.site-aside a.active , .site-aside a.active * {
+ color: #009DCB; }
+
+.box {
+ border: 3px solid #009DCB;
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -ms-border-radius: 15px;
+ -webkit-border-radius: 15px;
+ height: 330px;
+ padding: 40px; }
+.box h3, .box h3 * {
+ color: white;
+ margin: 0;
+ font-size: 14px;
+ font-weight: 700;
+ text-transform: uppercase; }
+.box h4, .box h4 * {
+ color: #009DCB;
+ margin: 10px 0; }
+@media (max-width: 1024px) {
+ .box {
+ border: none;
+ border-radius: 0;
+ padding: 0 0 20px 0;
+ height: auto;
+ margin: 40px 0; }
+ .box.last {
+ border: none;
+ padding: 0; } }
+
+.sponsor {
+ display: flex;
+ align-items: center; }
+@media (max-width: 460px) {
+ .sponsor a img {
+ max-width: 150px; } }
+
+.card {
+ background: transparent; }
+
+.site-nav ul {
+ display: flex; }
+.site-nav ul li a {
+ color: white;
+ font-size: 14px;
+ font-weight: 400;
+ letter-spacing: 1px;
+ padding: 0 10px;
+ text-transform: uppercase; }
+.site-nav ul li a:hover, .site-nav ul li a:focus {
+ color: #009DCB; }
+.site-nav ul li a.active-item {
+ position: relative; }
+.site-nav ul li a.active-item:after {
+ background: #009DCB;
+ content: "";
+ position: absolute;
+ bottom: -10px;
+ left: 50%;
+ height: 2px;
+ width: 30px;
+ transform: translateX(-50%); }
+
+.small-nav {
+ margin: 0 10px 10px 0; }
+.small-nav ul li a, .small-nav ul li a * {
+ color: rgba(245, 245, 245, 0.5);
+ font-size: 12px;
+ font-weight: 300;
+ padding: 0 3px; }
+.small-nav ul li a.active-item, .small-nav ul li a *.active-item {
+ color: #009DCB; }
+.small-nav ul li a.active-item:after, .small-nav ul li a *.active-item:after {
+ display: none; }
+
+@media (max-width: 1024px) {
+ .navigation {
+ background: #10242d;
+ display: none;
+ padding: 40px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ z-index: 2; }
+ .navigation ul {
+ flex-direction: column; }
+ .navigation ul li {
+ border-bottom: 1px solid rgba(51, 137, 255, 0.2); }
+ .navigation ul li a {
+ display: block;
+ font-size: 18px;
+ text-align: center;
+ padding: 20px 0; }
+ .navigation ul li a.active-item {
+ color: #009DCB; }
+ .navigation ul li a.active-item:after {
+ display: none; }
+ .navigation ul li:last-child {
+ border: none; }
+ .navigation .small-nav ul {
+ flex-direction: row; }
+ .navigation .small-nav ul li {
+ border: none; }
+ .navigation .small-nav ul li a {
+ font-size: 12px;
+ padding: 0 3px; } }
+
+.menu-open {
+ display: none; }
+@media (max-width: 1024px) {
+ .menu-open {
+ display: block;
+ cursor: pointer;
+ position: fixed;
+ top: 35px;
+ right: 20px;
+ height: 25px;
+ width: 25px;
+ transform: rotate(0deg);
+ -moz-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ -webkit-transform: rotate(0deg);
+ transition: 0.5s ease-in-out;
+ -moz-transition: 0.5s ease-in-out;
+ -ms-transition: 0.5s ease-in-out;
+ -webkit-transition: 0.5s ease-in-out;
+ z-index: 20; }
+ .menu-open span {
+ background: white;
+ display: block;
+ opacity: 1;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 3px;
+ width: 100%;
+ transition: 0.25s ease-in-out;
+ -moz-transition: 0.25s ease-in-out;
+ -ms-transition: 0.25s ease-in-out;
+ -webkit-transition: 0.25s ease-in-out;
+ transform: rotate(0deg);
+ -moz-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ -webkit-transform: rotate(0deg); }
+ .menu-open span:nth-child(1), .menu-open span:nth-child(2), .menu-open span:nth-child(3) {
+ transform-origin: left center;
+ -moz-transform-origin: left center;
+ -ms-transform-origin: left center;
+ -webkit-transform-origin: left center; }
+ .menu-open span:nth-child(1) {
+ top: 0px; }
+ .menu-open span:nth-child(2) {
+ top: 6px; }
+ .menu-open span:nth-child(3) {
+ top: 12px; }
+ .menu-open span:hover, .menu-open span:focus {
+ background: #006cff; }
+ .menu-open.clic span:nth-child(1) {
+ transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -webkit-transform: rotate(45deg);
+ position: absolute;
+ top: 0;
+ left: 0; }
+ .menu-open.clic span:nth-child(2) {
+ width: 0%;
+ opacity: 0; }
+ .menu-open.clic span:nth-child(3) {
+ transform: rotate(-45deg);
+ -moz-transform: rotate(-45deg);
+ -ms-transform: rotate(-45deg);
+ -webkit-transform: rotate(-45deg);
+ position: absolute;
+ top: 17px;
+ left: 0; } }
+
+pre {
+ background: #10242d;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -ms-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ padding: 20px;
+ margin: 0 0 1rem 0;
+ max-width: 800px;}
+
pre code {
+ color: white; }
+
+
+code {
+ color: white;
+ font-family: "Roboto Mono", monospace;}
+code span {
+ color: white;
+ font-family: "Roboto Mono", monospace;
+ font-size: inherit;
+ background-color: unset; }
+code a {
+ color: #00bfFF; }
+
+blockquote {
+ background: rgba(51, 137, 255, 0.2);
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -ms-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ padding: 20px;
+ margin-bottom: 20px; }
+blockquote p, blockquote p em {
+ font-size: 90%;
+ margin: 0; }
+
+.language-bash > .c {
+ color: #3CB371; }
+
+.language-bash > .nt {
+ color: #DDA0DD; }
+
+.language-bash > .s2 {
+ color: #00bfFF; }
+
+.language-bash > .nb {
+ color: white; }
+
+.highlighter-rouge {
+ border: solid 1px rgba(51, 137, 255, 0.2);
+ font-size: 80%;
+ padding: 1px 5px;
+ background: #10242d;
+}
+
+a > .highlighter-rouge{
+ color: #009DCB;
+}
+
+
+.container {
+ max-width: 1180px;
+ padding-left: 30px;
+ padding-right: 30px; }
+
+.btn {
+ background: #66d394;
+ border-radius: 30px;
+ -moz-border-radius: 30px;
+ -ms-border-radius: 30px;
+ -webkit-border-radius: 30px;
+ color: white;
+ padding: 10px 30px;
+ text-transform: uppercase;
+ font-size: 13px;
+ font-weight: 700;
+ letter-spacing: 1px; }
+.btn:hover, .btn:focus {
+ background: #3ec878;
+ color: white; }
+.btn * {
+ font-size: 13px;
+ font-weight: 700;
+ text-transform: uppercase; }
+
+.i-black {
+ background: #5b5b5b; }
+
+.i-white {
+ background: white; }
+
+.bg-grey {
+ background: #f5f5f5; }
+
+.bg-blue-dark {
+ background: #10242d; }
+
+ul,
+ul li {
+ margin: 0;
+ padding: 0;
+ list-style-type: none; }
+ul.list-bullet li,
+ul li.list-bullet li {
+ margin-bottom: 10px; }
+ul.list-bullet li:before,
+ul li.list-bullet li:before {
+ content: "o";
+ color: #009DCB;
+ margin-right: 10px;
+ font-size: 16px; }
+ul.list-bullet li ul,
+ul li.list-bullet li ul {
+ margin: 20px 0 20px 20px; }
+ul.list-bullet li ul li,
+ul li.list-bullet li ul li {
+ margin: 0; }
+ul.list-bullet li ul li:before,
+ul li.list-bullet li ul li:before {
+ content: "-";
+ color: #009DCB;
+ margin-right: 5px;
+ font-size: 16px; }
+
+.text-white,
+.text-white * {
+ color: white; }
+
+.text-blue-light,
+.text-blue-light * {
+ color: #009DCB !important; }
+
+.text-blue-dark,
+.text-blue-dark * {
+ color: #10242d !important; }
+
+figure img {
+ max-width: 100%; }
+
+/*# sourceMappingURL=app.css.map */
+
+.article-section > p > img {
+ background-color: rgba(51, 137, 255, 0.2);
+ max-width: 100%;
+}
+
+h3{
+ font-size: 20px;
+ padding: 115px 0 0px 0;
+ margin-bottom: -80px;
display: block;
- overflow: auto;
- padding: 1em;
+ position: relative;
+ top: -90px;
+ z-index: -1;
}
-pre code.terminal {
- color: lightgray;
- background-color: black;
+
+h2{
+ padding: 130px 0 0px 0;
+ margin-bottom: -100px;
+ display: block;
+ position: relative;
+ top: -110px;
+ z-index: -1;
}
-.language-bash > .c {
- color: #3CB371;
+h4{
+ padding: 115px 0 0px 0;
+ margin-bottom: -100px;
+ display: block;
+ position: relative;
+ top: -110px;
+ z-index: -1;
}
-.language-bash > .nt {
- color: #DDA0DD;
+
+a:hover {
+ color: #3389ff;
}
-.language-bash > .s2 {
- color: #00bfFF;
+
+.article-section ul,
+.article-section ul li{
+ margin: 0 0 5px 10px;
+ list-style-type: circle; }
+
+ol{
+ padding-inline-start: 20px;}
+
+td, th {
+ text-align: center;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #b1b3b7;
+ border-image: initial;
+ padding: 0.5rem;
+}
+
+div.highlighter-rouge{
+ margin-bottom: 1rem;
+ border: none;
}
+
+table {
+ margin-bottom: 1rem;
+}
\ No newline at end of file
The RPKI RFCs define fairly strict profiles for RPKI objects, and are unequivocal in stating that incorrectly-formed objects are supposed to be rejected by Relying Party validation. In practice, however, this does not prevent a significant amount of Certificate Authorities from issuing incorrect objects.
-By default, Fort is as pedantic as it can possibly be. The `incidence` section of its configuration file is a means to modify its behavior upon encountering profile violations that, from experience, are often overlooked.
+By default, Fort is lax with some of this bad practices. The `incidence` section of its configuration file is a means to modify its behavior upon encountering profile violations that, from experience, are often overlooked.
## `incidences` definition
```
"incidences": [
{
- "name": "Signed Object's hash algorithm has NULL object as parameters",
+ "name": "incid-hashalg-has-params",
"action": "warn"
}
]
```
-`name` is the identifier of an incidence. It is case-sensitive and developer-defined. It states the particular error condition that will be handled by the remaining field.
+`name` is the identifier of an incidence. It is case-sensitive and developer-defined. It states an ID of the particular error condition that will be handled by the remaining field.
`action` is an enumeration that states the outcome of a violation of the corresponding incidence. It can take one of three values:
2. `warn`: Print error message in `warning` log level, continue validation as if nothing happened.
3. `ignore`: Do not print error message, continue validation as if nothing happened.
-By Fort's pedantic nature, most incidences have an `action` of `error` by default.
+Since most of the incidences are result of a bad practice at the global RPKI, they have an `action` of `ignore` by default. If a strict behavior is desired, then the corresponding incidences should be configured with an `action` of `error`.
## Incidence types
### Signed Object's hash algorithm has NULL object as parameters
+- **Name:** `incid-hashalg-has-params`
+- **Default action:** `ignore`
+
[RFC 6488](https://tools.ietf.org/html/rfc6488) (RPKI Signed Objects) defers digest algorithm specification to RFC 6485:
```
parameters field;
```
-As of 2019-05-21, many signed objects in the global RPKI break this rule.
+As of 2019-08-12, many signed objects in the global RPKI break this rule.
If not `ignore`d, Fort will report this incidence with the following error message:
3. [Option 2: Compiling and installing the release tarball](#option-2-compiling-and-installing-the-release-tarball)
1. [Debian version](#debian-version)
2. [OpenBSD version](#openbsd-version)
+ 3. [CentOS version](#centos-version)
+ 4. [Fedora version](#fedora-version)
+ 5. [openSUSE Leap version](#opensuse-leap-version)
+ 6. [FreeBSD version](#freebsd-version)
+ 7. [Slackware version](#slackware-version)
4. [Option 3: Compiling and installing the git repository](#option-3-compiling-and-installing-the-git-repository)
## Dependencies
-> Note: I'm only including this section in case you intend to install Fort in an unlisted OS (and therefore need a little research). For Debians and OpenBSD, just follow the steps in the sections below.
+> Note: I'm only including this section in case you intend to install Fort in an unlisted OS (and therefore need a little research). For: Debians, OpenBSD, CentOS, Fedora, openSUSE Leap, FreeBSD, and Slackware just follow the steps in the sections below.
The dependencies are
1. [jansson](http://www.digip.org/jansson/)
-2. libcrypto (Either [LibreSSL](http://www.libressl.org/) or [OpenSSL](https://www.openssl.org/))
+2. libcrypto (Either [LibreSSL](http://www.libressl.org/) or [OpenSSL](https://www.openssl.org/) >= 1.1)
3. [rsync](http://rsync.samba.org/)
-## Option 1: Installing the Debian package
+Fort is currently supported in *64-bit* OS. A 32-bit OS may face the [Year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) when handling dates at certificates, and currently there's no work around for this.
-> TODO Upload to Debian, add more archs
+## Option 1: Installing the Debian package
{% highlight bash %}
wget https://github.com/NICMx/FORT-validator/releases/download/v{{ site.fort-latest-version }}/fort_{{ site.fort-latest-version }}-1_amd64.deb
exit
{% endhighlight %}
+### CentOS version
+
+The following steps are for CentOS 7, previous versions may require more steps to install Fort validator.
+
+This OS requires additional steps due to its GCC supported version (currently 4.8.5, fort needs >= 4.9 to compile) and default OpenSSL version (currently 1.0.2k, fort needs >= 1.1.0).
+
+**Install dependencies**
+
+OpenSSL devel (openssl-devel) package isn't necessary, if it's previously installed remove it to avoid future conflicts with newer OpenSSL versions.
+
+{% highlight bash %}
+sudo yum install autoconf automake git jansson-devel pkgconfig rsync
+# Install supported GCC to compile OpenSSL
+sudo yum groupinstall "Development Tools"
+{% endhighlight %}
+
+**Upgrade OpenSSL from 1.0.2k to 1.1.0k**
+
+The OpenSSL version must be greater than 1.0, in this case the version 1.1.0k is installed.
+
+{% highlight bash %}
+curl https://www.openssl.org/source/openssl-1.1.0k.tar.gz | tar xvz
+cd openssl-1.1.0k
+./config --prefix=/usr/local --openssldir=/usr/local/openssl
+make
+sudo make install
+# Update library files
+sudo mv libcrypto.so.1.1 libssl.so.1.1 /usr/lib64/
+sudo ln -sfn /usr/local/bin/openssl /usr/bin/openssl
+# Verify installed version
+openssl version
+{% endhighlight %}
+
+**Upgrade GCC**
+
+There are two options to upgrade GCC:
+1. Compile and install a newer version >= 4.9 (slow process).
+2. Use [Software Collections](https://www.softwarecollections.org) (indicated at the following steps).
+
+{% highlight bash %}
+sudo yum install centos-release-scl
+sudo yum install devtoolset-7-gcc
+# Start a session using the upgraded GCC
+scl enable devtoolset-7 bash
+cd ~
+curl -L https://github.com/NICMx/FORT-validator/releases/download/v{{ site.fort-latest-version }}/fort-{{ site.fort-latest-version }}.tar.gz --output fort-{{ site.fort-latest-version }}.tar.gz
+tar xvzf fort-{{ site.fort-latest-version }}.tar.gz
+cd fort-{{ site.fort-latest-version }}
+./configure
+make
+sudo make install
+# Close the 'devtoolset' session
+exit
+{% endhighlight %}
+
+### Fedora version
+
+The following steps are for Fedora 30.
+
+{% highlight bash %}
+sudo yum install autoconf automake gcc make openssl-devel jansson-devel
+
+wget https://github.com/NICMx/FORT-validator/releases/download/v{{ site.fort-latest-version }}/fort-{{ site.fort-latest-version }}.tar.gz
+tar xvzf fort-{{ site.fort-latest-version }}.tar.gz
+cd fort-{{ site.fort-latest-version }}/
+./configure
+make
+sudo make install
+{% endhighlight %}
+
+### openSUSE Leap version
+
+The following steps are for openSUSE Leap 15.1.
+
+{% highlight bash %}
+sudo zypper install autoconf automake gcc libopenssl-devel libjansson-devel
+
+wget https://github.com/NICMx/FORT-validator/releases/download/v{{ site.fort-latest-version }}/fort-{{ site.fort-latest-version }}.tar.gz
+tar xvzf fort-{{ site.fort-latest-version }}.tar.gz
+cd fort-{{ site.fort-latest-version }}/
+./configure
+make
+sudo make install
+{% endhighlight %}
+
+### FreeBSD version
+
+The following steps are for FreeBSD 12.0.
+
+{% highlight bash %}
+su
+pkg install autoconf automake gcc jansson pkgconf rsync
+exit
+
+curl -L https://github.com/NICMx/FORT-validator/releases/download/v{{ site.fort-latest-version }}/fort-{{ site.fort-latest-version }}.tar.gz --output fort-{{ site.fort-latest-version }}.tar.gz
+tar xvzf fort-{{ site.fort-latest-version }}.tar.gz
+cd fort-{{ site.fort-latest-version }}/
+./configure
+make
+su
+make install
+exit
+{% endhighlight %}
+
+### Slackware version
+
+The following steps are for Slackware "current" release (as of 2019-08-12).
+
+All dependencies are included in the current release, so there's no need to install any dependency.
+
+{% highlight bash %}
+wget https://github.com/NICMx/FORT-validator/releases/download/v{{ site.fort-latest-version }}/fort-{{ site.fort-latest-version }}.tar.gz
+tar xvzf fort-{{ site.fort-latest-version }}.tar.gz
+cd fort-{{ site.fort-latest-version }}/
+./configure
+make
+sudo make install
+{% endhighlight %}
+
## Option 3: Compiling and installing the git repository
+In case you wan't a fresh version of Fort validator, there's this third option. The steps are mostly the same as in [Option 2](#option-2-compiling-and-installing-the-release-tarball), just another dependency (as minimum) must be installed: "git"; and a few steps are included in order to get the source code and generate configuration scripts.
+
+The following example is the processo to clone, compile and install in Debian OS.
+
{% highlight bash %}
sudo apt install autoconf automake build-essential git libjansson-dev libssl-dev pkg-config rsync
{% highlight bash %}
$ {{ page.command }} --version
-fort 0.0.1
+fort {{ site.fort-latest-version }}
{% endhighlight %}
### `--tal`
- **Type:** Integer
- **Availability:** `argv` and JSON
- **Default:** 32
+- **Range:** 5--([`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)--1)
Maximum allowable RPKI tree height. Meant to protect Fort from iterating infinitely due to certificate chain loops.
- **Type:** Integer
- **Availability:** `argv` and JSON
- **Default:** 3600
-- **Range:** 60--[`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/)
+- **Range:** 60--[`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
Number of seconds the server will sleep between validation cycles.
The configuration options are mostly the same as the ones from the `argv` interface. (See the "Availability" metadata of each field.) Here's a full configuration file example:
<pre><code>{
- "<a href="#--tal">tal</a>": "/tmp/tal/test.tal",
- "<a href="#--local-repository">local-repository</a>": "/tmp/repository",
+ "<a href="#--tal">tal</a>": "/tmp/fort/tal/test.tal",
+ "<a href="#--local-repository">local-repository</a>": "/tmp/fort/repository",
"<a href="#--sync-strategy">sync-strategy</a>": "root",
"<a href="#--shuffle-uris">shuffle-uris</a>": true,
- "<a href="#--slurm">slurm</a>": "/tmp/test.slurm",
+ "<a href="#--slurm">slurm</a>": "/tmp/fort/test.slurm",
"<a href="#--mode">mode</a>": "server",
"server": {
"<a href="#incidences">incidences</a>": [
{
- "name": "Signed Object's hash algorithm has NULL object as parameters",
+ "name": "incid-hashalg-has-params",
"action": "ignore"
}
],
"output": {
- "<a href="#--outputroa">roa</a>": "/tmp/fort_roas.csv",
- "<a href="#--outputbgpsec">bgpsec</a>": "/tmp/fort_bgpsec.csv"
+ "<a href="#--outputroa">roa</a>": "/tmp/fort/roas.csv",
+ "<a href="#--outputbgpsec">bgpsec</a>": "/tmp/fort/bgpsec.csv"
}
}
</code></pre>
{
"local-repository": "a",
"sync-strategy": "root",
- "maximum-certificate-depth": 1
+ "maximum-certificate-depth": 5
}
$ cat b.json
{
"sync-strategy": "strict"
- "maximum-certificate-depth": 2
+ "maximum-certificate-depth": 6
}
$ cat c.json
{
- "maximum-certificate-depth": 4
+ "maximum-certificate-depth": 8
}
$ {{ page.command }} \
--configuration-file="a.json" \
--configuration-file="b.json" \
--configuration-file="c.json"
-$ # local-repository is "a", sync-strategy is "strict" and maximum-certificate-depth is 4
+$ # local-repository is "a", sync-strategy is "strict" and maximum-certificate-depth is 8
{% endhighlight %}
### rsync.program
---
title: Home
-layout: home
---
# {{ page.title }}
## Status
-Fort is currently in beta. Testing is underway.
+Version [{{ site.fort-latest-version }}](https://github.com/NICMx/FORT-validator/releases/tag/v{{ site.fort-latest-version }}){:target="_blank"} is the first official release! Don't forget to read the [docs](doc/index.html).
-$(document).ready(function () {
+$(document).ready(function() {
// Show nav + overlay-content
- $('.menu-open').click(function () {
- if ($(this).hasClass('clic')) {
+ $('.menu-open').click(function() {
+ if($(this).hasClass('clic')){
closeNavigation();
- } else {
+ }else{
openNavigation();
}
$(this).toggleClass('clic');
});
- // $('.overlay-content').click(function() {
- // closeNavigation();
- // });
-
- // $('.menu-close').click(function() {
- // closeNav();
- // });
-
- function openNavigation() {
- // $('body').addClass('nav-fixed');
+ function openNavigation(){
$('.navigation').fadeIn();
- // $('.js-overlay').fadeIn();
}
- function closeNavigation() {
- // $('body').removeClass('nav-fixed');
+ function closeNavigation(){
$('.navigation').fadeOut();
- // $('.js-overlay').fadeOut();
}
// Header fixed
- $(function () {
+ $(function(){
var shrinkHeader = 80;
- $(window).scroll(function () {
+ $(window).scroll(function() {
var scroll = getCurrentScroll();
- if (scroll >= shrinkHeader) {
+ if ( scroll >= shrinkHeader ) {
$('.site-header').addClass('small-header');
- } else {
+ }else {
$('.site-header').removeClass('small-header');
}
});
return window.pageYOffset || document.documentElement.scrollTop;
}
- $(document).ready(function() { var pathname = window.location.pathname;
- pathname = pathname.replace('/FORT-validator/doc', '.');
- pathname = pathname.replace('/FORT-validator', '.');
-
- //get the path of current page
- $('.site-nav > ul > li > a[href="'+pathname+'"]').addClass('active-item');
- })
-
-
});
-.TH fort 8 "2019-06-07" "v0.0.1-beta" "FORT validator"
+.TH fort 8 "2019-08-26" "v1.0.0" "FORT validator"
.SH NAME
fort \- RPKI certificate path validator
.RS 2
{
.RS 2
-"name": "Signed Object's hash algorithm has NULL object as parameters",
+"name": "incid-hashalg-has-params",
.br
"action": "warn"
.RE
happened.
.RE
.P
-By default, all the incidences have an action of \fIerror\fR. Currently there's
+By default, all the incidences have an action of \fIignore\fR. Currently there's
only one registered incidence:
-\fISigned Object's hash algorithm has NULL object as parameters\fR.
+\fIincid-hashalg-has-params\fR (Signed Object's hash algorithm has NULL object
+as parameters).
.P
More information about incidences can be consulted at FORT's web docs.
.RE
Right now, FORT accesses RPKI repositories by way of \fIrsync\fR. During each
validation cycle, FORT will literally invoke an rsync command (see
\fBrsync.program\fR and \fBrsync.arguments-recursive\fR), which will download
-the files into \fB--local-repository\fR. FORT’s validation operates on the resulting
-copy.
+the files into \fB--local-repository\fR. FORT’s validation operates on the
+resulting copy.
.P
Because rsync uses delta encoding, you’re advised to keep this cache around. It
significantly speeds up subsequent validation cycles.
+.P
+By default, the path is \fI/tmp/fort/repository\fR.
.RE
.P
Maximum allowable certificate chain length. Meant to protect FORT from
iterating infinitely due to certificate chain loops.
.P
-By default, it has a value of \fI32\fR.
+By default, it has a value of \fI32\fR. The minimum allowed value is 5.
.P
(Required to prevent loops and "other degenerate forms of the logical RPKI
hierarchy." (RFC 6481))
.nf
{
- "tal": "/tmp/tal/",
- "local-repository": "/tmp/repository",
+ "tal": "/tmp/fort/tal/",
+ "local-repository": "/tmp/fort/repository",
"sync-strategy": "root",
"shuffle-uris": true,
"maximum-certificate-depth": 32,
},
"incidences": [
{
- "name": "Signed Object's hash algorithm has NULL object as parameters",
+ "name": "incid-hashalg-has-params",
"action": "ignore"
}
],
"output": {
- "roa": "/tmp/fort_roas.csv",
- "bgpsec": "/tmp/fort_bgpsec.csv"
+ "roa": "/tmp/fort/roas.csv",
+ "bgpsec": "/tmp/fort/bgpsec.csv"
}
}
.fi
More documentation about FORT validator can be consulted at github repository
(https://github.com/NICMx/FORT-validator) and github website
(https://nicmx.github.io/FORT-validator/)
-.RE
\ No newline at end of file
+.RE
return 0;
}
+
+/*
+ * Check if @son_addr is covered by @f_addr prefix of @f_len length
+ */
+bool
+ipv4_covered(struct in_addr *f_addr, uint8_t f_len, struct in_addr *son_addr)
+{
+ return (son_addr->s_addr & ~be32_suffix_mask(f_len)) == f_addr->s_addr;
+}
+
+/*
+ * Check if @son_addr is covered by @f_addr prefix of @f_len length
+ */
+bool
+ipv6_covered(struct in6_addr *f_addr, uint8_t f_len, struct in6_addr *son_addr)
+{
+ struct in6_addr suffix;
+ unsigned int i;
+
+ memset(&suffix, 0, sizeof(suffix));
+ ipv6_suffix_mask(f_len, &suffix);
+
+ for (i = 0; i < 16; i++)
+ if ((son_addr->s6_addr[i] & ~suffix.s6_addr[i]) !=
+ f_addr->s6_addr[i])
+ return false;
+
+ return true;
+}
int ipv4_prefix_validate(struct ipv4_prefix *);
int ipv6_prefix_validate(struct ipv6_prefix *);
+bool ipv4_covered(struct in_addr *, uint8_t, struct in_addr *);
+bool ipv6_covered(struct in6_addr *, uint8_t, struct in6_addr *);
+
#endif /* SRC_ADDRESS_H_ */
#define _POSIX_PTHREAD_SEMANTICS /* for Sun */
#define _REENTRANT /* for Sun */
#define __EXTENSIONS__ /* for Sun */
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE 1
+#endif
#ifndef _BSD_SOURCE
#define _BSD_SOURCE /* for timegm(3) */
#endif
goto end1;
}
+ x509_name_pr_debug("Issuer", X509_get_issuer_name(cert));
+
error = certificate_validate_chain(cert, args->crls);
if (error)
goto end2;
}
int
-signed_data_decode(ANY_t *coded, struct signed_object_args *args,
- struct SignedData **result)
+signed_data_decode(struct signed_data *sdata, ANY_t *coded)
{
- struct SignedData *sdata;
int error;
+ sdata->encoded = coded;
+
/* rfc6488#section-3.1.l */
/* TODO (next iteration) this is BER, not guaranteed to be DER. */
- error = asn1_decode_any(coded, &asn_DEF_SignedData, (void **) &sdata,
- false);
+ error = asn1_decode_any(coded, &asn_DEF_SignedData,
+ (void **) &sdata->decoded, false);
if (error) {
/* Try to decode as PKCS content (RFC 5652 section 5.2.1) */
- error = signed_data_decode_pkcs7(coded, &sdata);
- if (error)
- return (error);
+ error = signed_data_decode_pkcs7(coded, &sdata->decoded);
}
- error = validate(sdata, coded, args);
- if (error) {
- signed_data_free(sdata);
- return error;
- }
+ return error;
+}
- *result = sdata;
- return 0;
+int
+signed_data_validate(struct signed_data *sdata, struct signed_object_args *args)
+{
+ /*
+ * TODO (fine) maybe collapse this wrapper,
+ * since there's no point to it anymore.
+ */
+ return validate(sdata->decoded, sdata->encoded, args);
}
void
-signed_data_free(struct SignedData *sdata)
+signed_data_cleanup(struct signed_data *sdata)
{
- ASN_STRUCT_FREE(asn_DEF_SignedData, sdata);
+ ASN_STRUCT_FREE(asn_DEF_SignedData, sdata->decoded);
}
/* Caller must free *@result. */
/*
* This only exists to reduce argument lists.
+ * TODO (fine) rename to signed_data_args, since it has nothing to do with
+ * signed objects anymore.
*/
struct signed_object_args {
/** Location of the signed object. */
STACK_OF(X509_CRL) *, bool);
void signed_object_args_cleanup(struct signed_object_args *);
-int signed_data_decode(ANY_t *, struct signed_object_args *args,
- struct SignedData **);
-void signed_data_free(struct SignedData *);
+struct signed_data {
+ ANY_t *encoded;
+ struct SignedData *decoded;
+};
+
+int signed_data_decode(struct signed_data *, ANY_t *);
+int signed_data_validate(struct signed_data *, struct signed_object_args *);
+void signed_data_cleanup(struct signed_data *);
int get_content_type_attr(struct SignedData *, OBJECT_IDENTIFIER_t **);
static int
process_file(char const *dir_name, char const *file_name, char const *file_ext,
- process_file_cb cb, void *arg)
+ int *fcount, process_file_cb cb, void *arg)
{
char *ext, *fullpath, *tmp;
int error;
return 0;
}
+ (*fcount)++; /* Increment the found count */
+
/* Get the full file path */
tmp = strdup(dir_name);
if (tmp == NULL)
{
DIR *dir_loc;
struct dirent *dir_ent;
- int error;
+ int found, error;
dir_loc = opendir(location);
if (dir_loc == NULL) {
}
errno = 0;
+ found = 0;
while ((dir_ent = readdir(dir_loc)) != NULL) {
- error = process_file(location, dir_ent->d_name, file_ext, cb,
- arg);
+ error = process_file(location, dir_ent->d_name, file_ext,
+ &found, cb, arg);
if (error) {
pr_err("The error was at file %s", dir_ent->d_name);
goto close_dir;
pr_err("Error reading dir %s", location);
error = -errno;
}
+ if (!error && found == 0)
+ pr_warn("Location '%s' doesn't have files with extension '%s'",
+ location, file_ext);
close_dir:
closedir(dir_loc);
end:
#include "common.h"
#include "configure_ac.h"
+#include "file.h"
#include "json_handler.h"
#include "log.h"
#include "config/boolean.h"
.offset = offsetof(struct rpki_config,
maximum_certificate_depth),
.doc = "Maximum allowable certificate chain length",
- .min = 1,
+ .min = 5,
/**
* It cannot be UINT_MAX, because then the actual number will
* overflow and will never be bigger than this.
.offset = offsetof(struct rpki_config, output.roa),
.doc = "File where ROAs will be stored in CSV format, use '-' to print at console",
.arg_doc = "<file>",
- },
- {
+ }, {
.id = 6001,
.name = "output.bgpsec",
.type = >_string,
return error;
}
+static bool
+valid_output_file(char const *path)
+{
+ return strcmp(path, "-") == 0 || file_valid(path);
+}
+
static int
validate_config(void)
{
rpki_config.server.interval.retry)
return pr_err("Expire interval must be greater than refresh and retry intervals");
+ if (rpki_config.output.roa != NULL &&
+ !valid_output_file(rpki_config.output.roa))
+ return pr_err("Invalid output.roa file.");
+
return (rpki_config.tal != NULL)
? 0
: pr_err("The TAL file/directory (--tal) is mandatory.");
parse_argv_uint(struct option_field const *field, char const *str,
void *result)
{
+ char *tmp;
unsigned long parsed;
if (field->type->has_arg != required_argument || str == NULL) {
}
errno = 0;
- parsed = strtoul(str, NULL, 10);
- if (errno)
- return pr_errno(errno, "'%s' is not an unsigned integer", str);
+ parsed = strtoul(str, &tmp, 10);
+ if (errno || *tmp != '\0')
+ return errno ? pr_errno(errno,
+ "Value '%s' at '%s' is not an unsigned integer", str,
+ field->name) :
+ pr_err("Value '%s' at '%s' is not an unsigned integer",
+ str, field->name);
if (parsed < field->min || field->max < parsed) {
- return pr_err("'%lu' is out of bounds (%u-%u).", parsed,
- field->min, field->max);
+ return pr_err("Value of '%s' is out of range (%u-%u).",
+ field->name, field->min, field->max);
}
*((unsigned int *) result) = parsed;
{
free(fc->buffer);
}
+
+/*
+ * Validate @file_name, if it doesn't exist, this function will create it and
+ * close it.
+ */
+bool
+file_valid(char const *file_name)
+{
+ FILE *tmp;
+ struct stat stat;
+ int error;
+
+ if (file_name == NULL)
+ return false;
+
+ error = file_write(file_name, &tmp, &stat);
+ if (error)
+ return false;
+
+ file_close(tmp);
+ return true;
+}
#ifndef SRC_FILE_H_
#define SRC_FILE_H_
+#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/stat.h>
int file_load(char const *, struct file_contents *);
void file_free(struct file_contents *);
+bool file_valid(char const *);
+
#endif /* SRC_FILE_H_ */
struct incidence {
const enum incidence_id id;
char const *const name;
+ char const *const description;
const enum incidence_action default_action;
enum incidence_action action;
};
static struct incidence incidences[__INID_MAX] = {
{
INID_HASHALG_HAS_PARAMS,
+ "incid-hashalg-has-params",
"Signed Object's hash algorithm has NULL object as parameters",
- INAC_ERROR,
+ INAC_IGNORE,
},
};
else
return pr_err("Unknown incidence action: '%s'", action_str);
- if (action > incidences[id].action)
- return pr_err("The '%s' incidence cannot have a more severe action than '%s'.",
- name, action2str(incidences[id].action));
-
incidences[id].action = action;
return 0;
}
incidence_print(void)
{
array_index i;
- bool printed;
pr_info("Custom incidences:");
pr_indent_add();
- printed = false;
-
for (i = 0; i < __INID_MAX; i++) {
- if (incidences[i].action != incidences[i].default_action) {
- pr_info("%s: %s", incidences[i].name,
- action2str(incidences[i].action));
- printed = true;
- }
+ pr_info("%s (%s): %s", incidences[i].name,
+ incidences[i].description,
+ action2str(incidences[i].action));
}
- if (!printed)
- pr_info("<None>");
-
pr_indent_rm();
}
#include "asn1/oid.h"
#include "asn1/asn1c/IPAddrBlocks.h"
#include "crypto/hash.h"
-#include "object/name.h"
#include "object/bgpsec.h"
+#include "object/name.h"
#include "object/manifest.h"
#include "rsync/rsync.h"
if (!is_ta)
return validate_issuer_name("Certificate", issuer);
+ /* TODO wait. Shouldn't we check subject == issuer? */
+
error = x509_name_decode(issuer, "issuer", &name);
- if (!error)
- x509_name_put(name);
+ if (error)
+ return error;
+ pr_debug("Issuer: %s", x509_name_commonName(name));
- return error;
+ x509_name_put(name);
+ return 0;
}
static int
error = x509_name_decode(X509_get_subject_name(cert), "subject", &name);
if (error)
return error;
+ pr_debug("Subject: %s", x509_name_commonName(name));
error = x509stack_store_subject(validation_certstack(state), name);
if (error)
goto revert_uris;
- /* -- Validate the manifest (@mft) pointed by the certificate -- */
- error = x509stack_push(validation_certstack(state), cert_uri, cert,
- policy, type);
- if (error)
- goto revert_uris;
-
if (type == BGPSEC) {
/* This is an EE, so there's no manifest to process */
error = handle_bgpsec(cert, ski,
goto revert_refs;
}
- cert = NULL; /* Ownership stolen */
/*
* RFC 6481 section 5: "when the repository publication point contents
*/
mft_retry = true;
do {
- error = handle_manifest(mft, rpp_parent_crl, &pp);
+ /* Validate the manifest (@mft) pointed by the certificate */
+ error = x509stack_push(validation_certstack(state), cert_uri,
+ cert, policy, IS_TA);
+ if (error) {
+ if (!mft_retry)
+ uri_refput(mft);
+ goto revert_uris;
+ }
+ cert = NULL; /* Ownership stolen */
+
+ error = handle_manifest(mft, &pp);
if (!mft_retry)
uri_refput(mft);
if (!error || !mft_retry)
error = download_files(caRepository, false, true);
if (error)
break;
+
+ /* Cancel stack, reload certificate (no need to revalidate) */
+ x509stack_cancel(validation_certstack(state));
+ error = certificate_load(cert_uri, &cert);
+ if (error) {
+ goto revert_uris;
+ }
uri_refget(mft);
mft_retry = false;
} while (true);
#include "vcard.h"
static int
-handle_vcard(OCTET_STRING_t *vcard, void *arg)
+handle_vcard(struct signed_object *sobj)
{
- return handle_ghostbusters_vcard(vcard);
+ return handle_ghostbusters_vcard(
+ sobj->sdata.decoded->encapContentInfo.eContent
+ );
}
int
{
static OID oid = OID_GHOSTBUSTERS;
struct oid_arcs arcs = OID2ARCS("ghostbusters", oid);
+ struct signed_object sobj;
struct signed_object_args sobj_args;
STACK_OF(X509_CRL) *crl;
int error;
+ /* Prepare */
pr_debug_add("Ghostbusters '%s' {", uri_get_printable(uri));
fnstack_push_uri(uri);
- error = rpp_crl(pp, &crl);
+ /* Decode */
+ error = signed_object_decode(&sobj, uri);
if (error)
- goto end1;
+ goto revert_log;
+ /* Prepare validation arguments */
+ error = rpp_crl(pp, &crl);
+ if (error)
+ goto revert_sobj;
error = signed_object_args_init(&sobj_args, uri, crl, true);
if (error)
- goto end1;
+ goto revert_sobj;
- error = signed_object_decode(&sobj_args, &arcs, handle_vcard, NULL);
+ /* Validate everything */
+ error = signed_object_validate(&sobj, &arcs, &sobj_args);
if (error)
- goto end2;
-
+ goto revert_args;
+ error = handle_vcard(&sobj);
+ if (error)
+ goto revert_args;
error = refs_validate_ee(&sobj_args.refs, pp, sobj_args.uri);
-end2:
+revert_args:
signed_object_args_cleanup(&sobj_args);
-end1:
+revert_sobj:
+ signed_object_cleanup(&sobj);
+revert_log:
pr_debug_rm("}");
fnstack_pop();
return error;
#include "object/signed_object.h"
static int
-manifest_decode(OCTET_STRING_t *string, void *arg)
+decode_manifest(struct signed_object *sobj, struct Manifest **result)
{
- return asn1_decode_octet_string(string, &asn_DEF_Manifest, arg, true);
+ return asn1_decode_octet_string(
+ sobj->sdata.decoded->encapContentInfo.eContent,
+ &asn_DEF_Manifest,
+ (void **) result,
+ true
+ );
}
static int
}
static int
-__handle_manifest(struct Manifest *mft, struct rpki_uri *mft_uri,
- struct rpp **pp)
+build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, struct rpp **pp)
{
int i;
struct FileAndHash *fah;
* @pp.
*/
int
-handle_manifest(struct rpki_uri *uri, STACK_OF(X509_CRL) *crls, struct rpp **pp)
+handle_manifest(struct rpki_uri *uri, struct rpp **pp)
{
static OID oid = OID_MANIFEST;
struct oid_arcs arcs = OID2ARCS("manifest", oid);
+ struct signed_object sobj;
struct signed_object_args sobj_args;
struct Manifest *mft;
+ STACK_OF(X509_CRL) *crl;
int error;
+ /* Prepare */
pr_debug_add("Manifest '%s' {", uri_get_printable(uri));
fnstack_push_uri(uri);
- error = signed_object_args_init(&sobj_args, uri, crls, false);
+ /* Decode */
+ error = signed_object_decode(&sobj, uri);
if (error)
- goto end1;
+ goto revert_log;
+ error = decode_manifest(&sobj, &mft);
+ if (error)
+ goto revert_sobj;
- error = signed_object_decode(&sobj_args, &arcs, manifest_decode, &mft);
+ /* Initialize out parameter (@pp) */
+ error = build_rpp(mft, uri, pp);
if (error)
- goto end2;
+ goto revert_manifest;
- error = validate_manifest(mft);
+ /* Prepare validation arguments */
+ error = rpp_crl(*pp, &crl);
if (error)
- goto end3;
- error = __handle_manifest(mft, uri, pp);
+ goto revert_rpp;
+ error = signed_object_args_init(&sobj_args, uri, crl, false);
if (error)
- goto end3;
+ goto revert_rpp;
+ /* Validate everything */
+ error = signed_object_validate(&sobj, &arcs, &sobj_args);
+ if (error)
+ goto revert_args;
+ error = validate_manifest(mft);
+ if (error)
+ goto revert_args;
error = refs_validate_ee(&sobj_args.refs, *pp, uri);
if (error)
- rpp_refput(*pp);
+ goto revert_args;
-end3:
- ASN_STRUCT_FREE(asn_DEF_Manifest, mft);
-end2:
+ /* Success */
+ signed_object_args_cleanup(&sobj_args);
+ goto revert_manifest;
+
+revert_args:
signed_object_args_cleanup(&sobj_args);
-end1:
+revert_rpp:
+ rpp_refput(*pp);
+revert_manifest:
+ ASN_STRUCT_FREE(asn_DEF_Manifest, mft);
+revert_sobj:
+ signed_object_cleanup(&sobj);
+revert_log:
pr_debug_rm("}");
fnstack_pop();
return error;
#ifndef SRC_OBJECT_MANIFEST_H_
#define SRC_OBJECT_MANIFEST_H_
-#include <openssl/x509.h>
#include "uri.h"
#include "rpp.h"
-int handle_manifest(struct rpki_uri *, STACK_OF(X509_CRL) *, struct rpp **);
+int handle_manifest(struct rpki_uri *, struct rpp **);
#endif /* SRC_OBJECT_MANIFEST_H_ */
error = x509_name_decode(issuer, "issuer", &child_issuer);
if (error)
goto end;
+ pr_debug("Issuer: %s", child_issuer->commonName);
if (!x509_name_equals(parent_subject, child_issuer)) {
char const *parent_serial;
end: x509_name_put(parent_subject);
return error;
}
+
+#ifdef DEBUG
+
+void
+x509_name_pr_debug(const char *prefix, X509_NAME *name)
+{
+ struct rfc5280_name *printable;
+
+ if (name == NULL) {
+ pr_debug("%s: (null)", prefix);
+ return;
+ }
+
+ if (x509_name_decode(name, prefix, &printable) != 0)
+ return; /* Error message already printed */
+
+ pr_debug("%s: %s", prefix, printable->commonName);
+ x509_name_put(printable);
+}
+
+#endif
bool x509_name_equals(struct rfc5280_name *, struct rfc5280_name *);
+
+/* X509_NAME utils */
int validate_issuer_name(char const *, X509_NAME *);
+#ifdef DEBUG
+void x509_name_pr_debug(char const *, X509_NAME *);
+#else
+#define x509_name_pr_debug(a, b) /* Nothing */
+#endif
+
#endif /* SRC_OBJECT_NAME_H_ */
#include "object/signed_object.h"
static int
-roa_decode(OCTET_STRING_t *string, void *arg)
+decode_roa(struct signed_object *sobj, struct RouteOriginAttestation **result)
{
- return asn1_decode_octet_string(string, &asn_DEF_RouteOriginAttestation,
- arg, true);
+ return asn1_decode_octet_string(
+ sobj->sdata.decoded->encapContentInfo.eContent,
+ &asn_DEF_RouteOriginAttestation,
+ (void **) result,
+ true
+ );
}
static int
int a;
int error;
-
pr_debug_add("eContent {");
if (roa->version != NULL) {
error = asn_INTEGER2ulong(roa->version, &version);
/* rfc6482#section-3.3 */
- if (roa->ipAddrBlocks.list.array == NULL)
- pr_crit("ipAddrBlocks array is NULL.");
+ if (roa->ipAddrBlocks.list.array == NULL) {
+ error = pr_err("ipAddrBlocks array is NULL.");
+ goto end_error;
+ }
pr_debug_add("ipAddrBlocks {");
for (b = 0; b < roa->ipAddrBlocks.list.count; b++) {
{
static OID oid = OID_ROA;
struct oid_arcs arcs = OID2ARCS("roa", oid);
+ struct signed_object sobj;
struct signed_object_args sobj_args;
struct RouteOriginAttestation *roa;
STACK_OF(X509_CRL) *crl;
int error;
+ /* Prepare */
pr_debug_add("ROA '%s' {", uri_get_printable(uri));
fnstack_push_uri(uri);
- error = rpp_crl(pp, &crl);
+ /* Decode */
+ error = signed_object_decode(&sobj, uri);
if (error)
- goto revert_fnstack;
-
- error = signed_object_args_init(&sobj_args, uri, crl, false);
- if (error)
- goto revert_fnstack;
-
- error = signed_object_decode(&sobj_args, &arcs, roa_decode, &roa);
+ goto revert_log;
+ error = decode_roa(&sobj, &roa);
if (error)
goto revert_sobj;
- error = refs_validate_ee(&sobj_args.refs, pp, sobj_args.uri);
+ /* Prepare validation arguments */
+ error = rpp_crl(pp, &crl);
+ if (error)
+ goto revert_roa;
+ error = signed_object_args_init(&sobj_args, uri, crl, false);
if (error)
goto revert_roa;
+ /* Validate and handle everything */
+ error = signed_object_validate(&sobj, &arcs, &sobj_args);
+ if (error)
+ goto revert_args;
error = __handle_roa(roa, sobj_args.res);
+ if (error)
+ goto revert_args;
+ error = refs_validate_ee(&sobj_args.refs, pp, sobj_args.uri);
+revert_args:
+ signed_object_args_cleanup(&sobj_args);
revert_roa:
ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
revert_sobj:
- signed_object_args_cleanup(&sobj_args);
-revert_fnstack:
+ signed_object_cleanup(&sobj);
+revert_log:
fnstack_pop();
pr_debug_rm("}");
return error;
#include "log.h"
#include "asn1/content_info.h"
+int
+signed_object_decode(struct signed_object *sobj, struct rpki_uri *uri)
+{
+ int error;
+
+ error = content_info_load(uri, &sobj->cinfo);
+ if (error)
+ return error;
+
+ error = signed_data_decode(&sobj->sdata, &sobj->cinfo->content);
+ if (error) {
+ content_info_free(sobj->cinfo);
+ return error;
+ }
+
+ return 0;
+}
+
static int
validate_eContentType(struct SignedData *sdata, struct oid_arcs const *oid)
{
}
int
-signed_object_decode(struct signed_object_args *args,
- struct oid_arcs const *oid,
- signed_object_cb cb,
- void *cb_arg)
+signed_object_validate(struct signed_object *sobj, struct oid_arcs const *oid,
+ struct signed_object_args *args)
{
- struct ContentInfo *cinfo;
- struct SignedData *sdata;
int error;
- error = content_info_load(args->uri, &cinfo);
- if (error)
- goto end1;
-
- error = signed_data_decode(&cinfo->content, args, &sdata);
- if (error)
- goto end2;
-
/* rfc6482#section-2 */
/* rfc6486#section-4.1 */
/* rfc6486#section-4.4.1 */
- error = validate_eContentType(sdata, oid);
+ error = validate_eContentType(sobj->sdata.decoded, oid);
if (error)
- goto end3;
+ return error;
/* rfc6482#section-2 */
/* rfc6486#section-4.3 */
- error = validate_content_type(sdata, oid);
+ error = validate_content_type(sobj->sdata.decoded, oid);
if (error)
- goto end3;
+ return error;
- error = cb(sdata->encapContentInfo.eContent, cb_arg);
+ return signed_data_validate(&sobj->sdata, args);
+}
-end3: signed_data_free(sdata);
-end2: content_info_free(cinfo);
-end1: return error;
+void
+signed_object_cleanup(struct signed_object *sobj)
+{
+ content_info_free(sobj->cinfo);
+ signed_data_cleanup(&sobj->sdata);
}
#ifndef SRC_OBJECT_SIGNED_OBJECT_H_
#define SRC_OBJECT_SIGNED_OBJECT_H_
-#include <openssl/x509.h>
#include "asn1/oid.h"
#include "asn1/signed_data.h"
-typedef int (*signed_object_cb)(OCTET_STRING_t *, void *);
+struct signed_object {
+ struct ContentInfo *cinfo;
+ struct signed_data sdata;
+};
-int signed_object_decode(struct signed_object_args *, struct oid_arcs const *,
- signed_object_cb, void *);
+int signed_object_decode(struct signed_object *, struct rpki_uri *);
+int signed_object_validate(struct signed_object *, struct oid_arcs const *,
+ struct signed_object_args *);
+void signed_object_cleanup(struct signed_object *);
#endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <sys/stat.h>
#include <openssl/evp.h>
} while (true);
}
+static size_t
+get_spki_orig_size(struct line_file *lfile)
+{
+ struct stat st;
+ size_t result;
+
+ stat(lfile_name(lfile), &st);
+ result = st.st_size - lfile_offset(lfile);
+ return result;
+}
+
/*
* Will usually allocate slightly more because of the newlines, but I'm fine
* with it.
static size_t
get_spki_alloc_size(struct line_file *lfile)
{
- struct stat st;
- size_t result;
+ return EVP_DECODE_LENGTH(get_spki_orig_size(lfile));
+}
- stat(lfile_name(lfile), &st);
- result = st.st_size - lfile_offset(lfile);
+/*
+ * Get the base64 chars from @lfile and allocate to @out with lines no greater
+ * than 65 chars (including line feed).
+ *
+ * Why? LibreSSL doesn't like lines greater than 80 chars, so use a common
+ * length per line.
+ */
+static int
+base64_sanitize(struct line_file *lfile, char **out)
+{
+#define BUF_SIZE 65
+ FILE *fd;
+ char buf[BUF_SIZE];
+ char *result, *eol;
+ size_t original_size, new_size;
+ size_t fread_result, offset;
+ int error;
- return EVP_DECODE_LENGTH(result);
+ /*
+ * lfile_read() isn't called since the lines aren't returned as needed
+ * "sanitized" (a.k.a. each line with a desired length)
+ */
+ original_size = get_spki_orig_size(lfile);
+ new_size = original_size + (original_size / BUF_SIZE);
+ result = malloc(new_size + 1);
+ if (result == NULL)
+ return pr_enomem();
+
+ fd = lfile_fd(lfile);
+ offset = 0;
+ while ((fread_result = fread(buf, 1,
+ (original_size > BUF_SIZE) ? BUF_SIZE : original_size, fd)) > 0) {
+ error = ferror(lfile_fd(lfile));
+ if (error) {
+ /*
+ * The manpage doesn't say that the result is an error
+ * code. It literally doesn't say how to get an error
+ * code.
+ */
+ pr_errno(error,
+ "File reading error. Error message (apparently)");
+ goto free_result;
+ }
+
+ original_size -= fread_result;
+ eol = strchr(buf, '\n');
+ /* Larger than buffer length, add LF and copy last char */
+ if (eol == NULL) {
+ memcpy(&result[offset], buf, fread_result - 1);
+ offset += fread_result - 1;
+ result[offset] = '\n';
+ result[offset + 1] = buf[fread_result - 1];
+ offset += 2;
+ continue;
+ }
+ /* Copy till last LF */
+ memcpy(&result[offset], buf, eol - buf + 1);
+ offset += eol - buf + 1;
+ if (eol - buf + 1 < fread_result) {
+ /* And add new line with remaining chars */
+ memcpy(&result[offset], eol + 1,
+ buf + fread_result - 1 - eol);
+ offset += buf + fread_result -1 - eol;
+ result[offset] = '\n';
+ offset++;
+ }
+ }
+ /* Reallocate to exact size and add nul char */
+ if (offset != new_size + 1) {
+ eol = realloc(result, offset + 1);
+ if (eol == NULL) {
+ error = pr_enomem();
+ goto free_result;
+ }
+ result = eol;
+ }
+ result[offset] = '\0';
+
+ *out = result;
+ return 0;
+free_result:
+ free(result);
+ return error;
+#undef BUF_SIZE
}
static int
read_spki(struct line_file *lfile, struct tal *tal)
{
BIO *encoded; /* base64 encoded. */
+ char *tmp;
size_t alloc_size;
int error;
alloc_size = get_spki_alloc_size(lfile);
tal->spki = malloc(alloc_size);
if (tal->spki == NULL)
- return -ENOMEM;
+ return pr_enomem();
- encoded = BIO_new_fp(lfile_fd(lfile), BIO_NOCLOSE);
+ tmp = NULL;
+ error = base64_sanitize(lfile, &tmp);
+ if (error) {
+ free(tal->spki);
+ return error;
+ }
+
+ encoded = BIO_new_mem_buf(tmp, -1);
if (encoded == NULL) {
free(tal->spki);
- return crypto_err("BIO_new_fp() returned NULL");
+ free(tmp);
+ return crypto_err("BIO_new_mem_buf() returned NULL");
}
error = base64_decode(encoded, tal->spki, true, alloc_size,
- &tal->spki_len);
+ &tal->spki_len);
if (error)
free(tal->spki);
+ free(tmp);
BIO_free(encoded);
return error;
}
error = download_files(uri, true, false);
if (error) {
- return pr_warn("TAL '%s' could not be RSYNC'd.",
+ pr_warn("TAL '%s' could not be RSYNC'd.",
uri_get_printable(uri));
+ return ENSURE_NEGATIVE(error);
}
error = validation_prepare(&state, tal, arg);
error = pr_err("None of the URIs of the TAL '%s' yielded a successful traversal.",
tal_file);
-end: tal_destroy(tal);
+ tal_destroy(tal);
+end:
fnstack_pop();
return error;
}
int child_status;
int error;
+ child_status = 0;
error = create_dir_recursive(uri);
if (error)
return error;
/* This code is run by us. */
error = waitpid(child_pid, &child_status, 0);
- if (error == -1) {
- error = errno;
- pr_err("The rsync sub-process returned error %d (%s)",
- error, strerror(error));
- return error;
- }
+ do {
+ if (error == -1) {
+ error = errno;
+ pr_err("The rsync sub-process returned error %d (%s)",
+ error, strerror(error));
+ if (child_status > 0)
+ break;
+ return error;
+ }
+ } while (0);
if (WIFEXITED(child_status)) {
/* Happy path (but also sad path sometimes). */
pr_err("The RSYNC was terminated by a signal I don't have a handler for. Dunno; guess I'll just die.");
break;
}
- exit(-EINTR); /* Meh? */
+ return -EINTR; /* Meh? */
}
pr_err("The RSYNC command died in a way I don't have a handler for. Dunno; guess I'll die as well.");
- exit(-EINVAL);
+ return -EINVAL;
}
/**
#include <stdint.h>
#include <netinet/in.h>
+#include "address.h"
#include "object/router_key.h"
#define FLAG_WITHDRAWAL 0
#define VRP_MAX_PREFIX_LEN_EQ(a, b) \
(a)->max_prefix_length == (b)->max_prefix_length
+#define SAME_ADDR_FAM(a, b, fam) \
+ (a)->addr_fam == fam && \
+ (b)->addr_fam == fam
+
#define VRP_PREFIX_V4_EQ(a, b) \
- ((a)->addr_fam == AF_INET && \
- (b)->addr_fam == AF_INET && \
+ (SAME_ADDR_FAM(a, b, AF_INET) && \
(a)->prefix.v4.s_addr == (b)->prefix.v4.s_addr && \
(a)->prefix_length == (b)->prefix_length)
+#define VRP_PREFIX_V4_COV(a, b) \
+ (SAME_ADDR_FAM(a, b, AF_INET) && \
+ ipv4_covered(&(a)->prefix.v4, (a)->prefix_length, \
+ &(b)->prefix.v4) && \
+ (a)->prefix_length <= (b)->prefix_length)
+
#define VRP_PREFIX_V6_EQ(a, b) \
- ((a)->addr_fam == AF_INET6 && \
- (b)->addr_fam == AF_INET6 && \
+ (SAME_ADDR_FAM(a, b, AF_INET6) && \
IN6_ARE_ADDR_EQUAL(&(a)->prefix.v6, &(b)->prefix.v6) && \
(a)->prefix_length == (b)->prefix_length)
+#define VRP_PREFIX_V6_COV(a, b) \
+ (SAME_ADDR_FAM(a, b, AF_INET6) && \
+ ipv6_covered(&(a)->prefix.v6, (a)->prefix_length, \
+ &(b)->prefix.v6) && \
+ (a)->prefix_length <= (b)->prefix_length)
+
#define VRP_PREFIX_EQ(a, b) \
(VRP_PREFIX_V4_EQ(a, b) || VRP_PREFIX_V6_EQ(a, b))
+/* Checks if 'a' equals or covers 'b' */
+#define VRP_PREFIX_COV(a, b) \
+ (VRP_PREFIX_V4_COV(a, b) || VRP_PREFIX_V6_COV(a, b))
+
#define VRP_EQ(a, b) \
(VRP_ASN_EQ(a, b) && VRP_PREFIX_EQ(a, b) && VRP_MAX_PREFIX_LEN_EQ(a, b))
#include <errno.h>
#include <netdb.h>
#include <pthread.h>
-#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "rtr/pdu.h"
#include "rtr/db/vrps.h"
-struct sigaction act;
-
struct thread_param {
int fd;
pthread_t tid;
{
char const *hostname;
char const *service;
+ char *tmp;
struct addrinfo hints;
+ unsigned long parsed, port;
int error;
memset(&hints, 0 , sizeof(hints));
hostname = config_get_server_address();
service = config_get_server_port();
+ if (hostname != NULL)
+ hints.ai_flags |= AI_CANONNAME;
+
error = getaddrinfo(hostname, service, &hints, result);
if (error) {
pr_err("Could not infer a bindable address out of address '%s' and port '%s': %s",
return error;
}
+ errno = 0;
+ parsed = strtoul(service, &tmp, 10);
+ if (errno || *tmp != '\0')
+ return 0; /* Ok, not a number */
+
+ /*
+ * 'getaddrinfo' isn't very strict validating the service when a port
+ * number is indicated. If a port larger than the max (65535) is
+ * received, the 16 rightmost bits are utilized as the port and set at
+ * the addrinfo returned.
+ *
+ * So, a manual validation is implemented. Port is actually a uint16_t,
+ * so read what's necessary and compare using the same data type.
+ */
+ port = (unsigned char)((*result)->ai_addr->sa_data[0]) << 8;
+ port += (unsigned char)((*result)->ai_addr->sa_data[1]);
+ if (parsed != port)
+ return pr_err("Service port %s is out of range (max value is %d)",
+ service, USHRT_MAX);
+
return 0;
}
{
struct addrinfo *addrs;
struct addrinfo *addr;
+ unsigned long port;
int fd; /* "file descriptor" */
int error;
continue;
}
- printf("Success.\n");
+ error = getsockname(fd, addr->ai_addr, &addr->ai_addrlen);
+ if (error) {
+ close(fd);
+ freeaddrinfo(addrs);
+ return pr_errno(errno, "getsockname() failed");
+ }
+
+ port = (unsigned char)(addr->ai_addr->sa_data[0]) << 8;
+ port += (unsigned char)(addr->ai_addr->sa_data[1]);
+ printf("Success, bound to address '%s', port '%ld'.\n",
+ (addr->ai_canonname != NULL) ? addr->ai_canonname : "any",
+ port);
freeaddrinfo(addrs);
*result = fd;
return 0; /* Happy path */
return 0; /* Unreachable. */
}
-static void
-signal_handler(int signal, siginfo_t *info, void *param)
-{
- /* Empty handler */
-}
-
-static int
-init_signal_handler(void)
-{
- int error;
-
- memset(&act, 0, sizeof act);
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction = signal_handler;
-
- error = sigaction(SIGINT, &act, NULL);
- if (error) {
- pr_errno(errno, "Error initializing signal handler");
- error = -errno;
- }
- return error;
-}
-
/*
* Receive @arg to be called as a clients_foreach_cb
*/
int server_fd; /* "file descriptor" */
int error;
- error = init_signal_handler();
- if (error)
- return error;
-
error = clients_db_init();
if (error)
return error;
#include "data_structure/array_list.h"
#include "object/router_key.h"
-ARRAY_LIST(al_filter_prefix, struct slurm_prefix)
-ARRAY_LIST(al_assertion_prefix, struct slurm_prefix)
-ARRAY_LIST(al_filter_bgpsec, struct slurm_bgpsec)
-ARRAY_LIST(al_assertion_bgpsec, struct slurm_bgpsec)
+struct slurm_prefix_ctx {
+ struct slurm_prefix element;
+ int ctx;
+};
+
+struct slurm_bgpsec_ctx {
+ struct slurm_bgpsec element;
+ int ctx;
+};
+
+ARRAY_LIST(al_filter_prefix, struct slurm_prefix_ctx)
+ARRAY_LIST(al_assertion_prefix, struct slurm_prefix_ctx)
+ARRAY_LIST(al_filter_bgpsec, struct slurm_bgpsec_ctx)
+ARRAY_LIST(al_assertion_bgpsec, struct slurm_bgpsec_ctx)
struct arraylist_db {
struct al_filter_prefix filter_pfx_al;
}
static bool
-prefix_filtered_by(struct slurm_prefix *filter, struct slurm_prefix *prefix)
+prefix_filtered_by(struct slurm_prefix *filter, struct slurm_prefix *prefix,
+ bool exact_match)
{
struct vrp *filter_vrp, *prefix_vrp;
filter_vrp = &filter->vrp;
prefix_vrp = &prefix->vrp;
+ /* The filter has ASN and prefix */
+ if (exact_match && (filter->data_flag & ~SLURM_COM_FLAG_COMMENT) ==
+ (SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX))
+ return VRP_ASN_EQ(filter_vrp, prefix_vrp) &&
+ VRP_PREFIX_COV(filter_vrp, prefix_vrp);
+
/* Both have ASN */
if ((filter->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
(prefix->data_flag & SLURM_COM_FLAG_ASN) > 0)
/* Both have a prefix of the same type */
if ((filter->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 &&
(prefix->data_flag & SLURM_PFX_FLAG_PREFIX) > 0)
- return VRP_PREFIX_EQ(filter_vrp, prefix_vrp);
+ return VRP_PREFIX_COV(filter_vrp, prefix_vrp);
return false;
}
static bool
-prefix_equal(struct slurm_prefix *left, struct slurm_prefix *right,
- bool filter)
+prefix_contained(struct slurm_prefix_ctx *left_ctx, struct slurm_prefix *right,
+ int ctx)
{
+ struct slurm_prefix *left;
+ struct vrp *left_vrp, *right_vrp;
+
+ /*
+ * rfc8416#section-4.2:
+ * 1. There may be conflicting changes to ROA Prefix Assertions if an
+ * IP address X and distinct SLURM files Y and Z exist such that X
+ * is contained by any prefix in any "prefixAssertions" or
+ * "prefixFilters" in file Y and X is contained by any prefix in any
+ * "prefixAssertions" or "prefixFilters" in file Z.
+ *
+ * A negative @ctx or an equal context will avoid this check.
+ */
+ if (ctx < 0 || ctx == left_ctx->ctx)
+ return false;
+
+ left = &left_ctx->element;
+ left_vrp = &left->vrp;
+ right_vrp = &right->vrp;
+
+ return (left->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 &&
+ (right->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 &&
+ VRP_PREFIX_COV(left_vrp, right_vrp);
+}
+
+/*
+ * @left_ctx is the prefix loaded from SLURM, @right is the VRP "masked" as a
+ * slurm prefix
+ */
+static bool
+prefix_equal(struct slurm_prefix_ctx *left_ctx, struct slurm_prefix *right,
+ int ctx, bool filter, bool exact_match)
+{
+ struct slurm_prefix *left;
struct vrp *left_vrp, *right_vrp;
bool equal;
+ left = &left_ctx->element;
left_vrp = &left->vrp;
right_vrp = &right->vrp;
- /* Ignore the comments */
+ if (prefix_contained(left_ctx, right, ctx))
+ return true;
+
+ /*
+ * Ignore the comments, remember: FILTERS don't have the same data (no
+ * max_length is declared), while ASSERTIONS do.
+ */
if ((left->data_flag & ~SLURM_COM_FLAG_COMMENT) !=
(right->data_flag & ~SLURM_COM_FLAG_COMMENT))
- return filter && prefix_filtered_by(left, right);
+ return filter && prefix_filtered_by(left, right, exact_match);
/* It has the same data, compare it */
equal = true;
- if ((left->data_flag & SLURM_COM_FLAG_ASN) > 0)
- equal = equal && VRP_ASN_EQ(left_vrp, right_vrp);
+ if (equal && (left->data_flag & SLURM_COM_FLAG_ASN) > 0)
+ equal = VRP_ASN_EQ(left_vrp, right_vrp);
if (equal && (left->data_flag & SLURM_PFX_FLAG_PREFIX) > 0)
- equal = equal && VRP_PREFIX_EQ(left_vrp, right_vrp);
+ equal = (filter ?
+ VRP_PREFIX_COV(left_vrp, right_vrp) :
+ VRP_PREFIX_EQ(left_vrp, right_vrp));
if (equal && (left->data_flag & SLURM_PFX_FLAG_MAX_LENGTH) > 0)
- equal = equal &&
- ((left->data_flag & SLURM_PFX_FLAG_MAX_LENGTH) > 0) &&
- VRP_MAX_PREFIX_LEN_EQ(left_vrp, right_vrp);
+ equal = VRP_MAX_PREFIX_LEN_EQ(left_vrp, right_vrp);
return equal;
}
static bool
-bgpsec_filtered_by(struct slurm_bgpsec *bgpsec, struct slurm_bgpsec *filter)
+bgpsec_filtered_by(struct slurm_bgpsec *bgpsec, struct slurm_bgpsec *filter,
+ bool exact_match)
{
+ /* The filter has ASN and SKI */
+ if (exact_match && (filter->data_flag & ~SLURM_COM_FLAG_COMMENT) ==
+ (SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI))
+ return bgpsec->asn == filter->asn &&
+ memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN) == 0;
+
/* Both have ASN */
if ((bgpsec->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
(filter->data_flag & SLURM_COM_FLAG_ASN) > 0)
/* Both have a SKI */
if ((bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) > 0 &&
(filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
- return memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN) == 0;
+ return memcmp(bgpsec->ski, filter->ski, RK_SPKI_LEN) == 0;
return false;
}
static bool
-bgpsec_equal(struct slurm_bgpsec *left, struct slurm_bgpsec *right,
- bool filter)
+bgpsec_contained(struct slurm_bgpsec_ctx *left_ctx, struct slurm_bgpsec *right,
+ int ctx)
+{
+ struct slurm_bgpsec *left;
+
+ /*
+ * rfc8416#section-4.2:
+ * 2. There may be conflicting changes to BGPsec Assertions if an ASN X
+ * and distinct SLURM files Y and Z exist such that X is used in any
+ * "bgpsecAssertions" or "bgpsecFilters" in file Y and X is used in
+ * any "bgpsecAssertions" or "bgpsecFilters" in file Z.
+ *
+ * A negative @ctx or an equal context will avoid this check.
+ */
+ if (ctx < 0 || ctx == left_ctx->ctx)
+ return false;
+
+ left = &left_ctx->element;
+
+ return (left->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
+ (right->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
+ left->asn == right->asn;
+}
+
+static bool
+bgpsec_equal(struct slurm_bgpsec_ctx *left_ctx, struct slurm_bgpsec *right,
+ int ctx, bool filter, bool exact_filter)
{
+ struct slurm_bgpsec *left;
bool equal;
+ left = &left_ctx->element;
+
+ if (bgpsec_contained(left_ctx, right, ctx))
+ return true;
+
/* Ignore the comments */
if ((left->data_flag & ~SLURM_COM_FLAG_COMMENT) !=
(right->data_flag & ~SLURM_COM_FLAG_COMMENT))
- return filter && bgpsec_filtered_by(left, right);
+ return filter && bgpsec_filtered_by(left, right, exact_filter);
/* It has the same data, compare it */
equal = true;
- if ((left->data_flag & SLURM_COM_FLAG_ASN) > 0)
- equal = equal && left->asn == right->asn;
+ if (equal && (left->data_flag & SLURM_COM_FLAG_ASN) > 0)
+ equal = left->asn == right->asn;
if (equal && (left->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
- equal = equal &&
- memcmp(left->ski, right->ski, RK_SKI_LEN) == 0;
+ equal = memcmp(left->ski, right->ski, RK_SKI_LEN) == 0;
if (equal && (left->data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0)
- equal = equal &&
- memcmp(left->router_public_key, right->router_public_key,
- RK_SPKI_LEN) == 0;
+ equal = memcmp(left->router_public_key,
+ right->router_public_key, RK_SPKI_LEN) == 0;
return equal;
}
-#define ADD_FUNCS(name, type, list_name, db_list, equal_cb, filter) \
+#define ADD_FUNCS(name, type, list_name, db_list, db_alt_list, equal_cb,\
+ cont_cb, filter) \
static type * \
- name##_locate(type *obj) \
+ name##_locate(type *obj, bool flt, int ctx) \
{ \
- type *cursor; \
+ type##_ctx *cursor; \
array_index i; \
\
ARRAYLIST_FOREACH(db_list, cursor, i) \
- if (equal_cb(cursor, obj, filter)) \
- return cursor; \
+ if (equal_cb(cursor, obj, ctx, filter, flt)) \
+ return &cursor->element; \
+ \
+ if (ctx < 0) \
+ return NULL; /* Avoid the next loop */ \
+ \
+ ARRAYLIST_FOREACH(db_alt_list, cursor, i) \
+ if (cont_cb(cursor, obj, ctx)) \
+ return &cursor->element; \
\
return NULL; \
} \
\
static bool \
- name##_exists(type *obj) \
+ name##_exists(type *obj, bool flt, int ctx) \
{ \
- return name##_locate(obj) != NULL; \
+ return name##_locate(obj, flt, ctx) != NULL; \
} \
\
int \
- slurm_db_add_##name(type *elem) { \
- if (name##_exists(elem)) \
+ slurm_db_add_##name(type *elem, int ctx) \
+ { \
+ type##_ctx new_elem; \
+ if (name##_exists(elem, !filter, ctx)) \
return -EEXIST; \
- return list_name##_add(db_list, elem); \
+ new_elem.element = *elem; \
+ new_elem.ctx = ctx; \
+ return list_name##_add(db_list, &new_elem); \
}
ADD_FUNCS(prefix_filter, struct slurm_prefix, al_filter_prefix,
- &array_lists_db.filter_pfx_al, prefix_equal, true)
+ &array_lists_db.filter_pfx_al, &array_lists_db.assertion_pfx_al,
+ prefix_equal, prefix_contained, true)
ADD_FUNCS(bgpsec_filter, struct slurm_bgpsec, al_filter_bgpsec,
- &array_lists_db.filter_bgps_al, bgpsec_equal, true)
+ &array_lists_db.filter_bgps_al, &array_lists_db.assertion_bgps_al,
+ bgpsec_equal, bgpsec_contained, true)
ADD_FUNCS(prefix_assertion, struct slurm_prefix, al_assertion_prefix,
- &array_lists_db.assertion_pfx_al, prefix_equal, false)
+ &array_lists_db.assertion_pfx_al, &array_lists_db.filter_pfx_al,
+ prefix_equal, prefix_contained, false)
ADD_FUNCS(bgpsec_assertion, struct slurm_bgpsec, al_assertion_bgpsec,
- &array_lists_db.assertion_bgps_al, bgpsec_equal, false)
+ &array_lists_db.assertion_bgps_al, &array_lists_db.filter_bgps_al,
+ bgpsec_equal, bgpsec_contained, false)
bool
slurm_db_vrp_is_filtered(struct vrp const *vrp)
slurm_prefix.vrp = *vrp;
slurm_prefix.comment = NULL;
- return prefix_filter_exists(&slurm_prefix);
+ return prefix_filter_exists(&slurm_prefix, true, -1);
}
int
slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb cb, void *arg)
{
- struct slurm_prefix *cursor;
+ struct slurm_prefix_ctx *cursor;
array_index i;
int error;
ARRAYLIST_FOREACH(&array_lists_db.assertion_pfx_al, cursor, i) {
- error = cb(cursor, arg);
+ error = cb(&cursor->element, arg);
if (error)
return error;
}
slurm_bgpsec.router_public_key = NULL;
slurm_bgpsec.comment = NULL;
- result = bgpsec_filter_exists(&slurm_bgpsec);
+ result = bgpsec_filter_exists(&slurm_bgpsec, true, -1);
free(tmp);
return result;
}
int
slurm_db_foreach_assertion_bgpsec(assertion_bgpsec_foreach_cb cb, void *arg)
{
- struct slurm_bgpsec *cursor;
+ struct slurm_bgpsec_ctx *cursor;
array_index i;
int error;
ARRAYLIST_FOREACH(&array_lists_db.assertion_bgps_al, cursor, i) {
- error = cb(cursor, arg);
+ error = cb(&cursor->element, arg);
if (error)
return error;
}
}
static void
-clean_slurm_prefix(struct slurm_prefix *prefix)
+clean_slurm_prefix(struct slurm_prefix_ctx *prefix)
{
- if ((prefix->data_flag & SLURM_COM_FLAG_COMMENT) > 0)
- free(prefix->comment);
+ if ((prefix->element.data_flag & SLURM_COM_FLAG_COMMENT) > 0)
+ free(prefix->element.comment);
}
static void
-clean_slurm_bgpsec(struct slurm_bgpsec *bgpsec)
+clean_slurm_bgpsec(struct slurm_bgpsec_ctx *bgpsec)
{
- if ((bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
- free(bgpsec->ski);
- if ((bgpsec->data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0)
- free(bgpsec->router_public_key);
- if ((bgpsec->data_flag & SLURM_COM_FLAG_COMMENT) > 0)
- free(bgpsec->comment);
+ if ((bgpsec->element.data_flag & SLURM_BGPS_FLAG_SKI) > 0)
+ free(bgpsec->element.ski);
+ if ((bgpsec->element.data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0)
+ free(bgpsec->element.router_public_key);
+ if ((bgpsec->element.data_flag & SLURM_COM_FLAG_COMMENT) > 0)
+ free(bgpsec->element.comment);
}
void
#include <stdbool.h>
#include "slurm/slurm_parser.h"
-
-struct slurm_prefix_list {
- struct slurm_prefix *list;
- unsigned int len;
-};
-
-struct slurm_bgpsec_list {
- struct slurm_bgpsec *list;
- unsigned int len;
-};
-
-struct slurm_db {
- struct slurm_prefix_list prefix_filters;
- struct slurm_bgpsec_list bgpsec_filters;
- struct slurm_prefix_list prefix_assertions;
- struct slurm_bgpsec_list bgpsec_assertions;
-};
+#include "rtr/db/vrp.h"
typedef int (*assertion_pfx_foreach_cb)(struct slurm_prefix *, void *);
typedef int (*assertion_bgpsec_foreach_cb)(struct slurm_bgpsec *, void *);
void slurm_db_init(void);
-int slurm_db_add_prefix_filter(struct slurm_prefix *);
-int slurm_db_add_prefix_assertion(struct slurm_prefix *);
-int slurm_db_add_bgpsec_filter(struct slurm_bgpsec *);
-int slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *);
+int slurm_db_add_prefix_filter(struct slurm_prefix *, int);
+int slurm_db_add_prefix_assertion(struct slurm_prefix *, int);
+int slurm_db_add_bgpsec_filter(struct slurm_bgpsec *, int);
+int slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *, int);
bool slurm_db_vrp_is_filtered(struct vrp const *);
int slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb, void *);
static int
slurm_load(bool *loaded)
{
+ int ctx = 0; /* Context (file number) */
/* Optional configuration */
*loaded = false;
if (config_get_slurm() == NULL)
*loaded = true;
slurm_db_init();
- return process_file_or_dir(config_get_slurm(),
- SLURM_FILE_EXTENSION, slurm_parse, NULL);
+ return process_file_or_dir(config_get_slurm(), SLURM_FILE_EXTENSION,
+ slurm_parse, &ctx);
}
static void
if (element == NULL) \
return pr_err("SLURM member '%s' is required", name);
-static int handle_json(json_t *);
+/* Context value, local to avoid forwarding the parameter */
+int cur_ctx;
+
+static int handle_json(json_t *, int *);
int
slurm_parse(char const *location, void *arg)
return -ENOENT;
}
- error = handle_json(json_root);
+ error = handle_json(json_root, arg);
json_decref(json_root);
return error;
goto release_comment;
}
- error = slurm_db_add_prefix_filter(&result);
+ error = slurm_db_add_prefix_filter(&result, cur_ctx);
if (error)
goto release_comment;
goto release_comment;
}
- error = slurm_db_add_prefix_assertion(&result);
+ error = slurm_db_add_prefix_assertion(&result, cur_ctx);
if (error)
goto release_comment;
json_array_foreach(array, index, element) {
error = load_single_prefix(element, is_assertion);
- if (error) {
- if (error == -EEXIST)
- pr_err(
- "The prefix %s element #%d, is duplicated or covered by another %s; SLURM loading will be stopped",
- (is_assertion ? "assertion" : "filter"),
- index + 1,
- (is_assertion ? "assertion" : "filter"));
- else
- pr_err(
- "Error at prefix %s, element #%d, SLURM loading will be stopped",
- (is_assertion ? "assertions" : "filters"),
- index + 1);
+ if (!error)
+ continue;
+ if (error == -EEXIST)
+ pr_err(
+ "The prefix %s element \"%s\", is duplicated or covered by another %s; SLURM loading will be stopped.%s",
+ (is_assertion ? "assertion" : "filter"),
+ json_dumps(element, 0),
+ (is_assertion ? "assertion" : "filter"),
+ (cur_ctx > 0
+ ? " TIP: More than 1 SLURM files were found, check if the prefix is contained in multiple files (see RFC 8416 section 4.2)."
+ : ""));
+ else
+ pr_err(
+ "Error at prefix %s, element \"%s\", SLURM loading will be stopped",
+ (is_assertion ? "assertions" : "filters"),
+ json_dumps(element, 0));
- return error;
- }
+ return error;
}
return 0;
goto release_comment;
}
- error = slurm_db_add_bgpsec_filter(&result);
+ error = slurm_db_add_bgpsec_filter(&result, cur_ctx);
if (error)
goto release_comment;
goto release_comment;
}
- error = slurm_db_add_bgpsec_assertion(&result);
+ error = slurm_db_add_bgpsec_assertion(&result, cur_ctx);
if (error)
goto release_comment;
continue;
if (error == -EEXIST)
pr_err(
- "The bgpsec %s element #%d, is duplicated or covered by another %s; SLURM loading will be stopped",
+ "The bgpsec %s element \"%s\", is duplicated or covered by another %s; SLURM loading will be stopped.%s",
+ (is_assertion ? "assertion" : "filter"),
+ json_dumps(element, 0),
(is_assertion ? "assertion" : "filter"),
- index + 1,
- (is_assertion ? "assertion" : "filter"));
+ (cur_ctx > 0
+ ? " TIP: More than 1 SLURM files were found, check if the ASN is contained in multiple files (see RFC 8416 section 4.2)."
+ : ""));
else
pr_err(
- "Error at bgpsec %s, element #%d, SLURM loading will be stopped",
+ "Error at bgpsec %s, element \"%s\", SLURM loading will be stopped",
(is_assertion ? "assertions" : "filters"),
- index + 1);
+ json_dumps(element, 0));
return error;
}
}
static int
-handle_json(json_t *root)
+handle_json(json_t *root, int *ctx)
{
size_t expected_members;
int error;
if (!json_is_object(root))
return pr_err("The root of the SLURM is not a JSON object.");
+ cur_ctx = *ctx;
+
error = load_version(root);
if (error)
return error;
"SLURM root must have only %lu members (RFC 8416 section 3.2)",
expected_members);
+ (*ctx)++; /* Next time will be another context */
+
return 0;
}
struct validation {
struct tal *tal;
- /** https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_load_locations.html */
- X509_STORE *store;
+ struct x509_data {
+ /** https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_load_locations.html */
+ X509_STORE *store;
+ X509_VERIFY_PARAM *params;
+ } x509_data;
struct cert_stack *certstack;
struct validation_handler *validation_handler)
{
struct validation *result;
+ X509_VERIFY_PARAM *params;
int error;
result = malloc(sizeof(struct validation));
result->tal = tal;
- result->store = X509_STORE_new();
- if (!result->store) {
+ result->x509_data.store = X509_STORE_new();
+ if (!result->x509_data.store) {
error = crypto_err("X509_STORE_new() returned NULL");
goto abort1;
}
- X509_STORE_set_verify_cb(result->store, cb);
+ params = X509_VERIFY_PARAM_new();
+ if (params == NULL) {
+ error = pr_enomem();
+ goto abort2;
+ }
+
+ X509_VERIFY_PARAM_set_flags(params, X509_V_FLAG_CRL_CHECK);
+ X509_STORE_set1_param(result->x509_data.store, params);
+ X509_STORE_set_verify_cb(result->x509_data.store, cb);
error = certstack_create(&result->certstack);
if (error)
- goto abort2;
+ goto abort3;
result->pubkey_state = PKS_UNTESTED;
result->validation_handler = *validation_handler;
+ result->x509_data.params = params; /* Ownership transfered */
*out = result;
return 0;
-
+abort3:
+ X509_VERIFY_PARAM_free(params);
abort2:
- X509_STORE_free(result->store);
+ X509_STORE_free(result->x509_data.store);
abort1:
free(result);
return error;
void
validation_destroy(struct validation *state)
{
- X509_STORE_free(state->store);
+ X509_VERIFY_PARAM_free(state->x509_data.params);
+ X509_STORE_free(state->x509_data.store);
certstack_destroy(state->certstack);
free(state);
}
X509_STORE *
validation_store(struct validation *state)
{
- return state->store;
+ return state->x509_data.store;
}
struct cert_stack *
do {
error = vrps_update(&changed);
+ if (error == -EINTR)
+ break; /* Process interrupted, terminate thread */
+
if (error) {
pr_err("Error code %d while trying to update the ROA database. Sleeping...",
error);
rtr_primitive_reader_test_LDADD = ${MY_LDADD}
EXTRA_DIST = impersonator.c
-EXTRA_DIST += rtr/db/rtr_db_impersonator.c
EXTRA_DIST += line_file/core.txt
EXTRA_DIST += line_file/empty.txt
EXTRA_DIST += line_file/error.txt
+EXTRA_DIST += rtr/stream.c rtr/stream.h
+EXTRA_DIST += rtr/db/rtr_db_impersonator.c
+EXTRA_DIST += tal/lacnic.tal
endif