Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c90af9a873 |
No files matched your search
@@ -88,13 +88,9 @@ one of its peers sends an update.
|
|||||||
old.
|
old.
|
||||||
|
|
||||||
- `GET /bogons` - The bogon announcements (HTML): the routes whose prefix or
|
- `GET /bogons` - The bogon announcements (HTML): the routes whose prefix or
|
||||||
origin AS is reserved. A prefix is reserved when it lies inside one of these:
|
origin AS is reserved. A prefix is reserved when it lies inside a block that
|
||||||
- a block that the IANA special-purpose address registries mark as not
|
the IANA special-purpose address registries mark as not globally reachable. A
|
||||||
globally reachable
|
reserved AS number is one of these:
|
||||||
- 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
|
- an AS number for private use or for documentation
|
||||||
- `AS23456`
|
- `AS23456`
|
||||||
- the last AS number of the 16-bit or the 32-bit range
|
- the last AS number of the 16-bit or the 32-bit range
|
||||||
|
|||||||
+14
-25
@@ -3,10 +3,9 @@
|
|||||||
// internet. A route is a bogon announcement when its prefix is reserved or its
|
// internet. A route is a bogon announcement when its prefix is reserved or its
|
||||||
// origin AS is.
|
// origin AS is.
|
||||||
//
|
//
|
||||||
// Most reserved prefixes come from the IANA special-purpose address registries
|
// The 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
|
// for IPv4 and IPv6. The reserved AS numbers come from the IANA special-purpose
|
||||||
// from the IANA IPv4 and IPv6 address space registries. The reserved AS
|
// AS numbers registry:
|
||||||
// numbers come from the IANA special-purpose AS numbers registry:
|
|
||||||
// - the AS numbers for private use
|
// - the AS numbers for private use
|
||||||
// - the AS numbers for documentation
|
// - the AS numbers for documentation
|
||||||
// - AS 23456, which stands in for a 32-bit AS number
|
// - AS 23456, which stands in for a 32-bit AS number
|
||||||
@@ -28,10 +27,10 @@ import (
|
|||||||
func Prefix(prefix netip.Prefix) (string, bool) {
|
func Prefix(prefix netip.Prefix) (string, bool) {
|
||||||
var holder *block
|
var holder *block
|
||||||
|
|
||||||
for i, b := range registryBlocks {
|
for i, b := range specialPurposeBlocks {
|
||||||
inside := b.prefix.Bits() <= prefix.Bits() && b.prefix.Contains(prefix.Addr())
|
inside := b.prefix.Bits() <= prefix.Bits() && b.prefix.Contains(prefix.Addr())
|
||||||
if inside && (holder == nil || b.prefix.Bits() > holder.prefix.Bits()) {
|
if inside && (holder == nil || b.prefix.Bits() > holder.prefix.Bits()) {
|
||||||
holder = ®istryBlocks[i]
|
holder = &specialPurposeBlocks[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,43 +72,35 @@ const (
|
|||||||
amt = "AMT"
|
amt = "AMT"
|
||||||
as112DirectDelegation = "Direct Delegation AS112 Service"
|
as112DirectDelegation = "Direct Delegation AS112 Service"
|
||||||
ipv4IPv6Translation = "IPv4-IPv6 Translat."
|
ipv4IPv6Translation = "IPv4-IPv6 Translat."
|
||||||
multicast = "Multicast"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// block is one row of an IANA address registry.
|
// block is one row of an IANA special-purpose address registry.
|
||||||
type block struct {
|
type block struct {
|
||||||
prefix netip.Prefix
|
prefix netip.Prefix
|
||||||
name string
|
name string
|
||||||
// reserved says that no network should announce the row's addresses on
|
// reserved says that the row's Globally Reachable column is False.
|
||||||
// the internet.
|
|
||||||
reserved bool
|
reserved bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// reservedBlock returns a reserved row: a multicast block, or a special-purpose
|
// reservedBlock returns a row whose Globally Reachable column is False.
|
||||||
// row whose Globally Reachable column is False.
|
|
||||||
func reservedBlock(prefix, name string) block {
|
func reservedBlock(prefix, name string) block {
|
||||||
return block{prefix: netip.MustParsePrefix(prefix), name: name, reserved: true}
|
return block{prefix: netip.MustParsePrefix(prefix), name: name, reserved: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reachableBlock returns a special-purpose row whose Globally Reachable column
|
// reachableBlock returns a row whose Globally Reachable column is True or N/A.
|
||||||
// is True or N/A. Such a row matters only inside a reserved block, whose
|
// Such a row matters only inside a reserved block, whose addresses it lets be
|
||||||
// addresses it lets be announced.
|
// announced.
|
||||||
func reachableBlock(prefix, name string) block {
|
func reachableBlock(prefix, name string) block {
|
||||||
return block{prefix: netip.MustParsePrefix(prefix), name: name}
|
return block{prefix: netip.MustParsePrefix(prefix), name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
// registryBlocks are the rows of the IANA special-purpose address registries,
|
// specialPurposeBlocks are the rows of the IANA special-purpose address
|
||||||
// without the deprecated ones:
|
// registries, without the deprecated ones:
|
||||||
// - https://www.iana.org/assignments/iana-ipv4-special-registry/
|
// - https://www.iana.org/assignments/iana-ipv4-special-registry/
|
||||||
// - https://www.iana.org/assignments/iana-ipv6-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
|
//nolint:gochecknoglobals // a fixed list, parsed once
|
||||||
var registryBlocks = []block{
|
var specialPurposeBlocks = []block{
|
||||||
reservedBlock("0.0.0.0/8", "This network"),
|
reservedBlock("0.0.0.0/8", "This network"),
|
||||||
reservedBlock("0.0.0.0/32", "This host on this network"),
|
reservedBlock("0.0.0.0/32", "This host on this network"),
|
||||||
reservedBlock("10.0.0.0/8", privateUse),
|
reservedBlock("10.0.0.0/8", privateUse),
|
||||||
@@ -133,7 +124,6 @@ var registryBlocks = []block{
|
|||||||
reservedBlock("198.18.0.0/15", benchmarking),
|
reservedBlock("198.18.0.0/15", benchmarking),
|
||||||
reservedBlock("198.51.100.0/24", "Documentation (TEST-NET-2)"),
|
reservedBlock("198.51.100.0/24", "Documentation (TEST-NET-2)"),
|
||||||
reservedBlock("203.0.113.0/24", "Documentation (TEST-NET-3)"),
|
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("240.0.0.0/4", "Reserved"),
|
||||||
reservedBlock("255.255.255.255/32", "Limited Broadcast"),
|
reservedBlock("255.255.255.255/32", "Limited Broadcast"),
|
||||||
|
|
||||||
@@ -161,7 +151,6 @@ var registryBlocks = []block{
|
|||||||
reservedBlock("5f00::/16", "Segment Routing (SRv6) SIDs"),
|
reservedBlock("5f00::/16", "Segment Routing (SRv6) SIDs"),
|
||||||
reservedBlock("fc00::/7", "Unique-Local"),
|
reservedBlock("fc00::/7", "Unique-Local"),
|
||||||
reservedBlock("fe80::/10", "Link-Local Unicast"),
|
reservedBlock("fe80::/10", "Link-Local Unicast"),
|
||||||
reservedBlock("ff00::/8", multicast),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// asRange is a range of reserved AS numbers, first to last.
|
// asRange is a range of reserved AS numbers, first to last.
|
||||||
|
|||||||
@@ -21,11 +21,6 @@ func TestPrefix(t *testing.T) {
|
|||||||
{"192.0.2.0/24", "Documentation (TEST-NET-1) (192.0.2.0/24)"},
|
{"192.0.2.0/24", "Documentation (TEST-NET-1) (192.0.2.0/24)"},
|
||||||
{"2001:db8:1::/48", "Documentation (2001:db8::/32)"},
|
{"2001:db8:1::/48", "Documentation (2001:db8::/32)"},
|
||||||
{"fd00::/8", "Unique-Local (fc00::/7)"},
|
{"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.
|
// The most specific block names the reason.
|
||||||
{"0.0.0.0/32", "This host on this network (0.0.0.0/32)"},
|
{"0.0.0.0/32", "This host on this network (0.0.0.0/32)"},
|
||||||
{"2001:2::/48", "Benchmarking (2001:2::/48)"},
|
{"2001:2::/48", "Benchmarking (2001:2::/48)"},
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package routetable
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"runtime"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -73,61 +72,3 @@ 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: {
|
multipleOriginsPath: {
|
||||||
"Prefixes announced by more than one origin AS: 1.", "1.0.0.0/24",
|
"Prefixes announced by more than one origin AS: 1.", "1.0.0.0/24",
|
||||||
asLink(twoPrefixASN), asLink(secondOrigin), ">1 peer<",
|
asLink(twoPrefixASN), asLink(secondOrigin),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,32 +315,6 @@ 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.
|
// waitUntil fails the test unless done reports true within maxWait.
|
||||||
func waitUntil(t *testing.T, maxWait time.Duration, done func() bool) {
|
func waitUntil(t *testing.T, maxWait time.Duration, done func() bool) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|||||||
@@ -166,7 +166,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<ul class="origins">
|
<ul class="origins">
|
||||||
{{ range .Origins }}
|
{{ range .Origins }}
|
||||||
<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>
|
<li>{{ if .ASN }}<a href="/as/{{ .ASN }}">AS{{ .ASN }}</a>{{ else }}No known origin{{ end }} <span class="peers">{{ .Peers }} peers</span></li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Reference in new issue
Block a user