]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Implement ASPA aspa
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 23 Jan 2026 21:49:18 +0000 (15:49 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 23 Jan 2026 21:49:18 +0000 (15:49 -0600)
50 files changed:
src/Makefile.am
src/asn1/asn1c/ASProviderAttestation.c [new file with mode: 0644]
src/asn1/asn1c/ASProviderAttestation.h [new file with mode: 0644]
src/asn1/asn1c/Makefile.include
src/asn1/asn1c/ProviderASSet.c [new file with mode: 0644]
src/asn1/asn1c/ProviderASSet.h [new file with mode: 0644]
src/asn1/oid.h
src/asn1/signed_data.c
src/asn1/signed_data.h
src/cert_stack.c
src/config.c
src/config.h
src/object/aspa.c [new file with mode: 0644]
src/object/aspa.h [new file with mode: 0644]
src/object/bgpsec.c
src/object/certificate.c
src/object/certificate.h
src/object/ghostbusters.c
src/object/manifest.c
src/object/roa.c
src/object/tal.c
src/resource.c
src/resource.h
src/resource/asn.c
src/resource/asn.h
src/rpp.c
src/rpp.h
src/rrdp.c
src/rtr/db/db_table.c
src/rtr/db/db_table.h
src/rtr/db/delta.c
src/rtr/db/delta.h
src/rtr/db/vrps.c
src/rtr/db/vrps.h
src/rtr/pdu.c
src/rtr/pdu.h
src/rtr/pdu_handler.c
src/rtr/pdu_sender.c
src/rtr/pdu_sender.h
src/sorted_array.c
src/sorted_array.h
src/types/aspa.c [new file with mode: 0644]
src/types/aspa.h [new file with mode: 0644]
src/types/delta.c
src/types/delta.h
src/validation_handler.c
src/validation_handler.h
test/rtr/db/db_table_test.c
test/rtr/db/vrps_test.c
test/rtr/pdu_handler_test.c

index 215e29ca90e0bd0cb5eda78889324e92d336284b..54c08952f3a73ea53d27b3f43407624718ffbbf9 100644 (file)
@@ -42,6 +42,7 @@ fort_SOURCES += asn1/oid.h asn1/oid.c
 fort_SOURCES += asn1/signed_data.h asn1/signed_data.c
 
 fort_SOURCES += types/address.h types/address.c
+fort_SOURCES += types/aspa.h types/aspa.c
 fort_SOURCES += types/bio_seq.c types/bio_seq.h
 fort_SOURCES += types/delta.c types/delta.h
 fort_SOURCES += types/router_key.c types/router_key.h
@@ -77,6 +78,7 @@ fort_SOURCES += http/http.h http/http.c
 
 fort_SOURCES += incidence/incidence.h incidence/incidence.c
 
+fort_SOURCES += object/aspa.h object/aspa.c
 fort_SOURCES += object/bgpsec.h object/bgpsec.c
 fort_SOURCES += object/certificate.h object/certificate.c
 fort_SOURCES += object/crl.h object/crl.c
diff --git a/src/asn1/asn1c/ASProviderAttestation.c b/src/asn1/asn1c/ASProviderAttestation.c
new file mode 100644 (file)
index 0000000..ce435fd
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ *     found in "aspa.asn1"
+ *     `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#include "asn1/asn1c/ASProviderAttestation.h"
+
+static int asn_DFL_2_cmp_0(const void *sptr) {
+       const INTEGER_t *st = sptr;
+       
+       if(!st) {
+               return -1; /* No value is not a default value */
+       }
+       
+       /* Test default value 0 */
+       long value;
+       if(asn_INTEGER2long(st, &value))
+               return -1;
+       return (value != 0);
+}
+static int asn_DFL_2_set_0(void **sptr) {
+       INTEGER_t *st = *sptr;
+       
+       if(!st) {
+               st = (*sptr = CALLOC(1, sizeof(*st)));
+               if(!st) return -1;
+       }
+       
+       /* Install default value 0 */
+       return asn_long2INTEGER(st, 0);
+}
+static asn_TYPE_member_t asn_MBR_ASProviderAttestation_1[] = {
+       { ATF_POINTER, 1, offsetof(struct ASProviderAttestation, version),
+               (ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+               +1,     /* EXPLICIT tag at current level */
+               &asn_DEF_INTEGER,
+               0,
+               { 0, 0, 0 },
+               &asn_DFL_2_cmp_0,       /* Compare DEFAULT 0 */
+               &asn_DFL_2_set_0,       /* Set DEFAULT 0 */
+               "version"
+               },
+       { ATF_NOFLAGS, 0, offsetof(struct ASProviderAttestation, customerASID),
+               (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)),
+               0,
+               &asn_DEF_ASId,
+               0,
+               { 0, 0, 0 },
+               0, 0, /* No default value */
+               "customerASID"
+               },
+       { ATF_NOFLAGS, 0, offsetof(struct ASProviderAttestation, providers),
+               (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)),
+               0,
+               &asn_DEF_ProviderASSet,
+               0,
+               { 0, 0, 0 },
+               0, 0, /* No default value */
+               "providers"
+               },
+};
+static const ber_tlv_tag_t asn_DEF_ASProviderAttestation_tags_1[] = {
+       (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_ASProviderAttestation_tag2el_1[] = {
+    { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 1, 0, 0 }, /* customerASID */
+    { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 2, 0, 0 }, /* providers */
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* version */
+};
+static asn_SEQUENCE_specifics_t asn_SPC_ASProviderAttestation_specs_1 = {
+       sizeof(struct ASProviderAttestation),
+       offsetof(struct ASProviderAttestation, _asn_ctx),
+       asn_MAP_ASProviderAttestation_tag2el_1,
+       3,      /* Count of tags in the map */
+       -1,     /* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_ASProviderAttestation = {
+       "ASProviderAttestation",
+       "ASProviderAttestation",
+       &asn_OP_SEQUENCE,
+       asn_DEF_ASProviderAttestation_tags_1,
+       sizeof(asn_DEF_ASProviderAttestation_tags_1)
+               /sizeof(asn_DEF_ASProviderAttestation_tags_1[0]), /* 1 */
+       asn_DEF_ASProviderAttestation_tags_1,   /* Same as above */
+       sizeof(asn_DEF_ASProviderAttestation_tags_1)
+               /sizeof(asn_DEF_ASProviderAttestation_tags_1[0]), /* 1 */
+       { 0, 0, SEQUENCE_constraint },
+       asn_MBR_ASProviderAttestation_1,
+       3,      /* Elements count */
+       &asn_SPC_ASProviderAttestation_specs_1  /* Additional specs */
+};
+
diff --git a/src/asn1/asn1c/ASProviderAttestation.h b/src/asn1/asn1c/ASProviderAttestation.h
new file mode 100644 (file)
index 0000000..2bcae02
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ *     found in "aspa.asn1"
+ *     `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#ifndef        _ASProviderAttestation_H_
+#define        _ASProviderAttestation_H_
+
+/* Including external dependencies */
+#include "asn1/asn1c/INTEGER.h"
+#include "asn1/asn1c/ASId.h"
+#include "asn1/asn1c/ProviderASSet.h"
+#include "asn1/asn1c/constr_SEQUENCE.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ASProviderAttestation */
+typedef struct ASProviderAttestation {
+       INTEGER_t       *version        /* DEFAULT 0 */;
+       ASId_t   customerASID;
+       ProviderASSet_t  providers;
+       
+       /* Context for parsing across buffer boundaries */
+       asn_struct_ctx_t _asn_ctx;
+} ASProviderAttestation_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_ASProviderAttestation;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ASProviderAttestation_H_ */
+#include "asn1/asn1c/asn_internal.h"
index 9b602c27c92b5f380d880d522027d603198faa07..e15cc619185173e557ece6076b452c264069d0a0 100644 (file)
@@ -8,6 +8,8 @@ ASN_MODULE_SRCS=        \
        asn1/asn1c/ASIdentifiers.c      \
        asn1/asn1c/ASIdentifierChoice.c \
        asn1/asn1c/ASIdOrRange.c        \
+       asn1/asn1c/ASProviderAttestation.c      \
+       asn1/asn1c/ProviderASSet.c      \
        asn1/asn1c/ASRange.c    \
        asn1/asn1c/ASId.c       \
        asn1/asn1c/AttributeType.c      \
@@ -73,6 +75,8 @@ ASN_MODULE_HDRS=      \
        asn1/asn1c/ASIdentifiers.h      \
        asn1/asn1c/ASIdentifierChoice.h \
        asn1/asn1c/ASIdOrRange.h        \
+       asn1/asn1c/ASProviderAttestation.h      \
+       asn1/asn1c/ProviderASSet.h      \
        asn1/asn1c/ASRange.h    \
        asn1/asn1c/ASId.h       \
        asn1/asn1c/AttributeType.h      \
diff --git a/src/asn1/asn1c/ProviderASSet.c b/src/asn1/asn1c/ProviderASSet.c
new file mode 100644 (file)
index 0000000..5074d24
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ *     found in "aspa.asn1"
+ *     `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#include "asn1/asn1c/ProviderASSet.h"
+
+asn_TYPE_member_t asn_MBR_ProviderASSet_1[] = {
+       { ATF_POINTER, 0, 0,
+               (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)),
+               0,
+               &asn_DEF_ASId,
+               0,
+               { 0, 0, 0 },
+               0, 0, /* No default value */
+               ""
+               },
+};
+static const ber_tlv_tag_t asn_DEF_ProviderASSet_tags_1[] = {
+       (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+asn_SET_OF_specifics_t asn_SPC_ProviderASSet_specs_1 = {
+       sizeof(struct ProviderASSet),
+       offsetof(struct ProviderASSet, _asn_ctx),
+       0,      /* XER encoding is XMLDelimitedItemList */
+};
+asn_TYPE_descriptor_t asn_DEF_ProviderASSet = {
+       "ProviderASSet",
+       "ProviderASSet",
+       &asn_OP_SEQUENCE_OF,
+       asn_DEF_ProviderASSet_tags_1,
+       sizeof(asn_DEF_ProviderASSet_tags_1)
+               /sizeof(asn_DEF_ProviderASSet_tags_1[0]), /* 1 */
+       asn_DEF_ProviderASSet_tags_1,   /* Same as above */
+       sizeof(asn_DEF_ProviderASSet_tags_1)
+               /sizeof(asn_DEF_ProviderASSet_tags_1[0]), /* 1 */
+       { NULL, NULL, SEQUENCE_OF_constraint },
+       asn_MBR_ProviderASSet_1,
+       1,      /* Single element */
+       &asn_SPC_ProviderASSet_specs_1  /* Additional specs */
+};
+
diff --git a/src/asn1/asn1c/ProviderASSet.h b/src/asn1/asn1c/ProviderASSet.h
new file mode 100644 (file)
index 0000000..8521933
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ *     found in "aspa.asn1"
+ *     `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#ifndef        _ProviderASSet_H_
+#define        _ProviderASSet_H_
+
+/* Including external dependencies */
+#include "asn1/asn1c/ASId.h"
+#include "asn1/asn1c/asn_SEQUENCE_OF.h"
+#include "asn1/asn1c/constr_SEQUENCE_OF.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ProviderASSet */
+typedef struct ProviderASSet {
+       A_SEQUENCE_OF(ASId_t) list;
+       
+       /* Context for parsing across buffer boundaries */
+       asn_struct_ctx_t _asn_ctx;
+} ProviderASSet_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_ProviderASSet;
+extern asn_SET_OF_specifics_t asn_SPC_ProviderASSet_specs_1;
+extern asn_TYPE_member_t asn_MBR_ProviderASSet_1[1];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ProviderASSet_H_ */
+#include "asn1/asn1c/asn_internal.h"
index 464205121628c04548faa34689435f619e1fccdc..b57e60faf290e34682e3de541e12d4530db6489e 100644 (file)
@@ -35,6 +35,7 @@ typedef asn_oid_arc_t OID[];
 #define OID_ROA                      { 1, 2, 840, 113549, 1, 9, 16, 1, 24 }
 #define OID_MANIFEST                 { 1, 2, 840, 113549, 1, 9, 16, 1, 26 }
 #define OID_GHOSTBUSTERS             { 1, 2, 840, 113549, 1, 9, 16, 1, 35 }
+#define OID_ASPA                     { 1, 2, 840, 113549, 1, 9, 16, 1, 49 }
 
 int oid2arcs(OBJECT_IDENTIFIER_t *, struct oid_arcs *);
 
index 40f7e6f401f3a261f4a2c85a6d9a6428e1cf8e77..1b59ce4dc86f42172cf8b1112d8dfdca7d7b9e44 100644 (file)
@@ -16,8 +16,10 @@ static const OID oid_mda = OID_MESSAGE_DIGEST_ATTR;
 static const OID oid_sta = OID_SIGNING_TIME_ATTR;
 
 void
-eecert_init(struct ee_cert *ee, STACK_OF(X509_CRL) *crls, bool force_inherit)
+eecert_init(struct ee_cert *ee, enum ee_type type, STACK_OF(X509_CRL) *crls,
+    bool force_inherit)
 {
+       ee->type = type;
        ee->res = resources_create(RPKI_POLICY_RFC6484, force_inherit);
        ee->crls = crls;
        memset(&ee->refs, 0, sizeof(ee->refs));
@@ -101,7 +103,7 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct ee_cert *ee,
                goto end2;
 
        resources_set_policy(ee->res, policy);
-       error = certificate_get_resources(cert, ee->res, CERTYPE_EE);
+       error = certificate_get_resources(cert, ee->res, CERTYPE_EE, ee->type);
        if (error)
                goto end2;
 
index 81b5f10553fb95398d8973e876e688bd872d922f..889b7fe0dcb01a0bb72da18fc94f6e67bdd9898b 100644 (file)
@@ -7,7 +7,16 @@
 #include "certificate_refs.h"
 #include "resource.h"
 
+enum ee_type {
+       EET_ROA = 1,
+       EET_ASPA,
+       EET_MFT,
+       EET_GBR,
+};
+
 struct ee_cert {
+       enum ee_type type;
+
        /** CRL that might or might not revoke the EE certificate. */
        STACK_OF(X509_CRL) *crls;
        /** A copy of the resources carried by the EE certificate. */
@@ -19,7 +28,7 @@ struct ee_cert {
        struct certificate_refs refs;
 };
 
-void eecert_init(struct ee_cert *, STACK_OF(X509_CRL) *, bool);
+void eecert_init(struct ee_cert *, enum ee_type, STACK_OF(X509_CRL) *, bool);
 void eecert_cleanup(struct ee_cert *);
 
 int signed_data_decode(ANY_t *, struct SignedData **);
index 8f21a0700b9033a3f38b88ad90879448fc3e055a..936270ccf49476d903cb85f86759dbf194eaf549 100644 (file)
@@ -248,7 +248,7 @@ init_resources(X509 *x509, enum rpki_policy policy, enum cert_type type,
 
        result = resources_create(policy, false);
 
-       error = certificate_get_resources(x509, result, type);
+       error = certificate_get_resources(x509, result, type, 0);
        if (error)
                goto fail;
 
index 25a5c7676a517e9e3aee0a6d87f2f793313a4991..06aaaf6e65855e43db129b01bc9526b9234096b6 100644 (file)
@@ -168,6 +168,10 @@ struct rpki_config {
                uint32_t facility;
        } validation_log;
 
+       struct {
+               unsigned int max_providers; /* per customer */
+       } aspa;
+
        struct {
                /** File where the validated ROAs will be stored */
                char *roa;
@@ -715,6 +719,17 @@ static const struct option_field options[] = {
                .doc = "Print ANSI color codes",
        },
 
+       /* ASPA */
+       {
+               .id = 15000,
+               .name = "aspa.max-providers",
+               .type = &gt_uint,
+               .offset = offsetof(struct rpki_config, aspa.max_providers),
+               .doc = "Maximum allowed providers per customer",
+               .min = 0,
+               .max = 16380u,
+       },
+
        /* Incidences */
        {
                .id = 7001,
@@ -948,9 +963,9 @@ set_default_values(void)
 
                "--contimeout=20", "--max-size=20MB", "--timeout=15",
 
-               "--include=*/", "--include=*.cer", "--include=*.crl",
-               "--include=*.gbr", "--include=*.mft", "--include=*.roa",
-               "--exclude=*",
+               "--include=*/", "--include=*.cer", "--include=*.roa",
+               "--include=*.asa", "--include=*.mft", "--include=*.crl",
+               "--include=*.gbr", "--exclude=*",
 
                "$REMOTE", "$LOCAL",
        };
@@ -1570,3 +1585,9 @@ free_rpki_config(void)
                        option->type->free(get_rpki_config_field(option));
        free(rpki_config.payload);
 }
+
+unsigned int
+config_get_max_aspa_providers(void)
+{
+       return rpki_config.aspa.max_providers;
+}
index ee21f0d51d9fd90c278df62f858d04830b087850..9110b1d66811ae565bd724e89374ca76b404c3e7 100644 (file)
@@ -61,6 +61,7 @@ unsigned int config_get_asn1_decode_max_stack(void);
 unsigned int config_get_thread_pool_server_max(void);
 enum file_type config_get_file_type(void);
 char const *config_get_payload(void);
+unsigned int config_get_max_aspa_providers(void);
 
 /* Logging getters */
 bool config_get_op_log_enabled(void);
diff --git a/src/object/aspa.c b/src/object/aspa.c
new file mode 100644 (file)
index 0000000..104889d
--- /dev/null
@@ -0,0 +1,192 @@
+#include "object/aspa.h"
+
+#include "asn1/asn1c/ASProviderAttestation.h"
+#include "asn1/decode.h"
+#include "asn1/oid.h"
+#include "asn1/signed_data.h"
+#include "config.h"
+#include "log.h"
+#include "object/signed_object.h"
+#include "thread_var.h"
+
+#define ASID_MAX UINT32_MAX
+
+static int
+decode_aspa(struct signed_object *sobj, struct ASProviderAttestation **result)
+{
+       return asn1_decode_octet_string(
+               sobj->sdata->encapContentInfo.eContent,
+               &asn_DEF_ASProviderAttestation,
+               (void **) result,
+               true
+       );
+}
+
+static int
+validate_version(INTEGER_t *version)
+{
+       long primitive;
+
+       if (version == NULL)
+               return pr_val_err("Version number is NULL.");
+       if (asn_INTEGER2long(version, &primitive) < 0)
+               return pr_val_err("Version number %s", strerror(errno));
+       if (primitive != 1)
+               return pr_val_err("Version number is not 1: %ld", primitive);
+
+       return 0;
+}
+
+static int
+parse_asid(char const *what, ASId_t *asid, uint32_t *result)
+{
+       unsigned long primitive;
+
+       if (asid == NULL)
+               return pr_val_err("%s is NULL.", what);
+       if (asn_INTEGER2ulong(asid, &primitive) < 0)
+               return pr_val_err("%s %s", what, strerror(errno));
+       if (primitive > ASID_MAX)
+               return pr_val_err("%s out of range. (0-%u)", what, ASID_MAX);
+
+       *result = primitive;
+       return 0;
+}
+
+static int
+parse_customer(ASId_t *asid, struct resources *parent, uint32_t *result)
+{
+       int error;
+
+       error = parse_asid("customerASID", asid, result);
+       if (error)
+               return error;
+
+       if (!resources_matches_asn(parent, *result))
+               return pr_val_err(
+                   "EE certificate's ASN extension does not exactly match customerASID %u.",
+                   *result);
+
+       return 0;
+}
+
+static int
+parse_providers(ProviderASSet_t *set, struct aspa *aspa)
+{
+       uint32_t *providers;
+       unsigned int limit;
+       int i;
+       int error;
+
+       aspa->providers.asids = NULL;
+       aspa->providers.count = 0;
+
+       if (set == NULL)
+               return pr_val_err("Providers set is NULL.");
+
+       limit = config_get_max_aspa_providers();
+       if (set->list.count > limit)
+               return pr_val_err("Too many providers: %d > %u",
+                   set->list.count, limit);
+
+       providers = pcalloc(set->list.count, sizeof(uint32_t));
+       for (i = 0; i < set->list.count; i++) {
+               error = parse_asid("Provider", set->list.array[i], &providers[i]);
+               if (error)
+                       goto cancel;
+
+               if (providers[i] == aspa->customer) {
+                       error = pr_val_err("The Providers list contains the customer's ASID (%u).",
+                           aspa->customer);
+                       goto cancel;
+               }
+               if (i != 0 && providers[i - 1] >= providers[i]) {
+                       error = pr_val_err("The Provider ASIDs are not listed in ascending order.");
+                       goto cancel;
+               }
+       }
+
+       aspa->providers.asids = providers;
+       aspa->providers.count = set->list.count;
+       return 0;
+
+cancel:        free(providers);
+       return error;
+}
+
+static int
+__handle_aspa(struct ASProviderAttestation *asn1, struct resources *parent)
+{
+       struct aspa *aspa;
+       int error;
+
+       error = validate_version(asn1->version);
+       if (error)
+               return error;
+
+       aspa = pzalloc(sizeof(struct aspa));
+       aspa->refs = 1;
+
+       error = parse_customer(&asn1->customerASID, parent, &aspa->customer);
+       if (error)
+               goto end;
+
+       error = parse_providers(&asn1->providers, aspa);
+       if (error)
+               goto end;
+
+       error = vhandler_handle_aspa(aspa);
+
+end:   aspa_refput(aspa);
+       return error;
+}
+
+int
+aspa_traverse(struct rpki_uri *uri, struct rpp *pp)
+{
+       static OID oid = OID_ASPA;
+       struct oid_arcs arcs = OID2ARCS("aspa", oid);
+       struct signed_object sobj;
+       struct ee_cert ee;
+       struct ASProviderAttestation *aspa;
+       STACK_OF(X509_CRL) *crl;
+       int error;
+
+       /* Prepare */
+       pr_val_debug("ASPA '%s' {", uri_val_get_printable(uri));
+       fnstack_push_uri(uri);
+
+       /* Decode */
+       error = signed_object_decode(&sobj, uri);
+       if (error)
+               goto revert_log;
+       error = decode_aspa(&sobj, &aspa);
+       if (error)
+               goto revert_sobj;
+
+       /* Prepare validation arguments */
+       error = rpp_crl(pp, &crl);
+       if (error)
+               goto revert_roa;
+       eecert_init(&ee, EET_ASPA, crl, false);
+
+       /* Validate and handle everything */
+       error = signed_object_validate(&sobj, &arcs, &ee);
+       if (error)
+               goto revert_args;
+       error = __handle_aspa(aspa, ee.res);
+       if (error)
+               goto revert_args;
+       error = refs_validate_ee(&ee.refs, pp, uri);
+
+revert_args:
+       eecert_cleanup(&ee);
+revert_roa:
+       ASN_STRUCT_FREE(asn_DEF_ASProviderAttestation, aspa);
+revert_sobj:
+       signed_object_cleanup(&sobj);
+revert_log:
+       fnstack_pop();
+       pr_val_debug("}");
+       return error;
+}
diff --git a/src/object/aspa.h b/src/object/aspa.h
new file mode 100644 (file)
index 0000000..6e613cc
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef SRC_OBJECT_ASPA_H_
+#define SRC_OBJECT_ASPA_H_
+
+#include "rpp.h"
+
+int aspa_traverse(struct rpki_uri *, struct rpp *);
+
+#endif /* SRC_OBJECT_ASPA_H_ */
index 8f5a45d6cf21bcbe249175e01e01a4cc56aa600e..2af60bd38e66f7c08dd3532d2916a1297b84f568 100644 (file)
@@ -44,7 +44,7 @@ handle_bgpsec(X509 *cert, struct resources *parent_resources, struct rpp *pp)
        resources = resources_create(policy, false);
        if (resources == NULL)
                goto revert_ski;
-       error = certificate_get_resources(cert, resources, CERTYPE_BGPSEC);
+       error = certificate_get_resources(cert, resources, CERTYPE_BGPSEC, 0);
        if (error)
                goto revert_resources;
 
index ac5108ee93da5111cfcae1adb97145ac9f61f0d9..931e7917f7062d44e5eeeb1ef238778316ead2fa 100644 (file)
@@ -1139,6 +1139,9 @@ handle_ip_extension(X509_EXTENSION *ext, struct resources *resources)
        int i;
        int error;
 
+       if (!X509_EXTENSION_get_critical(ext))
+               return pr_val_err("IP extension is not marked critical.");
+
        string = X509_EXTENSION_get_data(ext);
        error = asn1_decode(string->data, string->length, &asn_DEF_IPAddrBlocks,
            (void **) &blocks, true);
@@ -1199,95 +1202,92 @@ handle_asn_extension(X509_EXTENSION *ext, struct resources *resources,
        return error;
 }
 
-static int
-__certificate_get_resources(X509 *cert, struct resources *resources,
-    int addr_nid, int asn_nid, int bad_addr_nid, int bad_asn_nid,
-    char const *policy_rfc, char const *bad_ext_rfc, bool allow_asn_inherit)
+/**
+ * Copies the resources from @cert to @resources.
+ */
+int
+certificate_get_resources(X509 *cert, struct resources *resources,
+    enum cert_type type, enum ee_type eet)
 {
+       int allowed_ip_nid = NID_undef;
+       int allowed_as_nid = NID_undef;
+
+       int nid_ip1 = NID_sbgp_ipAddrBlock;
+       int nid_ip2 = nid_ipAddrBlocksv2();
+       int nid_as1 = NID_sbgp_autonomousSysNum;
+       int nid_as2 = nid_autonomousSysIdsv2();
+
        X509_EXTENSION *ext;
-       int nid;
-       int i;
+       int extnid;
+       int e;
        int error;
-       bool ip_ext_found = false;
-       bool asn_ext_found = false;
 
-       /* Reference: X509_get_ext_d2i */
-       /* rfc6487#section-2 */
+       switch (type) {
+       case CERTYPE_TA:
+       case CERTYPE_CA:
+       case CERTYPE_BGPSEC:
+               switch (resources_get_policy(resources)) {
+               case RPKI_POLICY_RFC6484:
+                       allowed_ip_nid = nid_ip1;
+                       allowed_as_nid = nid_as1;
+                       break;
+               case RPKI_POLICY_RFC8360:
+                       allowed_ip_nid = nid_ip2;
+                       allowed_as_nid = nid_as2;
+               }
+               break;
+       case CERTYPE_EE:
+               switch (eet) {
+               case EET_ROA:
+                       switch (resources_get_policy(resources)) {
+                       case RPKI_POLICY_RFC6484:
+                               allowed_ip_nid = nid_ip1; break;
+                       case RPKI_POLICY_RFC8360:
+                               allowed_ip_nid = nid_ip2;
+                       }
+                       break;
+               case EET_ASPA:
+                       switch (resources_get_policy(resources)) {
+                       case RPKI_POLICY_RFC6484:
+                               allowed_as_nid = nid_as1; break;
+                       case RPKI_POLICY_RFC8360:
+                               allowed_as_nid = nid_as2;
+                       }
+                       break;
+               case EET_MFT:
+               case EET_GBR:
+                       break;
+               }
+               break;
+       }
 
-       for (i = 0; i < X509_get_ext_count(cert); i++) {
-               ext = X509_get_ext(cert, i);
-               nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
+       for (e = 0; e < X509_get_ext_count(cert); e++) {
+               ext = X509_get_ext(cert, e);
+               extnid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
 
-               if (nid == addr_nid) {
-                       if (ip_ext_found)
-                               return pr_val_err("Multiple IP extensions found.");
-                       if (!X509_EXTENSION_get_critical(ext))
-                               return pr_val_err("The IP extension is not marked as critical.");
+               if (extnid == nid_ip1 || extnid == nid_ip2) {
+                       if (extnid != allowed_ip_nid)
+                               return pr_val_err("Found an unexpected IP Resources extension.");
 
-                       pr_val_debug("IP {");
                        error = handle_ip_extension(ext, resources);
-                       pr_val_debug("}");
-                       ip_ext_found = true;
-
                        if (error)
                                return error;
+                       allowed_ip_nid = NID_undef;
 
-               } else if (nid == asn_nid) {
-                       if (asn_ext_found)
-                               return pr_val_err("Multiple AS extensions found.");
-                       if (!X509_EXTENSION_get_critical(ext))
-                               return pr_val_err("The AS extension is not marked as critical.");
-
-                       pr_val_debug("ASN {");
-                       error = handle_asn_extension(ext, resources,
-                           allow_asn_inherit);
-                       pr_val_debug("}");
-                       asn_ext_found = true;
+               } else if (extnid == nid_as1 || extnid == nid_as2) {
+                       if (extnid != allowed_as_nid)
+                               return pr_val_err("Found an unexpected AS Resources extension.");
 
+                       error = handle_asn_extension(ext, resources, false);
                        if (error)
                                return error;
-
-               } else if (nid == bad_addr_nid) {
-                       return pr_val_err("Certificate has an RFC%s policy, but contains an RFC%s IP extension.",
-                           policy_rfc, bad_ext_rfc);
-               } else if (nid == bad_asn_nid) {
-                       return pr_val_err("Certificate has an RFC%s policy, but contains an RFC%s ASN extension.",
-                           policy_rfc, bad_ext_rfc);
+                       allowed_as_nid = NID_undef;
                }
        }
 
-       if (!ip_ext_found && !asn_ext_found)
-               return pr_val_err("Certificate lacks both IP and AS extension.");
-
        return 0;
 }
 
-/**
- * Copies the resources from @cert to @resources.
- */
-int
-certificate_get_resources(X509 *cert, struct resources *resources,
-    enum cert_type type)
-{
-       enum rpki_policy policy;
-
-       policy = resources_get_policy(resources);
-       switch (policy) {
-       case RPKI_POLICY_RFC6484:
-               return __certificate_get_resources(cert, resources,
-                   NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
-                   nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
-                   "6484", "8360", type != CERTYPE_BGPSEC);
-       case RPKI_POLICY_RFC8360:
-               return __certificate_get_resources(cert, resources,
-                   nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
-                   NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
-                   "8360", "6484", type != CERTYPE_BGPSEC);
-       }
-
-       pr_crit("Unknown policy: %u", policy);
-}
-
 static bool
 is_rsync(ASN1_IA5STRING *uri)
 {
index 37413f5244cb04ae3007dd822e9e9e05da8808e8..4aa2ace0138b8ae00c89b8a98319a5fe3901520f 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "asn1/asn1c/ANY.h"
 #include "asn1/asn1c/SignatureValue.h"
+#include "asn1/signed_data.h"
 #include "certificate_refs.h"
 #include "resource.h"
 
@@ -36,7 +37,8 @@ int certificate_validate_signature(X509 *, ANY_t *coded, SignatureValue_t *);
  * not care about order. I don't know if you'll find other reasons if you choose
  * to migrate it.
  */
-int certificate_get_resources(X509 *, struct resources *, enum cert_type);
+int certificate_get_resources(X509 *, struct resources *,
+    enum cert_type, enum ee_type);
 
 /**
  * Validates the certificate extensions, End-Entity style.
index 2aae99123fc5a391307594943aa60796aca508df..5b27d7e8e3d4d11435452472d6cd80dcbada66cb 100644 (file)
@@ -36,7 +36,7 @@ ghostbusters_traverse(struct rpki_uri *uri, struct rpp *pp)
        error = rpp_crl(pp, &crl);
        if (error)
                goto revert_sobj;
-       eecert_init(&ee, crl, true);
+       eecert_init(&ee, EET_GBR, crl, true);
 
        /* Validate everything */
        error = signed_object_validate(&sobj, &arcs, &ee);
index 8e404aa78f38cd48fd98dbf6057b7af021cc6e98..fa172d9ae5146a654d9369275e484425ba8c2743 100644 (file)
@@ -253,6 +253,8 @@ build_rpp(struct Manifest *mft, struct rpki_uri *notif,
                        rpp_add = rpp_add_cer;
                else if (strncmp(ext, ".roa", 4) == 0)
                        rpp_add = rpp_add_roa;
+               else if (strncmp(ext, ".asa", 4) == 0)
+                       rpp_add = rpp_add_asa;
                else if (strncmp(ext, ".crl", 4) == 0)
                        rpp_add = rpp_add_crl;
                else if (strncmp(ext, ".gbr", 4) == 0)
@@ -348,7 +350,7 @@ handle_manifest(struct rpki_uri *uri, struct rpki_uri *notif, struct rpp **pp)
        error = rpp_crl(*pp, &crl);
        if (error)
                goto revert_rpp;
-       eecert_init(&ee, crl, false);
+       eecert_init(&ee, EET_MFT, crl, false);
 
        /* Validate everything */
        error = signed_object_validate(&sobj, &arcs, &ee);
index 0b4067abe3c000a010063435b6bd1e33a323f4a2..a8f5d1bced7e4a6e6033e796df9bcce6df85df69 100644 (file)
@@ -271,7 +271,7 @@ roa_traverse(struct rpki_uri *uri, struct rpp *pp)
        error = rpp_crl(pp, &crl);
        if (error)
                goto revert_roa;
-       eecert_init(&ee, crl, false);
+       eecert_init(&ee, EET_ROA, crl, false);
 
        /* Validate and handle everything */
        error = signed_object_validate(&sobj, &arcs, &ee);
index 335157480165974ff50bfa15c6b97abced0241bf..635d813f318f5fed1680fadb63823cbeda56f3a2 100644 (file)
@@ -351,6 +351,7 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, struct db_table *db)
        validation_handler.handle_roa_v4 = handle_roa_v4;
        validation_handler.handle_roa_v6 = handle_roa_v6;
        validation_handler.handle_router_key = handle_router_key;
+       validation_handler.handle_aspa = handle_aspa;
        validation_handler.arg = db;
 
        error = validation_prepare(&state, tal, &validation_handler);
index 793acfc771d367608a0e0e17a1b49aa4b2c1f20e..e9a4523c3c5ef6ea9a855f1d10bda51104da024e 100644 (file)
@@ -556,6 +556,12 @@ resources_contains_asns(struct resources *res, struct asn_range const *range)
        return rasn_contains(res->asns, range);
 }
 
+bool
+resources_matches_asn(struct resources *res, uint32_t asid)
+{
+       return rasn_matches(res->asns, asid);
+}
+
 bool
 resources_contains_ipv4(struct resources *res, struct ipv4_prefix const *prefix)
 {
index 661e3b7bae0280e1704f79dc803ef496ac557085..7600798cb11f842d943e3a26160871ba7b9b4dd4 100644 (file)
@@ -31,6 +31,7 @@ int resources_add_asn(struct resources *, struct ASIdentifiers *, bool);
 
 bool resources_empty(struct resources *);
 bool resources_contains_asns(struct resources *, struct asn_range const *);
+bool resources_matches_asn(struct resources *, uint32_t);
 bool resources_contains_ipv4(struct resources *, struct ipv4_prefix const *);
 bool resources_contains_ipv6(struct resources *, struct ipv6_prefix const *);
 
index d9bebdc097ab3d9cfb86ec2effff4c506d2976ae..958856cdae12575b0d7de3d5305d45562616df66 100644 (file)
@@ -70,6 +70,21 @@ rasn_contains(struct resources_asn *asns, struct asn_range const *range)
        return sarray_contains((struct sorted_array *) asns, range);
 }
 
+bool
+rasn_matches(struct resources_asn *_asns, uint32_t asn)
+{
+       struct sorted_array *asns = (struct sorted_array *)_asns;
+       struct asn_range range;
+
+       if (asns == NULL)
+               return false;
+       if (sarray_count(asns) != 1u)
+               return false;
+
+       range.min = range.max = asn;
+       return sarray_contains(asns, &range);
+}
+
 static int
 asn_range_cb(void *node, void *arg)
 {
index 2d16c28e074008e6d3ae34c0de48e06b4437a833..1baf029e012c248fd3a320bc85eb7356efa919f5 100644 (file)
@@ -24,6 +24,7 @@ void rasn_put(struct resources_asn *);
 int rasn_add(struct resources_asn *, struct asn_range const *);
 bool rasn_empty(struct resources_asn *);
 bool rasn_contains(struct resources_asn *, struct asn_range const *);
+bool rasn_matches(struct resources_asn *, uint32_t);
 
 typedef int (*foreach_asn_cb)(struct asn_range const *, void *);
 int rasn_foreach(struct resources_asn *, foreach_asn_cb, void *);
index d62dcae054cfb48c63931cbb8db4902c7556ce8d..dbd7fc6d60e2169817a3c1b89cf951d0e0a55956 100644 (file)
--- a/src/rpp.c
+++ b/src/rpp.c
@@ -1,6 +1,7 @@
 #include "rpp.h"
 
 #include "log.h"
+#include "object/aspa.h"
 #include "object/crl.h"
 #include "object/ghostbusters.h"
 #include "object/roa.h"
@@ -34,6 +35,8 @@ struct rpp {
 
        struct uri_list roas; /* Route Origin Attestations */
 
+       struct uri_list aspas;
+
        struct uri_list ghostbusters;
 
        /*
@@ -99,6 +102,13 @@ rpp_add_roa(struct rpp *pp, struct rpki_uri *uri)
        return 0;
 }
 
+int
+rpp_add_asa(struct rpp *pp, struct rpki_uri *uri)
+{
+       uris_add(&pp->aspas, uri);
+       return 0;
+}
+
 /** Steals ownership of @uri. */
 int
 rpp_add_gbr(struct rpp *pp, struct rpki_uri *uri)
@@ -250,6 +260,9 @@ rpp_traverse(struct rpp *pp)
        ARRAYLIST_FOREACH(&pp->roas, uri)
                roa_traverse(*uri, pp);
 
+       ARRAYLIST_FOREACH(&pp->aspas, uri)
+               aspa_traverse(*uri, pp);
+
        /*
         * We don't do much with the ghostbusters right now.
         * Just validate them.
index 874068f575a563ce2315f5258c958d4410cf1cd1..afcdd835df41b1ab376c142d6652bade89f4b8c5 100644 (file)
--- a/src/rpp.h
+++ b/src/rpp.h
@@ -15,6 +15,7 @@ void rpp_refput(struct rpp *pp);
 int rpp_add_cer(struct rpp *, struct rpki_uri *);
 int rpp_add_crl(struct rpp *, struct rpki_uri *);
 int rpp_add_roa(struct rpp *, struct rpki_uri *);
+int rpp_add_asa(struct rpp *pp, struct rpki_uri *);
 int rpp_add_gbr(struct rpp *, struct rpki_uri *);
 
 struct rpki_uri *rpp_get_crl(struct rpp const *);
index 4d5355b6d9cb986217a306f21e78e58d530e6a51..f830db0e196c78fbfc82358f59085e6e757eb58a 100644 (file)
@@ -538,6 +538,7 @@ is_known_extension(struct rpki_uri *uri)
        ext = uri_get_global(uri) + uri_get_global_len(uri) - 4;
        return ((strcmp(ext, ".cer") == 0)
             || (strcmp(ext, ".roa") == 0)
+            || (strcmp(ext, ".asa") == 0)
             || (strcmp(ext, ".mft") == 0)
             || (strcmp(ext, ".crl") == 0)
             || (strcmp(ext, ".gbr") == 0));
index 2038381d503726a24ffa5129ad343ce773f412ec..4e26c871d6b1b2cbe90d1a32522dcd9da4340f01 100644 (file)
@@ -3,8 +3,10 @@
 #include <errno.h>
 
 #include "alloc.h"
+#include "config.h"
 #include "data_structure/uthash.h"
 #include "log.h"
+#include "types/aspa.h"
 
 struct hashable_roa {
        struct vrp data;
@@ -16,9 +18,15 @@ struct hashable_key {
        UT_hash_handle hh;
 };
 
+struct hashable_aspa {
+       struct aspa *v;
+       UT_hash_handle hh;
+};
+
 struct db_table {
        struct hashable_roa *roas;
        struct hashable_key *router_keys;
+       struct hashable_aspa *aspas;
 
        unsigned int total_roas_v4;
        unsigned int total_roas_v6;
@@ -100,6 +108,75 @@ add_router_key(struct db_table *table, struct hashable_key *new)
        return 0;
 }
 
+/* Assumes the lists are already sorted. Places the result in @new. */
+static struct aspa_providers
+merge_providers(struct aspa_providers *old, struct aspa_providers *new)
+{
+       struct aspa_providers result;
+       uint32_t *merge;
+       size_t o, n, m;
+
+       m = old->count + new->count;
+       if (!old->asids || m > config_get_max_aspa_providers()) {
+               result.asids = NULL;
+               result.count = 0;
+               return result;
+       }
+
+       merge = pcalloc(m, sizeof(uint32_t));
+
+       for (o = 0, n = 0, m = 0; o < old->count && n < new->count;) {
+               if (old->asids[o] < new->asids[n]) {
+                       merge[m] = old->asids[o];
+                       o++;
+                       m++;
+               } else if (old->asids[o] > new->asids[n]) {
+                       merge[m] = new->asids[n];
+                       n++;
+                       m++;
+               } else
+                       o++;
+       }
+
+       for (; o < old->count; o++, m++)
+               merge[m] = old->asids[o];
+       for (; n < new->count; n++, m++)
+               merge[m] = new->asids[n];
+
+       result.asids = merge;
+       result.count = m;
+       return result;
+}
+
+static int
+add_aspa(struct db_table *table, struct hashable_aspa *new)
+{
+       struct hashable_aspa *old;
+       struct aspa_providers merge;
+       int error;
+
+       errno = 0;
+       HASH_REPLACE(hh, table->aspas, v->customer, sizeof(new->v->customer),
+           new, old);
+       error = errno;
+       if (error) {
+               pr_val_err("Cannot store ASPA: %s", strerror(error));
+               return -error;
+       }
+
+       if (old != NULL) {
+               merge = merge_providers(&old->v->providers, &new->v->providers);
+
+               free(new->v->providers.asids);
+               new->v->providers = merge;
+
+               free(old->v->providers.asids);
+               free(old);
+       }
+
+       return 0;
+}
+
 /* Moves the content from @src into @dst. */
 int
 db_table_join(struct db_table *dst, struct db_table *src)
@@ -156,6 +233,22 @@ db_table_foreach_router_key(struct db_table const *table,
        return 0;
 }
 
+int
+db_table_foreach_aspa(struct db_table const *table, aspa_foreach_cb cb,
+    void *arg)
+{
+       struct hashable_aspa *node, *tmp;
+       int error;
+
+       HASH_ITER(hh, table->aspas, node, tmp) {
+               error = cb(node->v, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
 unsigned int
 db_table_roa_count(struct db_table *table)
 {
@@ -253,6 +346,24 @@ rtrhandler_handle_router_key(struct db_table *table, unsigned char const *ski,
        return error;
 }
 
+int
+rtrhandler_handle_aspa(struct db_table *table, struct aspa *v)
+{
+       struct hashable_aspa *aspa;
+       int error;
+
+       aspa = pzalloc(sizeof(struct hashable_aspa));
+       aspa->v = v;
+
+       error = add_aspa(table, aspa);
+       if (error)
+               free(aspa);
+       else
+               aspa_refget(v);
+
+       return error;
+}
+
 /*
  * Copies `@roas1 - roas2` into @deltas.
  *
@@ -282,12 +393,6 @@ add_roa_deltas(struct hashable_roa *roas1, struct hashable_roa *roas2,
        return 0;
 }
 
-static void
-add_router_key_delta(struct deltas *deltas, struct hashable_key *key, int op)
-{
-       deltas_add_router_key(deltas, &key->data, op);
-}
-
 /*
  * Copies `@keys1 - keys2` into @deltas.
  *
@@ -303,7 +408,33 @@ add_router_key_deltas(struct hashable_key *keys1, struct hashable_key *keys2,
        for (n1 = keys1; n1 != NULL; n1 = n1->hh.next) {
                HASH_FIND(hh, keys2, &n1->data, sizeof(n1->data), n2);
                if (n2 == NULL)
-                       add_router_key_delta(deltas, n1, op);
+                       deltas_add_router_key(deltas, &n1->data, op);
+       }
+}
+
+static void
+add_aspa_announcements(struct hashable_aspa *old, struct hashable_aspa *new,
+    struct deltas *deltas)
+{
+       struct hashable_aspa *o, *n, *tmp;
+
+       HASH_ITER(hh, new, n, tmp) {
+               HASH_FIND(hh, old, &n->v->customer, sizeof(n->v->customer), o);
+               if (o == NULL || !providers_equal(&o->v->providers, &n->v->providers))
+                       deltas_add_aspa(deltas, o->v, FLAG_ANNOUNCEMENT);
+       }
+}
+
+static void
+add_aspa_withdraws(struct hashable_aspa *old, struct hashable_aspa *new,
+    struct deltas *deltas)
+{
+       struct hashable_aspa *o, *n, *tmp;
+
+       HASH_ITER(hh, old, o, tmp) {
+               HASH_FIND(hh, new, &o->v->customer, sizeof(o->v->customer), n);
+               if (n == NULL)
+                       deltas_add_aspa(deltas, o->v, FLAG_WITHDRAWAL);
        }
 }
 
@@ -318,6 +449,8 @@ compute_deltas(struct db_table *old, struct db_table *new)
            FLAG_ANNOUNCEMENT);
        add_router_key_deltas(old->router_keys, new->router_keys, deltas,
            FLAG_WITHDRAWAL);
+       add_aspa_announcements(old->aspas, new->aspas, deltas);
+       add_aspa_withdraws(old->aspas, new->aspas, deltas);
 
        if (deltas_is_empty(deltas)) {
                deltas_refput(deltas);
index 814d3af03229618069c9cac1454abb7ae0c49d59..894187dcf545afc616b25869a65af623462ab33d 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "rtr/db/delta.h"
 #include "types/address.h"
+#include "types/aspa.h"
 
 struct db_table;
 
@@ -23,12 +24,15 @@ int db_table_foreach_router_key(struct db_table const *, router_key_foreach_cb,
     void *);
 void db_table_remove_router_key(struct db_table *, struct router_key const *);
 
+int db_table_foreach_aspa(struct db_table const *, aspa_foreach_cb, void *);
+
 int rtrhandler_handle_roa_v4(struct db_table *, uint32_t,
     struct ipv4_prefix const *, uint8_t);
 int rtrhandler_handle_roa_v6(struct db_table *, uint32_t,
     struct ipv6_prefix const *, uint8_t);
 int rtrhandler_handle_router_key(struct db_table *, unsigned char const *,
     uint32_t, unsigned char const *);
+int rtrhandler_handle_aspa(struct db_table *, struct aspa *);
 struct deltas *compute_deltas(struct db_table *, struct db_table *);
 
 #endif /* SRC_RTR_DB_DB_TABLE_H_ */
index bd625748148f1a15898e958f8f34aaea26f21dc3..c5f96047e9aa7873a88498affa60a621da2b203c 100644 (file)
@@ -25,9 +25,14 @@ struct delta_rk {
        unsigned char   spk[RK_SPKI_LEN];
 };
 
+struct _delta_aspa {
+       struct aspa *aspa;
+};
+
 STATIC_ARRAY_LIST(deltas_v6, struct delta_v6)
 STATIC_ARRAY_LIST(deltas_v4, struct delta_v4)
 STATIC_ARRAY_LIST(deltas_rk, struct delta_rk)
+STATIC_ARRAY_LIST(deltas_aspa, struct _delta_aspa)
 
 struct deltas {
        struct {
@@ -42,6 +47,10 @@ struct deltas {
                struct deltas_rk adds;
                struct deltas_rk removes;
        } rk;
+       struct {
+               struct deltas_aspa adds;
+               struct deltas_aspa removes;
+       } aspa;
 
        atomic_uint references;
 };
@@ -59,6 +68,8 @@ deltas_create(void)
        deltas_v6_init(&result->v6.removes);
        deltas_rk_init(&result->rk.adds);
        deltas_rk_init(&result->rk.removes);
+       deltas_aspa_init(&result->aspa.adds);
+       deltas_aspa_init(&result->aspa.removes);
        atomic_init(&result->references, 1);
 
        return result;
@@ -84,6 +95,8 @@ deltas_refput(struct deltas *deltas)
                deltas_v6_cleanup(&deltas->v6.removes, NULL);
                deltas_rk_cleanup(&deltas->rk.adds, NULL);
                deltas_rk_cleanup(&deltas->rk.removes, NULL);
+               deltas_aspa_cleanup(&deltas->aspa.adds, NULL);
+               deltas_aspa_cleanup(&deltas->aspa.removes, NULL);
                free(deltas);
        }
 }
@@ -177,6 +190,26 @@ deltas_add_router_key(struct deltas *deltas, struct router_key const *key,
        pr_crit("Unknown delta operation: %d", op);
 }
 
+void
+deltas_add_aspa(struct deltas *deltas, struct aspa *aspa, int op)
+{
+       struct _delta_aspa delta;
+
+       delta.aspa = aspa;
+       aspa_refget(aspa);
+
+       switch (op) {
+       case FLAG_ANNOUNCEMENT:
+               deltas_aspa_add(&deltas->aspa.adds, &delta);
+               return;
+       case FLAG_WITHDRAWAL:
+               deltas_aspa_add(&deltas->aspa.removes, &delta);
+               return;
+       }
+
+       pr_crit("Unknown delta operation: %d", op);
+}
+
 bool
 deltas_is_empty(struct deltas *deltas)
 {
@@ -185,7 +218,9 @@ deltas_is_empty(struct deltas *deltas)
            && (deltas->v6.adds.len == 0)
            && (deltas->v6.removes.len == 0)
            && (deltas->rk.adds.len == 0)
-           && (deltas->rk.removes.len == 0);
+           && (deltas->rk.removes.len == 0)
+           && (deltas->aspa.adds.len == 0)
+           && (deltas->aspa.removes.len == 0);
 }
 
 static int
@@ -258,37 +293,59 @@ __foreach_rk(struct deltas_rk *array,  delta_router_key_foreach_cb cb,
        return 0;
 }
 
+static int
+__foreach_aspa(struct deltas_aspa *array, delta_aspa_foreach_cb cb, void *arg,
+    uint8_t flags)
+{
+       struct delta_aspa delta;
+       struct _delta_aspa *d;
+       int error;
+
+       delta.flags = flags;
+
+       ARRAYLIST_FOREACH(array, d) {
+               delta.aspa = d->aspa;
+               error = cb(&delta, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
 int
 deltas_foreach(struct deltas *deltas, delta_vrp_foreach_cb cb_vrp,
-    delta_router_key_foreach_cb cb_rk, void *arg)
+    delta_router_key_foreach_cb cb_rk, delta_aspa_foreach_cb cb_aspa,
+    void *arg)
 {
        int error;
 
        error = __foreach_v4(&deltas->v4.adds, cb_vrp, arg, FLAG_ANNOUNCEMENT);
        if (error)
                return error;
-
        error = __foreach_v4(&deltas->v4.removes, cb_vrp, arg, FLAG_WITHDRAWAL);
        if (error)
                return error;
-
        error = __foreach_v6(&deltas->v6.adds, cb_vrp, arg, FLAG_ANNOUNCEMENT);
        if (error)
                return error;
-
        error = __foreach_v6(&deltas->v6.removes, cb_vrp, arg, FLAG_WITHDRAWAL);
        if (error)
                return error;
-
        error = __foreach_rk(&deltas->rk.adds, cb_rk, arg, FLAG_ANNOUNCEMENT);
        if (error)
                return error;
-
-       return __foreach_rk(&deltas->rk.removes, cb_rk, arg, FLAG_WITHDRAWAL);
+       error = __foreach_rk(&deltas->rk.removes, cb_rk, arg, FLAG_WITHDRAWAL);
+       if (error)
+               return error;
+       error = __foreach_aspa(&deltas->aspa.adds, cb_aspa, arg, FLAG_ANNOUNCEMENT);
+       if (error)
+               return error;
+       return __foreach_aspa(&deltas->aspa.removes, cb_aspa, arg, FLAG_WITHDRAWAL);
 }
 
 void
 deltas_print(struct deltas *deltas)
 {
-       deltas_foreach(deltas, delta_vrp_print, delta_rk_print, NULL);
+       deltas_foreach(deltas, delta_vrp_print, delta_rk_print, delta_aspa_print, NULL);
 }
index cdaa9bcb2c832901b795edcf5e85a240740fa9f1..b7d943ced3046c1002e78b5ccf4693276200e86d 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef SRC_DELTA_H_
 #define SRC_DELTA_H_
 
+#include "types/aspa.h"
 #include "types/delta.h"
 
 struct deltas;
@@ -12,10 +13,11 @@ void deltas_refput(struct deltas *);
 void deltas_add_roa(struct deltas *, struct vrp const *, int,
     char, unsigned int, unsigned int);
 void deltas_add_router_key(struct deltas *, struct router_key const *, int);
+void deltas_add_aspa(struct deltas *, struct aspa *, int);
 
 bool deltas_is_empty(struct deltas *);
 int deltas_foreach(struct deltas *, delta_vrp_foreach_cb,
-    delta_router_key_foreach_cb, void *);
+    delta_router_key_foreach_cb, delta_aspa_foreach_cb, void *);
 void deltas_print(struct deltas *);
 
 #endif /* SRC_DELTA_H_ */
index f23107d6b3f6cece57f3c53a7a81406d8d3b54b8..7778ce08d1c94debfc25b46a47a9aa557032b96f 100644 (file)
@@ -22,13 +22,20 @@ struct rk_node {
        SLIST_ENTRY(rk_node) next;
 };
 
+struct aspa_node {
+       struct delta_aspa delta;
+       SLIST_ENTRY(aspa_node) next;
+};
+
 /** Sorted list to filter deltas */
 SLIST_HEAD(vrp_slist, vrp_node);
 SLIST_HEAD(rk_slist, rk_node);
+SLIST_HEAD(aspa_slist, aspa_node);
 
 struct sorted_lists {
        struct vrp_slist prefixes;
        struct rk_slist router_keys;
+       struct aspa_slist aspas;
 };
 
 struct state {
@@ -168,6 +175,12 @@ handle_router_key(unsigned char const *ski, struct asn_range const *asns,
        return 0;
 }
 
+int
+handle_aspa(struct aspa *aspa, void *arg)
+{
+       return rtrhandler_handle_aspa(arg, aspa);
+}
+
 /*
  * High level validator function.
  *
@@ -289,7 +302,8 @@ vrps_update(bool *changed)
  * 2. -EAGAIN: No data available; database still under construction.
  */
 int
-vrps_foreach_base(vrp_foreach_cb cb_roa, router_key_foreach_cb cb_rk, void *arg)
+vrps_foreach_base(vrp_foreach_cb cb_roa, router_key_foreach_cb cb_rk,
+    aspa_foreach_cb cb_aspa, void *arg)
 {
        int error;
 
@@ -302,6 +316,9 @@ vrps_foreach_base(vrp_foreach_cb cb_roa, router_key_foreach_cb cb_rk, void *arg)
                if (error)
                        goto end;
                error = db_table_foreach_router_key(state.base, cb_rk, arg);
+               if (error)
+                       goto end;
+               error = db_table_foreach_aspa(state.base, cb_aspa, arg);
        } else
                error = -EAGAIN;
 
@@ -355,6 +372,7 @@ router_key_ovrd_remove(struct delta_router_key const *delta, void *arg)
                    && memcmp(key->spk, ptr->delta.router_key.spk,
                    RK_SPKI_LEN) == 0 &&
                    delta->flags != ptr->delta.flags) {
+                       /* TODO (rk) Shouldn't it be replaced? */
                        SLIST_REMOVE(filtered_keys, ptr, rk_node, next);
                        free(ptr);
                        return 0;
@@ -368,11 +386,34 @@ router_key_ovrd_remove(struct delta_router_key const *delta, void *arg)
        return 0;
 }
 
+static int
+aspa_ovrd_remove(struct delta_aspa const *delta, void *arg)
+{
+       struct sorted_lists *lists = arg;
+       struct aspa_node *ptr;
+       struct aspa_slist *filtered_aspas;
+
+       filtered_aspas = &lists->aspas;
+       SLIST_FOREACH(ptr, filtered_aspas, next) {
+               if (delta->aspa->customer == ptr->delta.aspa->customer) {
+                       SLIST_REMOVE(filtered_aspas, ptr, aspa_node, next);
+                       ptr->delta = *delta;
+                       SLIST_INSERT_HEAD(filtered_aspas, ptr, next);
+                       return 0;
+               }
+       }
+
+       ptr = pmalloc(sizeof(struct aspa_node));
+       ptr->delta = *delta;
+       SLIST_INSERT_HEAD(filtered_aspas, ptr, next);
+       return 0;
+}
+
 static int
 __deltas_foreach(struct deltas *deltas, void *arg)
 {
        return deltas_foreach(deltas, vrp_ovrd_remove, router_key_ovrd_remove,
-           arg);
+           aspa_ovrd_remove, arg);
 }
 
 /**
@@ -388,11 +429,12 @@ __deltas_foreach(struct deltas *deltas, void *arg)
 int
 vrps_foreach_delta_since(serial_t from, serial_t *to,
     delta_vrp_foreach_cb vrp_cb, delta_router_key_foreach_cb rk_cb,
-    void *arg)
+    delta_aspa_foreach_cb aspa_cb, void *arg)
 {
        struct sorted_lists filtered_lists;
        struct vrp_node *vnode;
        struct rk_node *rnode;
+       struct aspa_node *anode;
        int error;
 
        error = rwlock_read_lock(&state_lock);
@@ -434,6 +476,7 @@ vrps_foreach_delta_since(serial_t from, serial_t *to,
         */
        SLIST_INIT(&filtered_lists.prefixes);
        SLIST_INIT(&filtered_lists.router_keys);
+       SLIST_INIT(&filtered_lists.aspas);
 
        error = darray_foreach_since(state.deltas, state.serial - from,
            __deltas_foreach, &filtered_lists);
@@ -451,6 +494,11 @@ vrps_foreach_delta_since(serial_t from, serial_t *to,
                if (error)
                        break;
        }
+       SLIST_FOREACH(anode, &filtered_lists.aspas, next) {
+               error = aspa_cb(&anode->delta, arg);
+               if (error)
+                       break;
+       }
 
 release_list:
        while (!SLIST_EMPTY(&filtered_lists.prefixes)) {
@@ -463,6 +511,11 @@ release_list:
                SLIST_REMOVE_HEAD(&filtered_lists.router_keys, next);
                free(rnode);
        }
+       while (!SLIST_EMPTY(&filtered_lists.aspas)) {
+               anode = filtered_lists.aspas.slh_first;
+               SLIST_REMOVE_HEAD(&filtered_lists.aspas, next);
+               free(anode);
+       }
 
        *to = state.serial;
        rwlock_unlock(&state_lock);
@@ -507,5 +560,5 @@ get_current_session_id(uint8_t rtr_version)
 void
 vrps_print_base(void)
 {
-       vrps_foreach_base(vrp_print, router_key_print, NULL);
+       vrps_foreach_base(vrp_print, router_key_print, aspa_print, NULL);
 }
index f3a6521150cdda69451652f8edffdca53bb42363..4a9bd2cde373b68a21d8d0a6b03b76eb4d028aa4 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "as_number.h"
 #include "types/address.h"
+#include "types/aspa.h"
 #include "types/delta.h"
 #include "types/serial.h"
 
@@ -23,15 +24,17 @@ int vrps_update(bool *);
  * Handle gracefully.
  */
 
-int vrps_foreach_base(vrp_foreach_cb, router_key_foreach_cb, void *);
+int vrps_foreach_base(vrp_foreach_cb, router_key_foreach_cb, aspa_foreach_cb,
+    void *);
 int vrps_foreach_delta_since(serial_t, serial_t *, delta_vrp_foreach_cb,
-    delta_router_key_foreach_cb, void *);
+    delta_router_key_foreach_cb, delta_aspa_foreach_cb, void *);
 int get_last_serial_number(serial_t *);
 
 int handle_roa_v4(uint32_t, struct ipv4_prefix const *, uint8_t, void *);
 int handle_roa_v6(uint32_t, struct ipv6_prefix const *, uint8_t, void *);
 int handle_router_key(unsigned char const *, struct asn_range const *,
     unsigned char const *, void *);
+int handle_aspa(struct aspa *, void *);
 
 uint16_t get_current_session_id(uint8_t);
 
index 86fcd1416147edcd03bf55e84292ec51848efdb9..0782957978da8c708dfcaa9e8ca41ffc645e7ddd 100644 (file)
@@ -24,6 +24,8 @@ pdutype2str(enum pdu_type type)
                return "Router Key PDU";
        case PDU_TYPE_ERROR_REPORT:
                return "Error Report PDU";
+       case PDU_TYPE_ASPA:
+               return "ASPA PDU";
        }
 
        return "unknown PDU";
index 35ded498848ece1de97f48941451763f71d2eabc..60372a2bbad78d35c5d3c8d04e16eb02ff546e58 100644 (file)
@@ -10,6 +10,7 @@
 enum rtr_version {
        RTR_V0                  = 0,
        RTR_V1                  = 1,
+       RTR_V2                  = 2,
 };
 
 struct rtr_buffer {
@@ -28,6 +29,7 @@ enum pdu_type {
        PDU_TYPE_CACHE_RESET    = 8,
        PDU_TYPE_ROUTER_KEY     = 9,
        PDU_TYPE_ERROR_REPORT   = 10,
+       PDU_TYPE_ASPA           = 11,
 };
 
 char const *pdutype2str(enum pdu_type);
index 5a419140cf67fc8bdbbb89da144dfd1e80207200..39ea6b24994edba10103f89432a80ea46701d7f4 100644 (file)
@@ -56,6 +56,20 @@ send_delta_rk(struct delta_router_key const *delta, void *arg)
            &delta->router_key, delta->flags);
 }
 
+static int
+send_delta_aspa(struct delta_aspa const *delta, void *arg)
+{
+       struct send_delta_args *args = arg;
+       int error;
+
+       error = send_cache_response_maybe(args);
+       if (error)
+               return error;
+
+       return send_aspa_pdu(args->fd, args->rtr_version,
+           delta->aspa, delta->flags);
+}
+
 int
 handle_serial_query_pdu(struct rtr_request *request)
 {
@@ -93,7 +107,8 @@ handle_serial_query_pdu(struct rtr_request *request)
         */
 
        error = vrps_foreach_delta_since(request->pdu.obj.sq.serial_number,
-           &final_serial, send_delta_vrp, send_delta_rk, &args);
+           &final_serial, send_delta_vrp, send_delta_rk, send_delta_aspa,
+           &args);
        switch (error) {
        case 0:
                /*
@@ -167,6 +182,22 @@ send_base_router_key(struct router_key const *key, void *arg)
            FLAG_ANNOUNCEMENT);
 }
 
+static int
+send_base_aspa(struct aspa const *aspa, void *arg)
+{
+       struct base_roa_args *args = arg;
+       int error;
+
+       if (!args->started) {
+               error = send_cache_response_pdu(args->fd, args->version);
+               if (error)
+                       return error;
+               args->started = true;
+       }
+
+       return send_aspa_pdu(args->fd, args->version, aspa, FLAG_ANNOUNCEMENT);
+}
+
 int
 handle_reset_query_pdu(struct rtr_request *request)
 {
@@ -196,7 +227,8 @@ handle_reset_query_pdu(struct rtr_request *request)
         * queries than reset queries.
         */
 
-       error = vrps_foreach_base(send_base_roa, send_base_router_key, &args);
+       error = vrps_foreach_base(send_base_roa, send_base_router_key,
+           send_base_aspa, &args);
 
        /* See handle_serial_query_pdu() for some comments. */
        switch (error) {
index 2e50c23d98e21b62f76486caab24ceb0d6df6456..064a331f36a9423bcad0fcfb810b5c38f4a9e5e0 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "alloc.h"
 #include "config.h"
+#include "data_structure/common.h"
 #include "log.h"
 #include "rtr/db/vrps.h"
 #include "rtr/primitive_writer.h"
@@ -184,7 +185,7 @@ send_router_key_pdu(int fd, uint8_t version,
        unsigned char data[RTRPDU_ROUTER_KEY_LEN];
        unsigned char *buf;
 
-       if (version == RTR_V0)
+       if (version < RTR_V1)
                return 0;
 
        buf = serialize_hdr(data, version, type, flags << 8, len);
@@ -197,6 +198,52 @@ send_router_key_pdu(int fd, uint8_t version,
        return send_response(fd, type, data, len);
 }
 
+int
+send_aspa_pdu(int fd, uint8_t version, struct aspa const *aspa, uint8_t flags)
+{
+       static const uint8_t type = PDU_TYPE_ASPA;
+       unsigned char data[1024];
+       array_index i;
+       unsigned char *buf;
+       int error;
+
+       if (version < RTR_V2)
+               return 0;
+
+       if (flags & FLAG_ANNOUNCEMENT) {
+               buf = serialize_hdr(data, version, type, flags << 8,
+                   12 + 4 * aspa->providers.count);
+               buf = write_uint32(buf, aspa->customer);
+
+               for (i = 0; i < aspa->providers.count; i++) {
+                       buf = write_uint32(buf, aspa->providers.asids[i]);
+
+                       if (buf >= data + 1024) {
+                               error = send_response(fd, type, data, buf - data);
+                               if (error)
+                                       return error;
+                               buf = data;
+                       }
+               }
+
+               if (buf > data) {
+                       error = send_response(fd, type, data, buf - data);
+                       if (error)
+                               return error;
+               }
+
+       } else {
+               buf = serialize_hdr(data, version, type, flags << 8, 12);
+               write_uint32(buf, aspa->customer);
+               error = send_response(fd, type, data, 12);
+               if (error)
+                       return error;
+       }
+
+
+       return 0;
+}
+
 #define MAX(a, b) ((a > b) ? a : b)
 
 int
index ed1b709efec2ae849781672cb528f2bf02bb7882..ea05dc1a175b9ff5d47eafd69beca4d1f6aecf27 100644 (file)
@@ -2,6 +2,7 @@
 #define SRC_RTR_PDU_SENDER_H_
 
 #include "rtr/pdu.h"
+#include "types/aspa.h"
 #include "types/router_key.h"
 #include "types/serial.h"
 #include "types/vrp.h"
@@ -11,6 +12,7 @@ int send_cache_reset_pdu(int, uint8_t);
 int send_cache_response_pdu(int, uint8_t);
 int send_prefix_pdu(int, uint8_t, struct vrp const *, uint8_t);
 int send_router_key_pdu(int, uint8_t, struct router_key const *, uint8_t);
+int send_aspa_pdu(int, uint8_t, struct aspa const *, uint8_t);
 int send_end_of_data_pdu(int, uint8_t, serial_t);
 int send_error_report_pdu(int, uint8_t, uint16_t, struct rtr_buffer const *,
     char *);
index e6d10bf108344d19f54eac871683e417a8c9f6d3..b18a5b0d12c81b8a41bf393add6b1b1ef49b7498 100644 (file)
@@ -165,6 +165,12 @@ sarray_contains(struct sorted_array const *sarray, void const *elem)
        return false;
 }
 
+unsigned int
+sarray_count(struct sorted_array const *sarray)
+{
+       return sarray ? sarray->count : 0;
+}
+
 int
 sarray_foreach(struct sorted_array *sarray, sarray_foreach_cb cb, void *arg)
 {
index b06a685d642dfcdbc9c64d3158e7c3f19845f5dd..166f6a760160ea276054cd1f5f1788cc6e424f60 100644 (file)
@@ -41,6 +41,7 @@ void sarray_put(struct sorted_array *);
 int sarray_add(struct sorted_array *, void const *);
 bool sarray_empty(struct sorted_array const *);
 bool sarray_contains(struct sorted_array const *, void const *);
+unsigned int sarray_count(struct sorted_array const *);
 
 typedef int (*sarray_foreach_cb)(void *, void *);
 int sarray_foreach(struct sorted_array *, sarray_foreach_cb, void *);
diff --git a/src/types/aspa.c b/src/types/aspa.c
new file mode 100644 (file)
index 0000000..406b761
--- /dev/null
@@ -0,0 +1,48 @@
+#include "types/aspa.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "data_structure/common.h"
+
+void
+aspa_refget(struct aspa *aspa)
+{
+       aspa->refs++;
+}
+
+void
+aspa_refput(struct aspa *aspa)
+{
+       if ((aspa->refs--) <= 1) {
+               free(aspa->providers.asids);
+               free(aspa);
+       }
+}
+
+int
+aspa_print(struct aspa const *aspa, void *arg)
+{
+       array_index i;
+       printf("- [ASPA customerASID:%u\n", aspa->customer);
+       for (i = 0; i < aspa->providers.count; i++)
+               printf("    [Provider:%u]\n", aspa->providers.asids[i]);
+       printf("  ]\n");
+       return 0;
+}
+
+bool
+providers_equal(struct aspa_providers *a, struct aspa_providers *b)
+{
+       array_index i;
+
+       if (a == b)
+               return true;
+       if (!a || !b || (a->count != b->count))
+               return false;
+
+       for (i = 0; i < a->count; i++)
+               if (a->asids[i] != b->asids[i])
+                       return false;
+
+       return true;
+}
diff --git a/src/types/aspa.h b/src/types/aspa.h
new file mode 100644 (file)
index 0000000..d4ea190
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef SRC_TYPES_ASPA_H_
+#define SRC_TYPES_ASPA_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct aspa_providers {
+       /* Can be NULL and zero. If this happens, just withdraw. */
+       uint32_t *asids;
+       size_t count;
+};
+
+struct aspa {
+       uint32_t customer;
+       struct aspa_providers providers;
+
+       int refs;
+};
+
+typedef int (*aspa_foreach_cb)(struct aspa const *, void *);
+
+void aspa_refget(struct aspa *);
+void aspa_refput(struct aspa *);
+int aspa_print(struct aspa const *, void *);
+
+bool providers_equal(struct aspa_providers *, struct aspa_providers *);
+
+#endif /* SRC_TYPES_ASPA_H_ */
index dacdf1952b956683a7231b0204c69dcbca7802c2..1b9d895936d970578184cb66caf9be81f127c290 100644 (file)
@@ -31,3 +31,10 @@ delta_rk_print(struct delta_router_key const *delta, void *arg)
        print_flag(delta->flags);
        return router_key_print(&delta->router_key, arg);
 }
+
+int
+delta_aspa_print(struct delta_aspa const *delta, void *arg)
+{
+       print_flag(delta->flags);
+       return aspa_print(delta->aspa, arg);
+}
index 9b7914ea0e3cf5184c48923bb9cc3713d215ee7d..c29f3c4d437963ba58e8e6292c73c2f5a9c68439 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef SRC_TYPES_DELTA_H_
 #define SRC_TYPES_DELTA_H_
 
+#include "types/aspa.h"
 #include "types/router_key.h"
 #include "types/vrp.h"
 
@@ -17,11 +18,18 @@ struct delta_router_key {
        uint8_t flags;
 };
 
+struct delta_aspa {
+       struct aspa *aspa;
+       uint8_t flags;
+};
+
 typedef int (*delta_vrp_foreach_cb)(struct delta_vrp const *, void *);
 typedef int (*delta_router_key_foreach_cb)(struct delta_router_key const *,
     void *);
+typedef int (*delta_aspa_foreach_cb)(struct delta_aspa const *, void *);
 
 int delta_vrp_print(struct delta_vrp const *, void *);
 int delta_rk_print(struct delta_router_key const *, void *);
+int delta_aspa_print(struct delta_aspa const *, void *);
 
 #endif /* SRC_TYPES_DELTA_H_ */
index 9b02ac1e0a86c1f22cfafd773805a0b3496877f0..4c97632868233d6645f11c448e9d1cdddca3ea07 100644 (file)
@@ -56,3 +56,15 @@ vhandler_handle_router_key(unsigned char const *ski,
            ? handler->handle_router_key(ski, asns, spk, handler->arg)
            : 0;
 }
+
+int
+vhandler_handle_aspa(struct aspa *aspa)
+{
+       struct validation_handler const *handler;
+
+       handler = get_current_threads_handler();
+
+       return (handler->handle_aspa != NULL)
+           ? handler->handle_aspa(aspa, handler->arg)
+           : 0;
+}
index 2e284c1f923297e00185646fc1b0ed953d6fc87e..c6b502221a819ab82ef8236648d38eaa671769d6 100644 (file)
@@ -30,6 +30,8 @@ struct validation_handler {
        /** Called every time Fort has successfully validated a BGPsec cert */
        int (*handle_router_key)(unsigned char const *,
            struct asn_range const *, unsigned char const *, void *);
+       /* Swallows the ASPA. */
+       int (*handle_aspa)(struct aspa *, void *);
        /** Generic user-defined argument for the functions above. */
        void *arg;
 };
@@ -38,5 +40,6 @@ int vhandler_handle_roa_v4(uint32_t, struct ipv4_prefix const *, uint8_t);
 int vhandler_handle_roa_v6(uint32_t, struct ipv6_prefix const *, uint8_t);
 int vhandler_handle_router_key(unsigned char const *, struct asn_range const *,
     unsigned char const *);
+int vhandler_handle_aspa(struct aspa *);
 
 #endif /* SRC_VALIDATION_HANDLER_H_ */
index b19ae4029f77274998b2ad8aaed7cfdf68e1ccc2..d3492cf341e0405164d2db754b2ba0eb4fce3539 100644 (file)
@@ -19,6 +19,7 @@ static bool roas_found[TOTAL_ROAS];
 static unsigned int total_found;
 
 __MOCK_ABORT(config_get_local_repository, char const *, "tmp/dbt", void)
+MOCK_UINT(config_get_max_aspa_providers, 10, void)
 
 static bool
 vrp_equals_v4(struct vrp const *vrp, uint8_t as, uint32_t addr,
@@ -166,6 +167,83 @@ START_TEST(test_basic)
 }
 END_TEST
 
+static void
+init_providers(struct aspa_providers *provs, ...)
+{
+       int asn;
+       size_t a;
+       va_list ap;
+
+       va_start(ap, provs);
+       for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+               ;
+       va_end(ap);
+
+       provs->asids = pcalloc(a, sizeof(uint32_t));
+       provs->count = a;
+
+       va_start(ap, provs);
+       for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+               provs->asids[a] = asn;
+       va_end(ap);
+}
+
+static void
+ck_merge(struct aspa_providers *a1, struct aspa_providers *a2, ...)
+{
+       struct aspa_providers res;
+       va_list ap;
+       size_t a;
+       int asn;
+
+       res = merge_providers(a1, a2);
+
+       va_start(ap, a2);
+       for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+               ck_assert_uint_eq(asn, res.asids[a]);
+       va_end(ap);
+       ck_assert_uint_eq(a, res.count);
+       free(res.asids);
+
+       res = merge_providers(a2, a1);
+       va_start(ap, a2);
+       for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+               ck_assert_uint_eq(asn, res.asids[a]);
+       va_end(ap);
+       ck_assert_uint_eq(a, res.count);
+       free(res.asids);
+}
+
+START_TEST(test_aspa_merge)
+{
+       struct aspa_providers a, b;
+
+       init_providers(&a, 1, 2, 3, 0);
+       init_providers(&b, 5, 6, 7, 0);
+       ck_merge(&a, &b, 1, 2, 3, 5, 6, 7, 0);
+
+       init_providers(&a, 1, 3, 5, 0);
+       init_providers(&b, 2, 4, 6, 0);
+       ck_merge(&a, &b, 1, 2, 3, 4, 5, 6, 0);
+
+       init_providers(&a, 2, 4, 10, 0);
+       init_providers(&b, 6, 8, 12, 0);
+       ck_merge(&a, &b, 2, 4, 6, 8, 10, 12, 0);
+
+       init_providers(&a, 1, 2, 3, 4, 0);
+       init_providers(&b, 1, 2, 3, 4, 0);
+       ck_merge(&a, &b, 1, 2, 3, 4, 0);
+
+       init_providers(&a, 1, 2, 3, 0);
+       init_providers(&b, 1, 2, 4, 6, 0);
+       ck_merge(&a, &b, 1, 2, 3, 4, 6, 0);
+
+       init_providers(&a, 1, 2, 3, 0);
+       init_providers(&b, 1, 2, 3, 4, 5, 0);
+       ck_merge(&a, &b, 1, 2, 3, 4, 5, 0);
+}
+END_TEST
+
 static Suite *pdu_suite(void)
 {
        Suite *suite;
@@ -173,6 +251,7 @@ static Suite *pdu_suite(void)
 
        core = tcase_create("Core");
        tcase_add_test(core, test_basic);
+       tcase_add_test(core, test_aspa_merge);
 
        suite = suite_create("DB Table");
        suite_add_tcase(suite, core);
index 63e93de9ec0de1842a0096dff4c2ceb3ad461045..479ea7dcc66642c593de1a12e33a20504ec42b65 100644 (file)
@@ -73,6 +73,7 @@ MOCK_ABORT_ENUM(config_get_output_format, output_format, void)
 MOCK_ABORT_INT(hash_local_file, char const *uri, unsigned char *result,
     unsigned int *result_len)
 __MOCK_ABORT(config_get_local_repository, char const *, "tmp/vrps", void)
+MOCK_UINT(config_get_max_aspa_providers, 10, void)
 
 /* Test functions */
 
index bff211162f8a41fb1bcdccda1f4018f400164782..9ddcc1e98d5148f06b58579eeed89a166ca3f9c2 100644 (file)
@@ -25,6 +25,7 @@ MOCK_INT(slurm_apply, 0, struct db_table *base, struct db_slurm **slurm)
 MOCK_ABORT_VOID(db_slurm_destroy, struct db_slurm *db)
 MOCK_VOID(output_print_data, struct db_table const *db)
 __MOCK_ABORT(config_get_local_repository, char const *, "tmp/pdu", void)
+MOCK_UINT(config_get_max_aspa_providers, 10, void)
 
 /* Mocks end */