updated config tests; updated rpki config

This commit is contained in:
Annika Hannig 2023-11-23 15:17:51 +01:00
parent ad8a55815c
commit fd0700ed6f
No known key found for this signature in database
GPG Key ID: 62E226E47DDCE58D
4 changed files with 100 additions and 88 deletions

View File

@ -126,11 +126,11 @@ type RejectCandidatesConfig struct {
// validation state.
type RpkiConfig struct {
// Define communities
Enabled bool `ini:"enabled"`
Valid []string `ini:"valid"`
Unknown []string `ini:"unknown"`
NotChecked []string `ini:"not_checked"`
Invalid []string `ini:"invalid"`
Enabled bool `ini:"enabled"`
Valid [][]string `ini:"valid"`
Unknown [][]string `ini:"unknown"`
NotChecked [][]string `ini:"not_checked"`
Invalid [][]string `ini:"invalid"`
}
// UIConfig holds runtime settings for the web client
@ -486,70 +486,68 @@ func getRpkiConfig(config *ini.File) (RpkiConfig, error) {
// Defaults taken from:
// https://www.euro-ix.net/en/forixps/large-bgp-communities/
section := config.Section("rpki")
lines := strings.Split(section.Body(), "\n")
for _, line := range lines {
l := strings.TrimSpace(line)
if !strings.Contains(l, "=") {
continue
}
parts := strings.SplitN(l, "=", 2)
if len(parts) != 2 {
return rpki, fmt.Errorf("invalid rpki config line: %s", line)
}
key := strings.TrimSpace(parts[0])
value := strings.Split(strings.TrimSpace(parts[1]), ":")
if key == "enabled" {
rpki.Enabled = parts[1] == "true"
} else if key == "valid" {
rpki.Valid = append(rpki.Valid, value)
} else if key == "not_checked" {
rpki.NotChecked = append(rpki.NotChecked, value)
} else if key == "invalid" {
rpki.Invalid = append(rpki.Invalid, value)
} else if key == "unknown" {
rpki.Unknown = append(rpki.Unknown, value)
} else {
return rpki, fmt.Errorf("invalid rpki config line: %s", line)
}
}
if err := section.MapTo(&rpki); err != nil {
return rpki, err
}
fallbackAsn, err := getOwnASN(config)
if err != nil {
log.Println(
"Own ASN is not configured.",
"This might lead to unexpected behaviour with BGP large communities",
)
}
ownAsn := fmt.Sprintf("%d", fallbackAsn)
// Fill in defaults or postprocess config value
if len(rpki.Valid) == 0 {
rpki.Valid = []string{ownAsn, "1000", "1"}
} else {
rpki.Valid = strings.SplitN(rpki.Valid[0], ":", 3)
rpki.Valid = [][]string{{"*", "1000", "1"}}
}
if len(rpki.Unknown) == 0 {
rpki.Unknown = []string{ownAsn, "1000", "2"}
} else {
rpki.Unknown = strings.SplitN(rpki.Unknown[0], ":", 3)
rpki.Unknown = [][]string{{"*", "1000", "2"}}
}
if len(rpki.NotChecked) == 0 {
rpki.NotChecked = []string{ownAsn, "1000", "3"}
} else {
rpki.NotChecked = strings.SplitN(rpki.NotChecked[0], ":", 3)
rpki.NotChecked = [][]string{{"*", "1000", "3"}}
}
// As the euro-ix document states, this can be a range.
if len(rpki.Invalid) == 0 {
rpki.Invalid = []string{ownAsn, "1000", "4", "*"}
} else {
// Preprocess
rpki.Invalid = strings.SplitN(rpki.Invalid[0], ":", 3)
if len(rpki.Invalid) != 3 {
// This is wrong, we should have three parts (RS):1000:[range]
return rpki, fmt.Errorf(
"unexpected rpki.Invalid configuration: %v", rpki.Invalid)
for i, com := range rpki.Invalid {
if len(com) != 3 {
return rpki, fmt.Errorf("Invalid RPKI invalid config: %v", com)
}
tokens := strings.Split(rpki.Invalid[2], "-")
rpki.Invalid = append([]string{rpki.Invalid[0], rpki.Invalid[1]}, tokens...)
tokens := strings.Split(com[2], "-")
rpki.Invalid[i] = append([]string{com[0], com[1]}, tokens...)
}
if len(rpki.Invalid) == 0 {
rpki.Invalid = [][]string{{"*", "1000", "4", "*"}}
}
return rpki, nil
}
// Helper: Get own ASN from ini
// This is now easy, since we enforce an ASN in
// the [server] section.
func getOwnASN(config *ini.File) (int, error) {
server := config.Section("server")
asn := server.Key("asn").MustInt(-1)
if asn == -1 {
return 0, fmt.Errorf("could not get own ASN from config")
}
return asn, nil
}
// Get UI config: Theme settings
func getThemeConfig(config *ini.File) ThemeConfig {
baseConfig := config.Section("theme")
@ -823,18 +821,35 @@ func getSources(config *ini.File) ([]*SourceConfig, error) {
return sources, nil
}
// preprocessConfig parses the variables section of the config
// preprocessConfig parses the variables in the config
// and applies it to the rest of the config.
func preprocessConfig(data []byte) []byte {
lines := bytes.Split(data, []byte("\n"))
config := make([][]byte, 0, len(lines))
expMap := ExpandMap{}
for _, line := range lines {
l := strings.TrimSpace(string(line))
if strings.HasPrefix(l, "$") {
expMap.AddExpr(l[1:])
continue
}
config = append(config, line)
}
return bytes.Join(config, []byte("\n"))
// Now apply to config
configLines := []string{}
for _, line := range config {
l := string(line)
exp, err := expMap.Expand(l)
if err != nil {
log.Fatal("Error expanding expression in config:", l, err)
}
for _, e := range exp {
configLines = append(configLines, e)
}
}
return []byte(strings.Join(configLines, "\n"))
}
// LoadConfig reads a configuration from a file.
@ -860,6 +875,7 @@ func LoadConfig(file string) (*Config, error) {
"blackhole_communities",
"rejection_reasons",
"noexport_reasons",
"rpki",
},
}, configData)
if err != nil {

View File

@ -167,32 +167,21 @@ func TestBlackholeParsing(t *testing.T) {
}
}
func TestOwnASN(t *testing.T) {
config, err := LoadConfig("testdata/alice.conf")
if err != nil {
t.Fatal("Could not load test config:", err)
}
if config.Server.Asn != 9033 {
t.Error("Expected a set server asn")
}
}
func TestRpkiConfig(t *testing.T) {
config, err := LoadConfig("testdata/alice.conf")
if err != nil {
t.Fatal("Could not load test config:", err)
}
if len(config.UI.Rpki.Valid) != 3 {
if len(config.UI.Rpki.Valid[0]) != 3 {
t.Error("Unexpected RPKI:VALID,", config.UI.Rpki.Valid)
}
if len(config.UI.Rpki.Invalid) != 4 {
if len(config.UI.Rpki.Invalid[0]) != 4 {
t.Fatal("Unexpected RPKI:INVALID,", config.UI.Rpki.Invalid)
}
// Check fallback
if config.UI.Rpki.NotChecked[0] != "9033" {
if config.UI.Rpki.NotChecked[0][0] != "*" {
t.Error(
"Expected NotChecked to fall back to defaults, got:",
config.UI.Rpki.NotChecked,
@ -200,7 +189,7 @@ func TestRpkiConfig(t *testing.T) {
}
// Check range postprocessing
if config.UI.Rpki.Invalid[3] != "*" {
if config.UI.Rpki.Invalid[0][3] != "*" {
t.Error("Missing wildcard from config")
}

View File

@ -119,5 +119,4 @@ func TestExpandBgpCommunities(t *testing.T) {
t.Errorf("Expected %d results, got %d", expected, len(exp))
}
t.Log(exp)
}

View File

@ -2,6 +2,13 @@
# Alice-LG configuration example
# ======================================
$ASN01 = 1111
$ASN02 = 2222
$SW1001 = switch01.dc01
$SW1002 = switch02.dc01
$SW2023 = switch23.dc02
[server]
# configures the built-in webserver and provides global application settings
listen_http = 127.0.0.1:7340
@ -9,7 +16,6 @@ listen_http = 127.0.0.1:7340
enable_prefix_lookup = true
# Try to refresh the neighbor status on every request to /neighbors
enable_neighbors_status_refresh = false
asn = 9033
# this ASN is used as a fallback value in the RPKI feature and for route
# filtering evaluation with large BGP communities
@ -55,16 +61,16 @@ routes_not_exported_page_size = 250
[rejection_reasons]
# a pair of a large BGP community value and a string to signal the processing
# results of route filtering
9033:65666:1 = An IP Bogon was detected
9033:65666:2 = Prefix is longer than 64
9033:65666:3 = Prefix is longer than 24
9033:65666:4 = AS path contains a bogon AS
9033:65666:5 = AS path length is longer than 64
9033:65666:6 = First AS in path is not the same as the Peer AS
9033:65666:7 = ECIX prefix hijack
9033:65666:8 = Origin AS not found in IRRDB for Peer AS-SET
9033:65666:9 = Prefix not found in IRRDB for Origin AS
9033:65666:10 = Advertised nexthop address is not the same as the peer
{{ASN*}}:65666:1 = An IP Bogon was detected
{{ASN*}}:65666:2 = Prefix is longer than 64
{{ASN*}}:65666:3 = Prefix is longer than 24
{{ASN*}}:65666:4 = AS path contains a bogon AS
{{ASN*}}:65666:5 = AS path length is longer than 64
{{ASN*}}:65666:6 = First AS in path is not the same as the Peer AS
{{ASN*}}:65666:7 = ECIX prefix hijack
{{ASN*}}:65666:8 = Origin AS not found in IRRDB for Peer AS-SET
{{ASN*}}:65666:9 = Prefix not found in IRRDB for Origin AS
{{ASN*}}:65666:10 = Advertised nexthop address is not the same as the peer
23:42:1 = Some made up reason
@ -80,13 +86,13 @@ load_on_demand = true # Default: false
[noexport_reasons]
# a pair of a large BGP community value and a string to signal the processing
# results of route distribution and the distribution policy applied to a route
9033:65667:1 = The target peer policy is Fairly-open and the sender ASN is an exception
9033:65667:2 = The target peer policy is Selective and the sender ASN is no exception
9033:65667:3 = The target peer policy is set to restrictive
9033:65667:4 = The sender has specifically refused export to the target peer, either through sending 65000:AS, or through the portal
9033:65667:5 = The sender has refused export to all peers and the target is no exception, either through sending 65000:0, or through the portal
9033:65667:6 = The Sender has set (peerRTTHigherDeny:ms) and the targets RTT ms >= then the ms in the community
9033:65667:7 = The Sender has set (peerRTTLowerDeny:ms) and the targets RTT ms <= then the ms in the community
{{ASN*}}:65667:1 = The target peer policy is Fairly-open and the sender ASN is an exception
{{ASN*}}:65667:2 = The target peer policy is Selective and the sender ASN is no exception
{{ASN*}}:65667:3 = The target peer policy is set to restrictive
{{ASN*}}:65667:4 = The sender has specifically refused export to the target peer, either through sending 65000:AS, or through the portal
{{ASN*}}:65667:5 = The sender has refused export to all peers and the target is no exception, either through sending 65000:0, or through the portal
{{ASN*}}:65667:6 = The Sender has set (peerRTTHigherDeny:ms) and the targets RTT ms >= then the ms in the community
{{ASN*}}:65667:7 = The Sender has set (peerRTTLowerDeny:ms) and the targets RTT ms <= then the ms in the community
23:46:1 = Some other made up reason
@ -102,10 +108,10 @@ enabled = true
# Optional, falling back to defaults as defined in:
# https://www.euro-ix.net/en/forixps/large-bgp-communities/
valid = 23042:1000:1
unknown = 23042:1000:2
valid = {{ASN*}}:1000:1
unknown = {{ASN*}}:1000:2
# not_checked = 23042:1000:3
invalid = 23042:1000:4-*
invalid = {{ASN*}}:1000:4-*
# Define other known bgp communities
@ -115,6 +121,8 @@ invalid = 23042:1000:4-*
# Wildcards are supported aswell:
0:* = do not redistribute to AS$1
{{ASN*}}:911:{SW*} = Redistribute to {{SW*}}
#
# Define columns for neighbours and routes table,
# with <key> = <Table Header>