Skip to content

Commit

Permalink
RIPE NCC has merged 526db5cfe
Browse files Browse the repository at this point in the history
* Update dependency io.sentry:sentry-bom to v7.16.0 [99c33413a]
* Update dependency org.wiremock:wiremock-jetty12 to v3.9.2 [106643885]
* Update plugin com.google.cloud.tools.jib to v3.4.4 [4b7ba7a40]
* Cleanup imports [50bc49d7b]
* Cleanup [ee15397bb]
* Remove confusing comment [e9820a69e]
* Simplify [299aa2889]
* Remove unused code [751add2e0]
* Cleanup [5c533d512]
* Fix affected announcements that shouldn't be affected [8359f0e37]
* Update node Docker tag to v23 [476fa11fd]
  • Loading branch information
RPKI Team at RIPE NCC committed Oct 30, 2024
1 parent 17e05b0 commit d03dc7e
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 115 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ sonarqube:
- if: $CI_COMMIT_BRANCH == "next"

control/run-on-staging:
image: node:22-alpine
image: node:23-alpine
stage: qa
script:
- ./scripts/gitlab-deploy-check
Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id 'org.springframework.boot' version "3.2.4"
id 'distribution'
id 'jacoco'
id "com.google.cloud.tools.jib" version "3.4.3"
id "com.google.cloud.tools.jib" version "3.4.4"
id "com.google.osdetector" version "1.7.3"
}

Expand Down Expand Up @@ -44,7 +44,7 @@ dependencies {
implementation "org.thymeleaf:thymeleaf:3.1.2.RELEASE"
implementation "org.thymeleaf:thymeleaf-spring6:3.1.2.RELEASE"

implementation platform('io.sentry:sentry-bom:7.15.0')
implementation platform('io.sentry:sentry-bom:7.16.0')
implementation 'io.sentry:sentry-spring-boot-starter'
implementation 'io.sentry:sentry-logback'

Expand Down Expand Up @@ -72,7 +72,7 @@ dependencies {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
}

testImplementation "org.wiremock:wiremock-jetty12:3.9.1"
testImplementation "org.wiremock:wiremock-jetty12:3.9.2"
testImplementation 'net.jqwik:jqwik:1.9.1'
testImplementation "net.ripe.rpki:rpki-commons:$rpki_commons_version:tests"
testImplementation 'org.assertj:assertj-core'
Expand Down
37 changes: 4 additions & 33 deletions src/main/java/net/ripe/rpki/rest/service/AnnouncementService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
import net.ripe.ipresource.IpResource;
import net.ripe.ipresource.ImmutableResourceSet;
import net.ripe.ipresource.etree.NestedIntervalMap;
import net.ripe.rpki.commons.validation.roa.AllowedRoute;
import net.ripe.rpki.commons.validation.roa.AnnouncedRoute;
import net.ripe.rpki.commons.validation.roa.RouteOriginValidationPolicy;
import net.ripe.rpki.commons.validation.roa.RouteValidityState;
import net.ripe.rpki.rest.exception.BadRequestException;
import net.ripe.rpki.rest.pojo.BgpAnnouncement;
import net.ripe.rpki.rest.pojo.ApiRoaPrefix;
Expand All @@ -35,10 +33,8 @@
import org.springframework.web.bind.annotation.RestController;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -160,35 +156,10 @@ public ResponseEntity<List<BgpAnnouncement>> getAffectedAnnouncementsForCaAndRoa
final RoaConfigurationData roaConfiguration = roaViewService.getRoaConfiguration(ca.getId());
final Set<AnnouncedRoute> ignoredAnnouncements = Utils.getIgnoredAnnouncements(roaAlertConfigurationViewService, ca.getId());

final Set<AnnouncedRoute> routesValidatedByOthers = new HashSet<>();
final NestedIntervalMap<IpResource, List<RoaConfigurationPrefixData>> currentRouteMap = allowedRoutesToNestedIntervalMap(roaConfiguration.getPrefixes());
Stream.of(true, false)
.filter(announcements::containsKey)
.flatMap(verifiedOrNot -> announcements.get(verifiedOrNot).stream())
.map(BgpRisEntry::toAnnouncedRoute)
.forEach(announcedRoute -> {
final RouteValidityState currentValidityState = RouteOriginValidationPolicy.validateAnnouncedRoute(currentRouteMap, announcedRoute);
if (currentValidityState == RouteValidityState.VALID &&
!(roaAsn.equals(announcedRoute.getOriginAsn()) && roaPrefix.equals(announcedRoute.getPrefix()))) {
routesValidatedByOthers.add(announcedRoute);
}
});

final List<BgpAnnouncement> bgpAnnouncements = Utils.makeBgpAnnouncementList(announcements, Collections.singletonList(
new AllowedRoute(roaAsn, roaPrefix, roa.getMaxLength())),
ignoredAnnouncements);

final List<BgpAnnouncement> knownAnnouncements = new ArrayList<>();
for (BgpAnnouncement announcement : bgpAnnouncements) {
final AnnouncedRoute announcedRoute = new AnnouncedRoute(Asn.parse(announcement.getAsn()), IpRange.parse(announcement.getPrefix()));
if (announcement.getCurrentState() == RouteValidityState.VALID ||
((announcement.getCurrentState() == RouteValidityState.INVALID_ASN ||
announcement.getCurrentState() == RouteValidityState.INVALID_LENGTH) &&
!routesValidatedByOthers.contains(announcedRoute))) {
knownAnnouncements.add(announcement);
}
}
return ok(knownAnnouncements);
final List<BgpAnnouncement> affectedAnnouncements = Utils.getAffectedAnnouncements(
roaConfiguration, announcements, ignoredAnnouncements, roaAsn, roaPrefix, roa.getMaxLength());

return ok(affectedAnnouncements);
}

