Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
385775de04 |
@@ -88,9 +88,13 @@ one of its peers sends an update.
|
||||
old.
|
||||
|
||||
- `GET /bogons` - The bogon announcements (HTML): the routes whose prefix or
|
||||
origin AS is reserved. A prefix is reserved when it lies inside a block that
|
||||
the IANA special-purpose address registries mark as not globally reachable. A
|
||||
reserved AS number is one of these:
|
||||
origin AS is reserved. A prefix is reserved when it lies inside one of these:
|
||||
- a block that the IANA special-purpose address registries mark as not
|
||||
globally reachable
|
||||
- the multicast space, `224.0.0.0/4` and `ff00::/8`, which the IANA IPv4 and
|
||||
IPv6 address space registries list as Multicast
|
||||
|
||||
A reserved AS number is one of these:
|
||||
- an AS number for private use or for documentation
|
||||
- `AS23456`
|
||||
- the last AS number of the 16-bit or the 32-bit range
|
||||
|
||||
+25
-14
@@ -3,9 +3,10 @@
|
||||
// internet. A route is a bogon announcement when its prefix is reserved or its
|
||||
// origin AS is.
|
||||
//
|
||||
// The reserved prefixes come from the IANA special-purpose address registries
|
||||
// for IPv4 and IPv6. The reserved AS numbers come from the IANA special-purpose
|
||||
// AS numbers registry:
|
||||
// Most reserved prefixes come from the IANA special-purpose address registries
|
||||
// for IPv4 and IPv6. The two multicast blocks, 224.0.0.0/4 and ff00::/8, come
|
||||
// from the IANA IPv4 and IPv6 address space registries. The reserved AS
|
||||
// numbers come from the IANA special-purpose AS numbers registry:
|
||||
// - the AS numbers for private use
|
||||
// - the AS numbers for documentation
|
||||
// - AS 23456, which stands in for a 32-bit AS number
|
||||
@@ -27,10 +28,10 @@ import (
|
||||
func Prefix(prefix netip.Prefix) (string, bool) {
|
||||
var holder *block
|
||||
|
||||
for i, b := range specialPurposeBlocks {
|
||||
for i, b := range registryBlocks {
|
||||
inside := b.prefix.Bits() <= prefix.Bits() && b.prefix.Contains(prefix.Addr())
|
||||
if inside && (holder == nil || b.prefix.Bits() > holder.prefix.Bits()) {
|
||||
holder = &specialPurposeBlocks[i]
|
||||
holder = ®istryBlocks[i]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,35 +73,43 @@ const (
|
||||
amt = "AMT"
|
||||
as112DirectDelegation = "Direct Delegation AS112 Service"
|
||||
ipv4IPv6Translation = "IPv4-IPv6 Translat."
|
||||
multicast = "Multicast"
|
||||
)
|
||||
|
||||
// block is one row of an IANA special-purpose address registry.
|
||||
// block is one row of an IANA address registry.
|
||||
type block struct {
|
||||
prefix netip.Prefix
|
||||
name string
|
||||
// reserved says that the row's Globally Reachable column is False.
|
||||
// reserved says that no network should announce the row's addresses on
|
||||
// the internet.
|
||||
reserved bool
|
||||
}
|
||||
|
||||
// reservedBlock returns a row whose Globally Reachable column is False.
|
||||
// reservedBlock returns a reserved row: a multicast block, or a special-purpose
|
||||
// row whose Globally Reachable column is False.
|
||||
func reservedBlock(prefix, name string) block {
|
||||
return block{prefix: netip.MustParsePrefix(prefix), name: name, reserved: true}
|
||||
}
|
||||
|
||||
// reachableBlock returns a row whose Globally Reachable column is True or N/A.
|
||||
// Such a row matters only inside a reserved block, whose addresses it lets be
|
||||
// announced.
|
||||
// reachableBlock returns a special-purpose row whose Globally Reachable column
|
||||
// is True or N/A. Such a row matters only inside a reserved block, whose
|
||||
// addresses it lets be announced.
|
||||
func reachableBlock(prefix, name string) block {
|
||||
return block{prefix: netip.MustParsePrefix(prefix), name: name}
|
||||
}
|
||||
|
||||
// specialPurposeBlocks are the rows of the IANA special-purpose address
|
||||
// registries, without the deprecated ones:
|
||||
// registryBlocks are the rows of the IANA special-purpose address registries,
|
||||
// without the deprecated ones:
|
||||
// - https://www.iana.org/assignments/iana-ipv4-special-registry/
|
||||
// - https://www.iana.org/assignments/iana-ipv6-special-registry/
|
||||
//
|
||||
// They also hold the multicast blocks, which the IANA address space registries
|
||||
// list as Multicast:
|
||||
// - https://www.iana.org/assignments/ipv4-address-space/
|
||||
// - https://www.iana.org/assignments/ipv6-address-space/
|
||||
//
|
||||
//nolint:gochecknoglobals // a fixed list, parsed once
|
||||
var specialPurposeBlocks = []block{
|
||||
var registryBlocks = []block{
|
||||
reservedBlock("0.0.0.0/8", "This network"),
|
||||
reservedBlock("0.0.0.0/32", "This host on this network"),
|
||||
reservedBlock("10.0.0.0/8", privateUse),
|
||||
@@ -124,6 +133,7 @@ var specialPurposeBlocks = []block{
|
||||
reservedBlock("198.18.0.0/15", benchmarking),
|
||||
reservedBlock("198.51.100.0/24", "Documentation (TEST-NET-2)"),
|
||||
reservedBlock("203.0.113.0/24", "Documentation (TEST-NET-3)"),
|
||||
reservedBlock("224.0.0.0/4", multicast),
|
||||
reservedBlock("240.0.0.0/4", "Reserved"),
|
||||
reservedBlock("255.255.255.255/32", "Limited Broadcast"),
|
||||
|
||||
@@ -151,6 +161,7 @@ var specialPurposeBlocks = []block{
|
||||
reservedBlock("5f00::/16", "Segment Routing (SRv6) SIDs"),
|
||||
reservedBlock("fc00::/7", "Unique-Local"),
|
||||
reservedBlock("fe80::/10", "Link-Local Unicast"),
|
||||
reservedBlock("ff00::/8", multicast),
|
||||
}
|
||||
|
||||
// asRange is a range of reserved AS numbers, first to last.
|
||||
|
||||
@@ -21,6 +21,11 @@ func TestPrefix(t *testing.T) {
|
||||
{"192.0.2.0/24", "Documentation (TEST-NET-1) (192.0.2.0/24)"},
|
||||
{"2001:db8:1::/48", "Documentation (2001:db8::/32)"},
|
||||
{"fd00::/8", "Unique-Local (fc00::/7)"},
|
||||
// Multicast space, from the IANA address space registries.
|
||||
{"224.0.0.0/4", "Multicast (224.0.0.0/4)"},
|
||||
{"239.255.0.0/16", "Multicast (224.0.0.0/4)"},
|
||||
{"ff00::/8", "Multicast (ff00::/8)"},
|
||||
{"ff02::/16", "Multicast (ff00::/8)"},
|
||||
// The most specific block names the reason.
|
||||
{"0.0.0.0/32", "This host on this network (0.0.0.0/32)"},
|
||||
{"2001:2::/48", "Benchmarking (2001:2::/48)"},
|
||||
|
||||
@@ -2,6 +2,7 @@ package routetable
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -72,3 +73,61 @@ func TestWalkPrefixesVisitsEveryPrefix(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestWalkPrefixesLetsUpdatesIn starts an update during the walk's first
|
||||
// batch. The update must have been made by the time the walk visits the first
|
||||
// prefix of its second batch, because the walk lets the lock go in between.
|
||||
func TestWalkPrefixesLetsUpdatesIn(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
asn = 1000
|
||||
peer = "192.0.2.1"
|
||||
)
|
||||
|
||||
routeTime := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
|
||||
table := New(Params{})
|
||||
addr := netip.MustParseAddr("1.0.0.0")
|
||||
|
||||
for range walkBatch + 1 {
|
||||
prefix := netip.PrefixFrom(addr, addr.BitLen())
|
||||
table.Announce(prefix, asn, Route{Peer: peer, Time: routeTime})
|
||||
|
||||
addr = addr.Next()
|
||||
}
|
||||
|
||||
updatePrefix := netip.MustParsePrefix("2.0.0.0/8")
|
||||
updateDone := make(chan struct{})
|
||||
visited := 0
|
||||
madeBeforeSecondBatch := false
|
||||
|
||||
table.walkPrefixes(func(netip.Prefix, []*origin) {
|
||||
visited++
|
||||
|
||||
switch visited {
|
||||
case 1:
|
||||
go func() {
|
||||
defer close(updateDone)
|
||||
|
||||
table.Announce(updatePrefix, asn, Route{Peer: peer, Time: routeTime})
|
||||
}()
|
||||
|
||||
// Wait until the update waits for the lock. TryRLock fails
|
||||
// once a writer waits.
|
||||
for table.mu.TryRLock() {
|
||||
table.mu.RUnlock()
|
||||
runtime.Gosched()
|
||||
}
|
||||
case walkBatch + 1:
|
||||
// The walk holds the read lock, so the table can be read.
|
||||
madeBeforeSecondBatch = table.origins(updatePrefix) != nil
|
||||
}
|
||||
})
|
||||
|
||||
<-updateDone
|
||||
|
||||
if !madeBeforeSecondBatch {
|
||||
t.Fatal("an update started during the walk's first batch was not made " +
|
||||
"before its second batch")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func TestListPagesListTheirEntries(t *testing.T) {
|
||||
},
|
||||
multipleOriginsPath: {
|
||||
"Prefixes announced by more than one origin AS: 1.", "1.0.0.0/24",
|
||||
asLink(twoPrefixASN), asLink(secondOrigin),
|
||||
asLink(twoPrefixASN), asLink(secondOrigin), ">1 peer<",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -315,6 +315,32 @@ func TestKeepHomeCardsFreshWorksThemOutEveryInterval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStartedServerWorksOutTheCards starts a server and waits until its home
|
||||
// page shows the cards.
|
||||
func TestStartedServerWorksOutTheCards(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const maxWait = 5 * time.Second
|
||||
|
||||
s := newServerWithTable(t, newCardsTable())
|
||||
|
||||
err := s.Start(t.Context())
|
||||
if err != nil {
|
||||
t.Fatalf("Start: %v", err)
|
||||
}
|
||||
|
||||
defer func() { _ = s.Stop(context.Background()) }()
|
||||
|
||||
waitUntil(t, maxWait, func() bool {
|
||||
return !strings.Contains(get(t, s, "/").Body.String(), cardsNotReadyText)
|
||||
})
|
||||
|
||||
card := homeCard(t, get(t, s, "/").Body.String(), "Newest Updated Route")
|
||||
if !strings.Contains(card, "8.8.8.0/24") {
|
||||
t.Errorf("the newest route is not the table's: %s", card)
|
||||
}
|
||||
}
|
||||
|
||||
// waitUntil fails the test unless done reports true within maxWait.
|
||||
func waitUntil(t *testing.T, maxWait time.Duration, done func() bool) {
|
||||
t.Helper()
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
<td>
|
||||
<ul class="origins">
|
||||
{{ range .Origins }}
|
||||
<li>{{ if .ASN }}<a href="/as/{{ .ASN }}">AS{{ .ASN }}</a>{{ else }}No known origin{{ end }} <span class="peers">{{ .Peers }} peers</span></li>
|
||||
<li>{{ if .ASN }}<a href="/as/{{ .ASN }}">AS{{ .ASN }}</a>{{ else }}No known origin{{ end }} <span class="peers">{{ .Peers }} {{ if eq .Peers 1 }}peer{{ else }}peers{{ end }}</span></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user