public static final String NO_CA_RESOURCES = "no-ca-resources";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import com.google.common.base.Preconditions;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import net.ripe.ipresource.*;
import net.ripe.ipresource.etree.NestedIntervalMap;
import net.ripe.rpki.commons.validation.roa.*;
import net.ripe.rpki.domain.roa.RoaConfigurationRepository;
import net.ripe.rpki.rest.pojo.BgpAnnouncement;
import net.ripe.rpki.rest.pojo.BgpAnnouncementChange;
import net.ripe.rpki.rest.pojo.PublishSet;
Expand Down Expand Up @@ -53,7 +51,6 @@ public class CaRoaConfigurationService extends AbstractCaRestService {

@Autowired
public CaRoaConfigurationService(RoaViewService roaViewService,
RoaConfigurationRepository roaConfigurationRepository,
BgpRisEntryViewService bgpRisEntryViewService,
RoaAlertConfigurationViewService roaAlertConfigurationViewService,
CommandService commandService) {
Expand Down Expand Up @@ -163,10 +160,10 @@ static RouteValidityState determineValidityState(IpRange announcedPrefix, String
@PostMapping(path = "stage")
@Operation(summary = "Stage ROA changes for the given CA")
public ResponseEntity<?> stageRoaChanges(@PathVariable("caName") final CaName caName,
@RequestBody final List<ApiRoaPrefix> futureRoas) {
@RequestBody final List<ApiRoaPrefix> futureRoasPrefixes) {
log.info("REST call: Stage ROAs for CA: {}", caName);

final Optional<String> errorMessage = Utils.errorsInUserInputRoas(futureRoas);
final Optional<String> errorMessage = Utils.errorsInUserInputRoas(futureRoasPrefixes);
if (errorMessage.isPresent()) {
return ResponseEntity.status(BAD_REQUEST).body(of(ERROR, "New ROAs are not correct: " + errorMessage.get()));
}
Expand All @@ -177,80 +174,71 @@ public ResponseEntity<?> stageRoaChanges(@PathVariable("caName") final CaName ca
final Map<Boolean, Collection<BgpRisEntry>> bgpAnnouncements = bgpRisEntryViewService.findMostSpecificContainedAndNotContained(certifiedResources);
final RoaConfigurationData currentRoaConfiguration = roaViewService.getRoaConfiguration(ca.getId());

final Set<RoaConfigurationPrefixData> currentRoutes = new HashSet<>(currentRoaConfiguration.getPrefixes());
final Set<RoaConfigurationPrefixData> currentRoas = new HashSet<>(currentRoaConfiguration.getPrefixes());

// MAY throw, but IllegalArgumentExceptions are translated to HTTP 500 through @ControllerAdvice
List<AllowedRoute> futureRoas = futureRoasPrefixes.stream()
.map(r -> new AllowedRoute(Asn.parse(r.getAsn()), IpRange.parse(r.getPrefix()), r.getMaxLength()))
.toList();

var effectOfFutureRoas = buildAffectedRanges(futureRoas, currentRoutes.stream().map(RoaPrefixData::toAllowedRoute).collect(Collectors.toSet()));
var affectedRanges = buildAffectedRanges(
futureRoas,
currentRoas.stream()
.map(RoaPrefixData::toAllowedRoute)
.collect(Collectors.toSet()));

Optional<String> validationError = Roas.validateRoaUpdate(effectOfFutureRoas.futureRoutes);
Optional<String> validationError = Roas.validateRoaUpdate(futureRoas);
if (validationError.isPresent()) {
return ResponseEntity.status(BAD_REQUEST).body(of(ERROR, validationError.get()));
}

final List<BgpAnnouncementChange> bgpAnnouncementChanges = getBgpAnnouncementChanges(
roaAlertConfigurationViewService,
ca, currentRoutes, effectOfFutureRoas.futureRoutes, bgpAnnouncements, effectOfFutureRoas.affectedRanges);
currentRoas, futureRoas, bgpAnnouncements, affectedRanges,
getIgnoredAnnouncement(roaAlertConfigurationViewService, ca.getId()));

return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.eTag(currentRoaConfiguration.entityTag())
.body(bgpAnnouncementChanges);
}

/**
* Gather the set of resources span by the <code>futureRoas</code> and add an AllowedRoute to futureRoutes for all
* ROAs in <code>futureRoas</code> that are not in <code>currentRoutes</code>.
*/
private static AffectedRangesForVRPs buildAffectedRanges(List<ApiRoaPrefix> futureRoas, Set<AllowedRoute> currentRoutes) {
var affectedRanges = new IpResourceSet();

static Set<IpRange> buildAffectedRanges(List<AllowedRoute> futureRoas, Set<AllowedRoute> currentRoas) {
var affectedRanges = new HashSet<IpRange>();
var futureRoutes = new HashSet<AllowedRoute>();

for (ApiRoaPrefix roa : futureRoas) {
final IpRange roaIpRange = IpRange.parse(roa.getPrefix());
final AllowedRoute route = new AllowedRoute(Asn.parse(roa.getAsn()), roaIpRange, roa.getMaxLength());
futureRoutes.add(route);
if (!currentRoutes.contains(route))
affectedRanges.add(roaIpRange);
for (var roa : futureRoas) {
futureRoutes.add(roa);
if (!currentRoas.contains(roa))
affectedRanges.add(roa.getPrefix());
}
for (var route : currentRoutes) {
if (!futureRoutes.contains(route))
affectedRanges.add(route.getPrefix());
for (var roa : currentRoas) {
if (!futureRoutes.contains(roa))
affectedRanges.add(roa.getPrefix());
}

return new AffectedRangesForVRPs(affectedRanges, futureRoutes);
return affectedRanges;
}

@Value
private static class AffectedRangesForVRPs {
private final IpResourceSet affectedRanges;
private final Set<AllowedRoute> futureRoutes;
}
static <T extends RoaPrefixData> List<BgpAnnouncementChange> getBgpAnnouncementChanges(
Collection<T> currentRoutes,
Collection<AllowedRoute> futureRoutes,
Map<Boolean, Collection<BgpRisEntry>> bgpAnnouncements,
Set<IpRange> affectedRanges,
Set<AnnouncedRoute> ignoredAnnouncements) {

private static <T extends RoaPrefixData> List<BgpAnnouncementChange> getBgpAnnouncementChanges(
RoaAlertConfigurationViewService service,
HostedCertificateAuthorityData ca,
Set<T> currentRoutes,
Set<AllowedRoute> futureRoutes,
Map<Boolean, Collection<BgpRisEntry>> bgpAnnouncements,
IpResourceSet affectedRanges) {
final NestedIntervalMap<IpResource, List<T>> currentRouteMap = allowedRoutesToNestedIntervalMap(currentRoutes);
final NestedIntervalMap<IpResource, List<AllowedRoute>> futureRouteMap = allowedRoutesToNestedIntervalMap(futureRoutes);
final Set<AnnouncedRoute> ignoredAnnouncements = getIgnoredAnnouncement(service, ca.getId());

final List<BgpAnnouncementChange> result = new ArrayList<>();
for (Boolean verifiedOrNot : new Boolean[]{true, false}) {
if (bgpAnnouncements.containsKey(verifiedOrNot)) {
for (BgpRisEntry bgp : bgpAnnouncements.get(verifiedOrNot)) {
final AnnouncedRoute announcedRoute = bgp.toAnnouncedRoute();
final RouteValidityState currentValidityState = RouteOriginValidationPolicy.validateAnnouncedRoute(currentRouteMap, announcedRoute);
final RouteValidityState futureValidityState = RouteOriginValidationPolicy.validateAnnouncedRoute(futureRouteMap, announcedRoute);
final boolean isSuppressed = ignoredAnnouncements.contains(announcedRoute);
result.add(new BgpAnnouncementChange(bgp.getOrigin().toString(), bgp.getPrefix().toString(),
bgp.getVisibility(), isSuppressed, currentValidityState, futureValidityState,
affectedRanges.contains(bgp.getPrefix()),
verifiedOrNot));
}
for (BgpRisEntry bgp : bgpAnnouncements.getOrDefault(verifiedOrNot, Collections.emptyList())) {
AnnouncedRoute announcedRoute = bgp.toAnnouncedRoute();
RouteValidityState currentValidityState = RouteOriginValidationPolicy.validateAnnouncedRoute(currentRouteMap, announcedRoute);
RouteValidityState futureValidityState = RouteOriginValidationPolicy.validateAnnouncedRoute(futureRouteMap, announcedRoute);
boolean isSuppressed = ignoredAnnouncements.contains(announcedRoute);
boolean affectedByChange = affectedRanges.stream().anyMatch(r -> r.contains(bgp.getPrefix()));
result.add(new BgpAnnouncementChange(bgp.getOrigin().toString(), bgp.getPrefix().toString(),
bgp.getVisibility(), isSuppressed, currentValidityState, futureValidityState,
affectedByChange, verifiedOrNot));
}
}
return result;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/ripe/rpki/rest/service/Roas.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static Set<AllowedRoute> applyDiff(Set<AllowedRoute> currentRoas, RoaDiff
return futureRoas;
}

public static <T extends RoaPrefixData> Optional<String> validateRoaUpdate(Set<T> futureRoutes) {
public static <T extends RoaPrefixData> Optional<String> validateRoaUpdate(Collection<T> futureRoutes) {
var futureMap = futureRoutes.stream().collect(Collectors.toMap(
r -> new AnnouncedRoute(r.getAsn(), r.getPrefix()),
r -> Collections.singletonList(r.getMaximumLength()),
Expand Down
Loading

0 comments on commit d03dc7e

Please sign in to comment.