From 328dbd086502924eca2b9df551ec49e1f6013dd5 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Fri, 25 Nov 2016 14:22:22 +0100 Subject: [PATCH 01/35] fixed regex, added as_path splitting --- bird/parser.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bird/parser.go b/bird/parser.go index 908f8a1..8a8dbdd 100644 --- a/bird/parser.go +++ b/bird/parser.go @@ -127,7 +127,7 @@ func parseRoutes(input []byte) Parsed { routes := []Parsed{} route := Parsed{} - start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[(\w+)\s+([0-9\-\:]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`) + start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[([\w\.]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`) second_rx := regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[(\w+)\s+([0-9\-\:]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`) type_rx := regexp.MustCompile(`^\s+Type:\s+(.*)\s*$`) bgp_rx := regexp.MustCompile(`^\s+BGP.(\w+):\s+(\w+)\s*$`) @@ -186,6 +186,8 @@ func parseRoutes(input []byte) Parsed { } } bgp["communities"] = communities + } else if groups[1] == "as_path" { + bgp["as_path"] = strings.Split(groups[2], " ") } else { bgp[groups[1]] = groups[2] } From b5ae11c1053354cd50a33fbb27d1acc0145807ad Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Fri, 25 Nov 2016 14:24:06 +0100 Subject: [PATCH 02/35] vbump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3eefcb9..7dea76e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 From 75b4aa3bd1295b2e61ad8271753ad0147c98f4c6 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 12:55:22 +0100 Subject: [PATCH 03/35] load and merge configs from system folder --- birdwatcher.go | 40 ++++++++++++++++++----- config.go | 67 ++++++++++++++++++++++++++++++++++++++ config_test.go | 17 ++++++++++ etc/init/bird4watcher.conf | 2 +- etc/init/bird6watcher.conf | 2 +- 5 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 config.go create mode 100644 config_test.go diff --git a/birdwatcher.go b/birdwatcher.go index df3197e..8540d5a 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -28,19 +28,43 @@ func makeRouter() *httprouter.Router { return r } +// Print service information like, listen address, +// access restrictions and configuration flags +func PrintServiceInfo(conf *Config, birdConf BirdConfig) { + // General Info + log.Println("Starting Birdwatcher") + log.Println(" Using:", birdConf.BirdCmd) + log.Println(" Listen:", birdConf.Listen) +} + func main() { - port := flag.String("port", - "29184", - "The port the birdwatcher should run on") - birdc := flag.String("birdc", - "birdc", - "The birdc command to use (for IPv6, use birdc6)") + bird6 := flag.Bool("6", false, "Use bird6 instead of bird") flag.Parse() - bird.BirdCmd = *birdc + // Load configurations + conf, err := LoadConfigs([]string{ + "./etc/birdwatcher/birdwatcher.conf", + "/etc/birdwatcher/birdwatcher.conf", + "./etc/birdwatcher/birdwatcher.local.conf", + }) + + if err != nil { + log.Fatal("Loading birdwatcher configuration failed:", err) + } + + // Get config according to flags + birdConf := conf.Bird + if *bird6 { + birdConf = conf.Bird6 + } + + PrintServiceInfo(conf, birdConf) + + // Configure client + bird.BirdCmd = birdConf.BirdCmd r := makeRouter() - realPort := strings.Join([]string{":", *port}, "") + realPort := strings.Join([]string{":", "23022"}, "") log.Fatal(http.ListenAndServe(realPort, r)) } diff --git a/config.go b/config.go new file mode 100644 index 0000000..fea2b6f --- /dev/null +++ b/config.go @@ -0,0 +1,67 @@ +package main + +// Birdwatcher Configuration + +import ( + "fmt" + "github.com/BurntSushi/toml" + "github.com/imdario/mergo" +) + +type Config struct { + Server ServerConfig + Status StatusConfig + Bird BirdConfig + Bird6 BirdConfig +} + +type ServerConfig struct { + AllowFrom []string `toml:"allow_from"` +} + +type StatusConfig struct { + ReconfigTimestampSource string `toml:"reconfig_timestamp_source"` + ReconfigTimestampMatch string `toml:"reconfig_timestamp_match"` + + FilteredFields []string `toml:"filtered_fields"` +} + +type BirdConfig struct { + Listen string + ConfigFilename string `toml:"config"` + BirdCmd string `toml:"birdc"` +} + +// Try to load configfiles as specified in the files +// list. For example: +// +// ./etc/birdwatcher/birdwatcher.conf +// /etc/birdwatcher/birdwatcher.conf +// ./etc/birdwatcher/birdwatcher.local.conf +// +// +func LoadConfigs(configFiles []string) (*Config, error) { + config := &Config{} + hasConfig := false + var confError error + + for _, filename := range configFiles { + tmp := &Config{} + _, err := toml.DecodeFile(filename, tmp) + if err != nil { + continue + } else { + hasConfig = true + // Merge configs + if err := mergo.Merge(config, tmp); err != nil { + return nil, err + } + } + } + + if !hasConfig { + confError = fmt.Errorf("Could not load any config file") + } + + return config, confError +} diff --git a/config_test.go b/config_test.go new file mode 100644 index 0000000..4770030 --- /dev/null +++ b/config_test.go @@ -0,0 +1,17 @@ +package main + +import ( + "testing" +) + +func TestLoadConfigs(t *testing.T) { + t.Log("Loading configs") + res, err := LoadConfigs([]string{ + "./etc/birdwatcher/birdwatcher.conf", + "/etc/birdwatcher/birdwatcher.conf", + "./etc/birdwatcher/birdwatcher.local.conf", + }) + + t.Log(res) + t.Log(err) +} diff --git a/etc/init/bird4watcher.conf b/etc/init/bird4watcher.conf index 0293fff..a8834a6 100644 --- a/etc/init/bird4watcher.conf +++ b/etc/init/bird4watcher.conf @@ -10,5 +10,5 @@ respawn limit 20 10 start on starting birdwatcher stop on stopping birdwatcher -exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -birdc bird -port 29184 2>&1 | logger -i -t 'BIRD4 WATCHER' +exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 2>&1 | logger -i -t 'BIRD4 WATCHER' diff --git a/etc/init/bird6watcher.conf b/etc/init/bird6watcher.conf index 642c095..7cada64 100644 --- a/etc/init/bird6watcher.conf +++ b/etc/init/bird6watcher.conf @@ -10,5 +10,5 @@ respawn limit 20 10 start on starting birdwatcher stop on stopping birdwatcher -exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -birdc bird6 -port 29185 2>&1 | logger -i -t 'BIRD6 WATCHER' +exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -6 2>&1 | logger -i -t 'BIRD6 WATCHER' From afc3f8a25db0b1eab542afac67bb3f276c80f6dd Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 12:56:54 +0100 Subject: [PATCH 04/35] moved config files --- .gitignore | 2 ++ birdwatcher.go | 6 +++--- etc/ecix/birdwatcher.conf | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 etc/ecix/birdwatcher.conf diff --git a/.gitignore b/.gitignore index 251ae28..c16085f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ birdwatcher birdwatcher-* DIST/ + +*.local.* diff --git a/birdwatcher.go b/birdwatcher.go index 8540d5a..bf3b1ed 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -43,9 +43,9 @@ func main() { // Load configurations conf, err := LoadConfigs([]string{ - "./etc/birdwatcher/birdwatcher.conf", - "/etc/birdwatcher/birdwatcher.conf", - "./etc/birdwatcher/birdwatcher.local.conf", + "./etc/ecix/birdwatcher.conf", + "/etc/ecix/birdwatcher.conf", + "./etc/ecix/birdwatcher.local.conf", }) if err != nil { diff --git a/etc/ecix/birdwatcher.conf b/etc/ecix/birdwatcher.conf new file mode 100644 index 0000000..a2e1969 --- /dev/null +++ b/etc/ecix/birdwatcher.conf @@ -0,0 +1,35 @@ + + +# +# Birdwatcher Configuration +# + +[server] +# Restrict access to certain IPs. Leave empty to allow from all. +allow_from = [] + + +[status] +# +# Where to get the reconfigure timestamp from: +# Available sources: bird, config_regex, config_modified +# +reconfig_timestamp_source = "bird" +reconfig_timestamp_match = "# Created (.*)" + +# Remove fields e.g. uptime +filter_fields = [] + + +[bird] +listen = "0.0.0.0:29184" +config = "/etc/bird.conf" +birdc = "birdc" + + +[bird6] +listen = "0.0.0.0:29185" +config = "/etc/bird6.conf" +birdc = "birdc6" + + From f7217108d9fd4dfbf69c760186d88eb2cbb5dbe3 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 13:14:12 +0100 Subject: [PATCH 05/35] fixed startup script --- .gitignore | 2 ++ VERSION | 2 +- etc/init/bird4watcher.conf | 2 +- etc/init/bird6watcher.conf | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 251ae28..b978237 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ birdwatcher birdwatcher-* DIST/ + +etc/ecix diff --git a/VERSION b/VERSION index 7dea76e..6d7de6e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.1 +1.0.2 diff --git a/etc/init/bird4watcher.conf b/etc/init/bird4watcher.conf index 0293fff..c8430ef 100644 --- a/etc/init/bird4watcher.conf +++ b/etc/init/bird4watcher.conf @@ -10,5 +10,5 @@ respawn limit 20 10 start on starting birdwatcher stop on stopping birdwatcher -exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -birdc bird -port 29184 2>&1 | logger -i -t 'BIRD4 WATCHER' +exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -birdc birdc -port 29184 2>&1 | logger -i -t 'BIRD4 WATCHER' diff --git a/etc/init/bird6watcher.conf b/etc/init/bird6watcher.conf index 642c095..d166f96 100644 --- a/etc/init/bird6watcher.conf +++ b/etc/init/bird6watcher.conf @@ -10,5 +10,5 @@ respawn limit 20 10 start on starting birdwatcher stop on stopping birdwatcher -exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -birdc bird6 -port 29185 2>&1 | logger -i -t 'BIRD6 WATCHER' +exec /opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -birdc birdc6 -port 29185 2>&1 | logger -i -t 'BIRD6 WATCHER' From bb1f3b7eaf67341f8f428ca6b828754f0b5c7e0c Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 13:16:39 +0100 Subject: [PATCH 06/35] vbump --- Makefile | 5 +++-- VERSION | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c3315c6..6b61f41 100644 --- a/Makefile +++ b/Makefile @@ -56,8 +56,6 @@ dist: clean linux rpm: dist # Clear tmp failed build (if any) - rm -f $(RPM) - rm -fr $(LOCAL_RPMS) mkdir $(LOCAL_RPMS) # Create RPM from dist @@ -68,6 +66,9 @@ rpm: dist remote_rpm: build_server dist + + mkdir -p $(LOCAL_RPMS) + # Copy distribution to build server ssh $(BUILD_SERVER) -- rm -rf $(REMOTE_DIST) scp -r $(DIST) $(BUILD_SERVER):$(REMOTE_DIST) diff --git a/VERSION b/VERSION index 6d7de6e..21e8796 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.2 +1.0.3 From d826108fc8227f75b9b01e4e14488b1a1d4189e4 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 13:21:40 +0100 Subject: [PATCH 07/35] get listen address from config --- birdwatcher.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/birdwatcher.go b/birdwatcher.go index bf3b1ed..339fb1b 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -4,7 +4,6 @@ import ( "flag" "log" "net/http" - "strings" "github.com/ecix/birdwatcher/bird" "github.com/ecix/birdwatcher/endpoints" @@ -63,8 +62,7 @@ func main() { // Configure client bird.BirdCmd = birdConf.BirdCmd + // Make server r := makeRouter() - - realPort := strings.Join([]string{":", "23022"}, "") - log.Fatal(http.ListenAndServe(realPort, r)) + log.Fatal(http.ListenAndServe(birdConf.Listen, r)) } From 7758148d3a639da82f259a524545f001b7a480e6 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 13:28:59 +0100 Subject: [PATCH 08/35] added marked birdwatcher.conf as config file --- Makefile | 2 ++ VERSION | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6b61f41..cee69e4 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,7 @@ rpm: dist # Create RPM from dist fpm -s dir -t rpm -n $(PROG) -v $(VERSION) -C $(DIST) \ + --config-files /etc/ecix/birdwatcher.conf \ opt/ etc/ mv $(RPM) $(LOCAL_RPMS) @@ -73,6 +74,7 @@ remote_rpm: build_server dist ssh $(BUILD_SERVER) -- rm -rf $(REMOTE_DIST) scp -r $(DIST) $(BUILD_SERVER):$(REMOTE_DIST) ssh $(BUILD_SERVER) -- fpm -s dir -t rpm -n $(PROG) -v $(VERSION) -C $(REMOTE_DIST) \ + --config-files /etc/ecix/birdwatcher.conf \ opt/ etc/ # Get rpm from server diff --git a/VERSION b/VERSION index 21e8796..9084fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.3 +1.1.0 From 3508a2298b74c9fc201f9ae187b00d973888c726 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 13:40:34 +0100 Subject: [PATCH 09/35] use config in bird --- bird/bird.go | 4 ++-- bird/config.go | 16 ++++++++++++++++ birdwatcher.go | 5 +++-- config.go | 22 ++++++---------------- 4 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 bird/config.go diff --git a/bird/bird.go b/bird/bird.go index b737344..85a9d6a 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -7,7 +7,7 @@ import ( "time" ) -var BirdCmd string +var Conf BirdConfig var Cache = struct { sync.RWMutex @@ -31,7 +31,7 @@ func toCache(key string, val Parsed) { func Run(args string) ([]byte, error) { args = "show " + args argsList := strings.Split(args, " ") - return exec.Command(BirdCmd, argsList...).Output() + return exec.Command(Conf.BirdCmd, argsList...).Output() } func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) { diff --git a/bird/config.go b/bird/config.go new file mode 100644 index 0000000..c84802b --- /dev/null +++ b/bird/config.go @@ -0,0 +1,16 @@ +package bird + +// Birdwatcher Birdc Configuration + +type StatusConfig struct { + ReconfigTimestampSource string `toml:"reconfig_timestamp_source"` + ReconfigTimestampMatch string `toml:"reconfig_timestamp_match"` + + FilteredFields []string `toml:"filtered_fields"` +} + +type BirdConfig struct { + Listen string + ConfigFilename string `toml:"config"` + BirdCmd string `toml:"birdc"` +} diff --git a/birdwatcher.go b/birdwatcher.go index 339fb1b..e5a9621 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -7,6 +7,7 @@ import ( "github.com/ecix/birdwatcher/bird" "github.com/ecix/birdwatcher/endpoints" + "github.com/julienschmidt/httprouter" ) @@ -29,7 +30,7 @@ func makeRouter() *httprouter.Router { // Print service information like, listen address, // access restrictions and configuration flags -func PrintServiceInfo(conf *Config, birdConf BirdConfig) { +func PrintServiceInfo(conf *Config, birdConf bird.BirdConfig) { // General Info log.Println("Starting Birdwatcher") log.Println(" Using:", birdConf.BirdCmd) @@ -60,7 +61,7 @@ func main() { PrintServiceInfo(conf, birdConf) // Configure client - bird.BirdCmd = birdConf.BirdCmd + bird.Conf = birdConf // Make server r := makeRouter() diff --git a/config.go b/config.go index fea2b6f..d8a82b4 100644 --- a/config.go +++ b/config.go @@ -6,32 +6,22 @@ import ( "fmt" "github.com/BurntSushi/toml" "github.com/imdario/mergo" + + "github.com/ecix/birdwatcher/bird" ) type Config struct { Server ServerConfig - Status StatusConfig - Bird BirdConfig - Bird6 BirdConfig + + Status bird.StatusConfig + Bird bird.BirdConfig + Bird6 bird.BirdConfig } type ServerConfig struct { AllowFrom []string `toml:"allow_from"` } -type StatusConfig struct { - ReconfigTimestampSource string `toml:"reconfig_timestamp_source"` - ReconfigTimestampMatch string `toml:"reconfig_timestamp_match"` - - FilteredFields []string `toml:"filtered_fields"` -} - -type BirdConfig struct { - Listen string - ConfigFilename string `toml:"config"` - BirdCmd string `toml:"birdc"` -} - // Try to load configfiles as specified in the files // list. For example: // From 830bf89944cff2af44f66af3065d651ec7601b64 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 13:43:39 +0100 Subject: [PATCH 10/35] remove local configuration files --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index cee69e4..6542e7f 100644 --- a/Makefile +++ b/Makefile @@ -45,9 +45,13 @@ dist: clean linux mkdir -p $(DIST)opt/ecix/birdwatcher/bin mkdir -p $(DIST)etc/init + mkdir -p $(DIST)etc/ecix + # Copy config and startup script cp etc/init/* DIST/etc/init/. + cp etc/ecix/* DIST/etc/ecix/. + rm -f DIST/etc/ecix/*.local.* # Copy bin cp $(PROG)-linux-$(ARCH) DIST/opt/ecix/birdwatcher/bin/. From 0a4befdcaa79f4005a25466ef46f560c3ccfba81 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 15:19:01 +0100 Subject: [PATCH 11/35] added access control --- birdwatcher.go | 15 ++++++++++++--- config.go | 8 +++----- endpoints/config.go | 6 ++++++ endpoints/endpoint.go | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 endpoints/config.go diff --git a/birdwatcher.go b/birdwatcher.go index e5a9621..759c4ad 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -4,6 +4,7 @@ import ( "flag" "log" "net/http" + "strings" "github.com/ecix/birdwatcher/bird" "github.com/ecix/birdwatcher/endpoints" @@ -33,8 +34,15 @@ func makeRouter() *httprouter.Router { func PrintServiceInfo(conf *Config, birdConf bird.BirdConfig) { // General Info log.Println("Starting Birdwatcher") - log.Println(" Using:", birdConf.BirdCmd) - log.Println(" Listen:", birdConf.Listen) + log.Println(" Using:", birdConf.BirdCmd) + log.Println(" Listen:", birdConf.Listen) + + // Endpoint Info + if len(conf.Server.AllowFrom) == 0 { + log.Println(" AllowFrom: ALL") + } else { + log.Println(" AllowFrom:", strings.Join(conf.Server.AllowFrom, ", ")) + } } func main() { @@ -60,8 +68,9 @@ func main() { PrintServiceInfo(conf, birdConf) - // Configure client + // Configuration bird.Conf = birdConf + endpoints.Conf = conf.Server // Make server r := makeRouter() diff --git a/config.go b/config.go index d8a82b4..6127f0f 100644 --- a/config.go +++ b/config.go @@ -4,24 +4,22 @@ package main import ( "fmt" + "github.com/BurntSushi/toml" "github.com/imdario/mergo" "github.com/ecix/birdwatcher/bird" + "github.com/ecix/birdwatcher/endpoints" ) type Config struct { - Server ServerConfig + Server endpoints.ServerConfig Status bird.StatusConfig Bird bird.BirdConfig Bird6 bird.BirdConfig } -type ServerConfig struct { - AllowFrom []string `toml:"allow_from"` -} - // Try to load configfiles as specified in the files // list. For example: // diff --git a/endpoints/config.go b/endpoints/config.go new file mode 100644 index 0000000..b727d4c --- /dev/null +++ b/endpoints/config.go @@ -0,0 +1,6 @@ +package endpoints + +// Endpoints / Server configuration +type ServerConfig struct { + AllowFrom []string `toml:"allow_from"` +} diff --git a/endpoints/endpoint.go b/endpoints/endpoint.go index e27ee35..ac95194 100644 --- a/endpoints/endpoint.go +++ b/endpoints/endpoint.go @@ -1,6 +1,10 @@ package endpoints import ( + "fmt" + "log" + "strings" + "encoding/json" "net/http" @@ -8,10 +12,43 @@ import ( "github.com/julienschmidt/httprouter" ) +var Conf ServerConfig + +func CheckAccess(req *http.Request) error { + if len(Conf.AllowFrom) == 0 { + return nil // AllowFrom ALL + } + + // Extract IP + tokens := strings.Split(req.RemoteAddr, ":") + ip := strings.Join(tokens[:len(tokens)-1], ":") + ip = strings.Replace(ip, "[", "", -1) + ip = strings.Replace(ip, "]", "", -1) + + // Check Access + for _, allowed := range Conf.AllowFrom { + if ip == allowed { + return nil + } + } + + // Log this request + log.Println("Rejecting access from:", ip) + + return fmt.Errorf("%s is not allowed to access this service.", ip) +} + func Endpoint(wrapped func(httprouter.Params) (bird.Parsed, bool)) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + // Access Control + if err := CheckAccess(r); err != nil { + http.Error(w, err.Error(), http.StatusForbidden) + return + } + res := make(map[string]interface{}) ret, from_cache := wrapped(ps) From 10b3174a502a73992fe20777d911df7a4c6770f5 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 15:19:35 +0100 Subject: [PATCH 12/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9084fa2..26aaba0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +1.2.0 From 53ff3aa013a13ff27dd3b128f56b4f0f619af8dc Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 15:41:17 +0100 Subject: [PATCH 13/35] added systemd support --- Makefile | 4 ++-- VERSION | 2 +- {etc => docs/upstart_example}/init/bird4watcher.conf | 0 {etc => docs/upstart_example}/init/bird6watcher.conf | 0 {etc => docs/upstart_example}/init/birdwatcher.conf | 0 etc/systemd/birdwatcher.target | 6 ++++++ etc/systemd/birdwatcher4.service | 11 +++++++++++ etc/systemd/birdwatcher6.service | 11 +++++++++++ 8 files changed, 31 insertions(+), 3 deletions(-) rename {etc => docs/upstart_example}/init/bird4watcher.conf (100%) rename {etc => docs/upstart_example}/init/bird6watcher.conf (100%) rename {etc => docs/upstart_example}/init/birdwatcher.conf (100%) create mode 100644 etc/systemd/birdwatcher.target create mode 100644 etc/systemd/birdwatcher4.service create mode 100644 etc/systemd/birdwatcher6.service diff --git a/Makefile b/Makefile index 6542e7f..9ad0f75 100644 --- a/Makefile +++ b/Makefile @@ -44,12 +44,12 @@ endif dist: clean linux mkdir -p $(DIST)opt/ecix/birdwatcher/bin - mkdir -p $(DIST)etc/init + mkdir -p $(DIST)etc/systemd mkdir -p $(DIST)etc/ecix # Copy config and startup script - cp etc/init/* DIST/etc/init/. + cp etc/systemd/* DIST/etc/systemd/. cp etc/ecix/* DIST/etc/ecix/. rm -f DIST/etc/ecix/*.local.* diff --git a/VERSION b/VERSION index 26aaba0..f0bb29e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.0 +1.3.0 diff --git a/etc/init/bird4watcher.conf b/docs/upstart_example/init/bird4watcher.conf similarity index 100% rename from etc/init/bird4watcher.conf rename to docs/upstart_example/init/bird4watcher.conf diff --git a/etc/init/bird6watcher.conf b/docs/upstart_example/init/bird6watcher.conf similarity index 100% rename from etc/init/bird6watcher.conf rename to docs/upstart_example/init/bird6watcher.conf diff --git a/etc/init/birdwatcher.conf b/docs/upstart_example/init/birdwatcher.conf similarity index 100% rename from etc/init/birdwatcher.conf rename to docs/upstart_example/init/birdwatcher.conf diff --git a/etc/systemd/birdwatcher.target b/etc/systemd/birdwatcher.target new file mode 100644 index 0000000..11f6f41 --- /dev/null +++ b/etc/systemd/birdwatcher.target @@ -0,0 +1,6 @@ +[Unit] +Wants=birdwatcher4.service birdwatcher6.service + +[Install] +WantedBy=multi-user.target + diff --git a/etc/systemd/birdwatcher4.service b/etc/systemd/birdwatcher4.service new file mode 100644 index 0000000..fc1bbc9 --- /dev/null +++ b/etc/systemd/birdwatcher4.service @@ -0,0 +1,11 @@ + +[Unit] +Description=Birdwatcher (IPv4) +After=network.target + +[Service] +ExecStart=/opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 + +[Install] +WantedBy=multi-user.target + diff --git a/etc/systemd/birdwatcher6.service b/etc/systemd/birdwatcher6.service new file mode 100644 index 0000000..e61c004 --- /dev/null +++ b/etc/systemd/birdwatcher6.service @@ -0,0 +1,11 @@ + +[Unit] +Description=Birdwatcher (IPv6) +After=network.target + +[Service] +ExecStart=/opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -6 + +[Install] +WantedBy=multi-user.target + From 340b13ab6e44e74dffe9a9f589c2c956ce75e3da Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Wed, 30 Nov 2016 17:42:40 +0100 Subject: [PATCH 14/35] added rpm build option for upstart and systemd --- Makefile | 14 ++++++++++++-- etc/systemd/birdwatcher.target | 6 ------ {etc => install}/systemd/birdwatcher4.service | 6 +++--- {etc => install}/systemd/birdwatcher6.service | 6 +++--- .../upstart}/init/bird4watcher.conf | 0 .../upstart}/init/bird6watcher.conf | 0 .../upstart}/init/birdwatcher.conf | 0 7 files changed, 18 insertions(+), 14 deletions(-) delete mode 100644 etc/systemd/birdwatcher.target rename {etc => install}/systemd/birdwatcher4.service (68%) rename {etc => install}/systemd/birdwatcher6.service (68%) rename {docs/upstart_example => install/upstart}/init/bird4watcher.conf (100%) rename {docs/upstart_example => install/upstart}/init/bird6watcher.conf (100%) rename {docs/upstart_example => install/upstart}/init/birdwatcher.conf (100%) diff --git a/Makefile b/Makefile index 9ad0f75..c7db02a 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,8 @@ VERSION=$(APP_VERSION)_$(shell git rev-parse --short HEAD) BUILD_SERVER='' +SYSTEM_INIT=systemd + DIST=DIST/ REMOTE_DIST=$(PROG)-$(DIST) @@ -44,12 +46,20 @@ endif dist: clean linux mkdir -p $(DIST)opt/ecix/birdwatcher/bin - mkdir -p $(DIST)etc/systemd mkdir -p $(DIST)etc/ecix +ifeq ($(SYSTEM_INIT), systemd) + # Installing systemd services + mkdir -p $(DIST)usr/lib/systemd/system/ + cp install/systemd/* $(DIST)usr/lib/systemd/system/. +else + # Installing upstart configuration + mkdir -p $(DIST)/etc/init/ + cp install/upstart/init/* $(DIST)etc/init/. +endif + # Copy config and startup script - cp etc/systemd/* DIST/etc/systemd/. cp etc/ecix/* DIST/etc/ecix/. rm -f DIST/etc/ecix/*.local.* diff --git a/etc/systemd/birdwatcher.target b/etc/systemd/birdwatcher.target deleted file mode 100644 index 11f6f41..0000000 --- a/etc/systemd/birdwatcher.target +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Wants=birdwatcher4.service birdwatcher6.service - -[Install] -WantedBy=multi-user.target - diff --git a/etc/systemd/birdwatcher4.service b/install/systemd/birdwatcher4.service similarity index 68% rename from etc/systemd/birdwatcher4.service rename to install/systemd/birdwatcher4.service index fc1bbc9..a4b6563 100644 --- a/etc/systemd/birdwatcher4.service +++ b/install/systemd/birdwatcher4.service @@ -1,11 +1,11 @@ - [Unit] -Description=Birdwatcher (IPv4) +Description=BIRDwatcher IPv4 +Wants=network.target After=network.target [Service] +Type=simple ExecStart=/opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 [Install] WantedBy=multi-user.target - diff --git a/etc/systemd/birdwatcher6.service b/install/systemd/birdwatcher6.service similarity index 68% rename from etc/systemd/birdwatcher6.service rename to install/systemd/birdwatcher6.service index e61c004..940d53e 100644 --- a/etc/systemd/birdwatcher6.service +++ b/install/systemd/birdwatcher6.service @@ -1,11 +1,11 @@ - [Unit] -Description=Birdwatcher (IPv6) +Description=BIRDwatcher IPv6 +Wants=network.target After=network.target [Service] +Type=simple ExecStart=/opt/ecix/birdwatcher/bin/birdwatcher-linux-amd64 -6 [Install] WantedBy=multi-user.target - diff --git a/docs/upstart_example/init/bird4watcher.conf b/install/upstart/init/bird4watcher.conf similarity index 100% rename from docs/upstart_example/init/bird4watcher.conf rename to install/upstart/init/bird4watcher.conf diff --git a/docs/upstart_example/init/bird6watcher.conf b/install/upstart/init/bird6watcher.conf similarity index 100% rename from docs/upstart_example/init/bird6watcher.conf rename to install/upstart/init/bird6watcher.conf diff --git a/docs/upstart_example/init/birdwatcher.conf b/install/upstart/init/birdwatcher.conf similarity index 100% rename from docs/upstart_example/init/birdwatcher.conf rename to install/upstart/init/birdwatcher.conf From c9381314e39bc24c4d5a6abcd8dacd7074adeb80 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Fri, 2 Dec 2016 17:07:30 +0100 Subject: [PATCH 15/35] use multiple sources for last reconfig timestamp --- bird/bird.go | 30 ++++++++++++++++++++++++++--- bird/status.go | 47 +++++++++++++++++++++++++++++++++++++++++++++ bird/status_test.go | 23 ++++++++++++++++++++++ birdwatcher.go | 3 ++- 4 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 bird/status.go create mode 100644 bird/status_test.go diff --git a/bird/bird.go b/bird/bird.go index 85a9d6a..f498cd7 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -7,7 +7,8 @@ import ( "time" ) -var Conf BirdConfig +var ClientConf BirdConfig +var StatusConf StatusConfig var Cache = struct { sync.RWMutex @@ -31,7 +32,7 @@ func toCache(key string, val Parsed) { func Run(args string) ([]byte, error) { args = "show " + args argsList := strings.Split(args, " ") - return exec.Command(Conf.BirdCmd, argsList...).Output() + return exec.Command(ClientConf.BirdCmd, argsList...).Output() } func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) { @@ -52,7 +53,30 @@ func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) { } func Status() (Parsed, bool) { - return RunAndParse("status", parseStatus) + birdStatus, ok := RunAndParse("status", parseStatus) + + // Last Reconfig Timestamp source: + var lastReconfig string + switch StatusConf.ReconfigTimestampSource { + case "bird": + lastReconfig = birdStatus["last_reconfig"].(string) + break + case "config_modified": + lastReconfig = lastReconfigTimestampFromFileStat( + ClientConf.ConfigFilename, + ) + case "config_regex": + lastReconfig = lastReconfigTimestampFromFileContent( + ClientConf.ConfigFilename, + StatusConf.ReconfigTimestampMatch, + ) + } + + birdStatus["lastReconfig"] = lastReconfig + + // Filter fields + + return birdStatus, ok } func Protocols() (Parsed, bool) { diff --git a/bird/status.go b/bird/status.go new file mode 100644 index 0000000..609b357 --- /dev/null +++ b/bird/status.go @@ -0,0 +1,47 @@ +package bird + +import ( + "bufio" + "fmt" + "os" + "regexp" +) + +// Get last reconfig timestamp from file modification date +func lastReconfigTimestampFromFileStat(filename string) string { + info, err := os.Stat(filename) + if err != nil { + return fmt.Sprintf("Could not fetch file modified timestamp: %s", err) + } + + modTime := info.ModTime().UTC() + buf, _ := modTime.MarshalJSON() + + return string(buf) +} + +// Parse config file linewise, find matching line and extract date +func lastReconfigTimestampFromFileContent(filename string, regex string) string { + rx := regexp.MustCompile(regex) + + // Read config file linewise + file, err := os.Open(filename) + if err != nil { + return fmt.Sprintf("Could not read: %s", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + matches := rx.FindStringSubmatch(scanner.Text()) + if len(matches) > 0 { + return matches[1] + } + } + + if err := scanner.Err(); err != nil { + return fmt.Sprintf("Error reading config: %s", err) + } + + return "" +} diff --git a/bird/status_test.go b/bird/status_test.go new file mode 100644 index 0000000..da98c52 --- /dev/null +++ b/bird/status_test.go @@ -0,0 +1,23 @@ +package bird + +// Created: 2016-12-01 14:15:00 + +import ( + "testing" +) + +func TestReconfigTimestampFromStat(t *testing.T) { + + // Just get the modification date of this file + ts := lastReconfigTimestampFromFileStat("./status_test.go") + t.Log(ts) + + ts = lastReconfigTimestampFromFileStat("./___i_do_not_exist___") + t.Log(ts) +} + +func TestReconfigTimestampFromContent(t *testing.T) { + + ts := lastReconfigTimestampFromFileContent("./status_test.go", "// Created: (.*)") + t.Log(ts) +} diff --git a/birdwatcher.go b/birdwatcher.go index 759c4ad..1b99b2b 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -69,7 +69,8 @@ func main() { PrintServiceInfo(conf, birdConf) // Configuration - bird.Conf = birdConf + bird.ClientConf = birdConf + bird.StatusConf = conf.Status endpoints.Conf = conf.Server // Make server From 0ec65b02bb1b7abc9e6cad59a2cd932acd961164 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Fri, 2 Dec 2016 17:11:57 +0100 Subject: [PATCH 16/35] added filtered fields --- bird/bird.go | 3 +++ bird/config.go | 2 +- config_test.go | 6 +++--- etc/ecix/birdwatcher.conf | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bird/bird.go b/bird/bird.go index f498cd7..5e78671 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -75,6 +75,9 @@ func Status() (Parsed, bool) { birdStatus["lastReconfig"] = lastReconfig // Filter fields + for _, field := range StatusConf.FilterFields { + birdStatus[field] = nil + } return birdStatus, ok } diff --git a/bird/config.go b/bird/config.go index c84802b..b5c6788 100644 --- a/bird/config.go +++ b/bird/config.go @@ -6,7 +6,7 @@ type StatusConfig struct { ReconfigTimestampSource string `toml:"reconfig_timestamp_source"` ReconfigTimestampMatch string `toml:"reconfig_timestamp_match"` - FilteredFields []string `toml:"filtered_fields"` + FilterFields []string `toml:"filter_fields"` } type BirdConfig struct { diff --git a/config_test.go b/config_test.go index 4770030..adf7376 100644 --- a/config_test.go +++ b/config_test.go @@ -7,9 +7,9 @@ import ( func TestLoadConfigs(t *testing.T) { t.Log("Loading configs") res, err := LoadConfigs([]string{ - "./etc/birdwatcher/birdwatcher.conf", - "/etc/birdwatcher/birdwatcher.conf", - "./etc/birdwatcher/birdwatcher.local.conf", + "./etc/ecix/birdwatcher.conf", + "/etc/ecix/birdwatcher.conf", + "./etc/ecix/birdwatcher.local.conf", }) t.Log(res) diff --git a/etc/ecix/birdwatcher.conf b/etc/ecix/birdwatcher.conf index a2e1969..6fb1472 100644 --- a/etc/ecix/birdwatcher.conf +++ b/etc/ecix/birdwatcher.conf @@ -17,7 +17,7 @@ allow_from = [] reconfig_timestamp_source = "bird" reconfig_timestamp_match = "# Created (.*)" -# Remove fields e.g. uptime +# Remove fields e.g. last_reboot filter_fields = [] From 757e2960a32f468511c47e8a390cb0bf2571f8f2 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 11:32:25 +0100 Subject: [PATCH 17/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f0bb29e..88c5fb8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.0 +1.4.0 From 8e31be933eacea8e1dbb7c996558f335468fb1dc Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 14:06:17 +0100 Subject: [PATCH 18/35] fixed fieldname and ipv6 regex --- bird/bird.go | 2 +- bird/parser.go | 2 +- bird/status.go | 8 +++++++- etc/ecix/birdwatcher.conf | 10 +++++----- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/bird/bird.go b/bird/bird.go index 5e78671..c2d142c 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -72,7 +72,7 @@ func Status() (Parsed, bool) { ) } - birdStatus["lastReconfig"] = lastReconfig + birdStatus["last_reconfig"] = lastReconfig // Filter fields for _, field := range StatusConf.FilterFields { diff --git a/bird/parser.go b/bird/parser.go index 8a8dbdd..7204118 100644 --- a/bird/parser.go +++ b/bird/parser.go @@ -244,7 +244,7 @@ func parseBgp(input string) Parsed { lines := getLinesFromString(input) route_changes := Parsed{} - bgp_rx := regexp.MustCompile(`^([\w\.]+)\s+BGP\s+(\w+)\s+(\w+)\s+([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2})\s*(\w+)?.*$`) + bgp_rx := regexp.MustCompile(`^([\w\.:]+)\s+BGP\s+(\w+)\s+(\w+)\s+([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2})\s*(\w+)?.*$`) num_val_rx := regexp.MustCompile(`^\s+([^:]+):\s+([\d]+)\s*$`) str_val_rx := regexp.MustCompile(`^\s+([^:]+):\s+(.+)\s*$`) routes_rx := regexp.MustCompile(`^\s+Routes:\s+(\d+)\s+imported,\s+(\d+)\s+filtered,\s+(\d+)\s+exported,\s+(\d+)\s+preferred\s*$`) diff --git a/bird/status.go b/bird/status.go index 609b357..9763058 100644 --- a/bird/status.go +++ b/bird/status.go @@ -24,6 +24,8 @@ func lastReconfigTimestampFromFileStat(filename string) string { func lastReconfigTimestampFromFileContent(filename string, regex string) string { rx := regexp.MustCompile(regex) + fmt.Println("Using regex:", regex) + // Read config file linewise file, err := os.Open(filename) if err != nil { @@ -33,7 +35,11 @@ func lastReconfigTimestampFromFileContent(filename string, regex string) string scanner := bufio.NewScanner(file) for scanner.Scan() { - matches := rx.FindStringSubmatch(scanner.Text()) + txt := scanner.Text() + fmt.Println("---------") + fmt.Println(txt) + + matches := rx.FindStringSubmatch(txt) if len(matches) > 0 { return matches[1] } diff --git a/etc/ecix/birdwatcher.conf b/etc/ecix/birdwatcher.conf index 6fb1472..75511b9 100644 --- a/etc/ecix/birdwatcher.conf +++ b/etc/ecix/birdwatcher.conf @@ -15,21 +15,21 @@ allow_from = [] # Available sources: bird, config_regex, config_modified # reconfig_timestamp_source = "bird" -reconfig_timestamp_match = "# Created (.*)" +reconfig_timestamp_match = "# Created: (.*)" # Remove fields e.g. last_reboot filter_fields = [] [bird] -listen = "0.0.0.0:29184" -config = "/etc/bird.conf" +listen = "0.0.0.0:29188" +config = "./etc/bird.conf" birdc = "birdc" [bird6] -listen = "0.0.0.0:29185" -config = "/etc/bird6.conf" +listen = "0.0.0.0:29189" +config = "./etc/bird6.conf" birdc = "birdc6" From 2dfcf48ac744f0cb90657ebc548ac01b5e025f0e Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 14:06:44 +0100 Subject: [PATCH 19/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 88c5fb8..347f583 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.0 +1.4.1 From 9583f996cf79439b9c6bb21c864f8a3a586d1f0b Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 14:33:21 +0100 Subject: [PATCH 20/35] use nested map --- VERSION | 2 +- bird/bird.go | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 347f583..9df886c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.1 +1.4.2 diff --git a/bird/bird.go b/bird/bird.go index c2d142c..bb215c7 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -54,12 +54,13 @@ func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) { func Status() (Parsed, bool) { birdStatus, ok := RunAndParse("status", parseStatus) + status := birdStatus["status"].(map[string]interface{}) // Last Reconfig Timestamp source: var lastReconfig string switch StatusConf.ReconfigTimestampSource { case "bird": - lastReconfig = birdStatus["last_reconfig"].(string) + lastReconfig = status["last_reconfig"].(string) break case "config_modified": lastReconfig = lastReconfigTimestampFromFileStat( @@ -72,13 +73,15 @@ func Status() (Parsed, bool) { ) } - birdStatus["last_reconfig"] = lastReconfig + status["last_reconfig"] = lastReconfig // Filter fields for _, field := range StatusConf.FilterFields { - birdStatus[field] = nil + status[field] = nil } + birdStatus["status"] = status + return birdStatus, ok } From d55f56ccd17d14b73388920c08fcd92c9b69575d Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 14:34:02 +0100 Subject: [PATCH 21/35] fixed example path --- etc/ecix/birdwatcher.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/ecix/birdwatcher.conf b/etc/ecix/birdwatcher.conf index 75511b9..ce32389 100644 --- a/etc/ecix/birdwatcher.conf +++ b/etc/ecix/birdwatcher.conf @@ -23,13 +23,13 @@ filter_fields = [] [bird] listen = "0.0.0.0:29188" -config = "./etc/bird.conf" +config = "/etc/bird.conf" birdc = "birdc" [bird6] listen = "0.0.0.0:29189" -config = "./etc/bird6.conf" +config = "/etc/bird6.conf" birdc = "birdc6" From 0cba1865b0c14edb2bf30c2f696cce783fea815a Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 14:54:13 +0100 Subject: [PATCH 22/35] fixed cast, removed debug output --- VERSION | 2 +- bird/bird.go | 2 +- bird/status.go | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 9df886c..428b770 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.2 +1.4.3 diff --git a/bird/bird.go b/bird/bird.go index bb215c7..84a2daf 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -54,7 +54,7 @@ func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) { func Status() (Parsed, bool) { birdStatus, ok := RunAndParse("status", parseStatus) - status := birdStatus["status"].(map[string]interface{}) + status := birdStatus["status"].(Parsed) // Last Reconfig Timestamp source: var lastReconfig string diff --git a/bird/status.go b/bird/status.go index 9763058..fa38a34 100644 --- a/bird/status.go +++ b/bird/status.go @@ -35,11 +35,7 @@ func lastReconfigTimestampFromFileContent(filename string, regex string) string scanner := bufio.NewScanner(file) for scanner.Scan() { - txt := scanner.Text() - fmt.Println("---------") - fmt.Println(txt) - - matches := rx.FindStringSubmatch(txt) + matches := rx.FindStringSubmatch(scanner.Text()) if len(matches) > 0 { return matches[1] } From 244c4824068206c7ae299e4896e22de6937b423c Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 15:26:19 +0100 Subject: [PATCH 23/35] ipv6 compat regex --- bird/parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bird/parser.go b/bird/parser.go index 7204118..0bd1a03 100644 --- a/bird/parser.go +++ b/bird/parser.go @@ -127,7 +127,7 @@ func parseRoutes(input []byte) Parsed { routes := []Parsed{} route := Parsed{} - start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[([\w\.]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`) + start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`) second_rx := regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[(\w+)\s+([0-9\-\:]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`) type_rx := regexp.MustCompile(`^\s+Type:\s+(.*)\s*$`) bgp_rx := regexp.MustCompile(`^\s+BGP.(\w+):\s+(\w+)\s*$`) From 40e5fea9b3ea51e5c094c0c56c1c3c221c8cbdd1 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 15:26:34 +0100 Subject: [PATCH 24/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 428b770..1c99cf0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.3 +1.4.4 From 34871bf43d2e29f2def3b22d9995b31695f7dc1e Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 16:36:59 +0100 Subject: [PATCH 25/35] another day, another regex fix. --- bird/parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bird/parser.go b/bird/parser.go index 0bd1a03..8a1fdde 100644 --- a/bird/parser.go +++ b/bird/parser.go @@ -130,7 +130,7 @@ func parseRoutes(input []byte) Parsed { start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`) second_rx := regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[(\w+)\s+([0-9\-\:]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`) type_rx := regexp.MustCompile(`^\s+Type:\s+(.*)\s*$`) - bgp_rx := regexp.MustCompile(`^\s+BGP.(\w+):\s+(\w+)\s*$`) + bgp_rx := regexp.MustCompile(`^\s+BGP.(\w+):\s+(.+)\s*$`) community_rx := regexp.MustCompile(`^\((\d+),(\d+)\)`) for _, line := range lines { if specialLine(line) || (len(route) == 0 && emptyLine(line)) { From e06c02fffab1edf7cbf729e0e08d9edcb8d22287 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Mon, 5 Dec 2016 17:14:28 +0100 Subject: [PATCH 26/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1c99cf0..e516bb9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.4 +1.4.5 From afe0297a9dce50ae03010a49dbb373fbc5b9005c Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Tue, 6 Dec 2016 13:02:12 +0100 Subject: [PATCH 27/35] added filtering for protocol params --- endpoints/filter.go | 50 ++++++++++++++++++++++++++++++++++++++++ endpoints/filter_test.go | 39 +++++++++++++++++++++++++++++++ endpoints/routes.go | 8 ++++++- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 endpoints/filter.go create mode 100644 endpoints/filter_test.go diff --git a/endpoints/filter.go b/endpoints/filter.go new file mode 100644 index 0000000..4947ae5 --- /dev/null +++ b/endpoints/filter.go @@ -0,0 +1,50 @@ +package endpoints + +import ( + "fmt" +) + +/* + * Parameter / Request Validation + */ + +// Check if the value is not longer than a given length +func ValidateLength(value string, maxLength int) error { + if len(value) > maxLength { + return fmt.Errorf("Provided param value is too long.") + } + return nil +} + +func ValidateCharset(value string, alphabet string) error { + for i := 0; i < len(value); i++ { + c := value[i] + ok := false + for j := 0; j < len(alphabet); j++ { + if alphabet[j] == c { + ok = true + break + } + } + if !ok { + return fmt.Errorf("Invalid character in param value") + } + } + return nil +} + +func ValidateProtocolParam(value string) (string, error) { + + // Check length + if err := ValidateLength(value, 80); err != nil { + return "", err + } + + // Check input + allowed := "ID_AS:.abcdef1234567890" + if err := ValidateCharset(value, allowed); err != nil { + return "", err + } + + return value, nil +} diff --git a/endpoints/filter_test.go b/endpoints/filter_test.go new file mode 100644 index 0000000..b57f10a --- /dev/null +++ b/endpoints/filter_test.go @@ -0,0 +1,39 @@ +package endpoints + +import ( + "testing" +) + +func TestValidateProtocol(t *testing.T) { + + validProtocols := []string{ + "ID421_AS11171_123.8.127.19", + "ID429_AS12240_2222:7af8:8:05:01:30bb:0:1", + "AI421_AS11171_123..8..127..19", + } + + invalidProtocols := []string{ + "ID421_AS11171_123.8.127.lö19", + "Test123", + "ThisValueIsTooLong12345678901234567890123456789012345678901234567890123456789012345678901234567890", + } + + // Valid protocol values + for _, param := range validProtocols { + t.Log("Testing valid protocol:", param) + _, err := ValidateProtocolParam(param) + if err != nil { + t.Error(param, "should be a valid protocol param") + } + } + + // Invalid protocol values + for _, param := range invalidProtocols { + t.Log("Testing invalid protocol:", param) + _, err := ValidateProtocolParam(param) + if err == nil { + t.Error(param, "should be an invalid protocol param") + } + } + +} diff --git a/endpoints/routes.go b/endpoints/routes.go index 961d9b1..3d1fcf2 100644 --- a/endpoints/routes.go +++ b/endpoints/routes.go @@ -1,12 +1,18 @@ package endpoints import ( + "fmt" + "github.com/ecix/birdwatcher/bird" "github.com/julienschmidt/httprouter" ) func ProtoRoutes(ps httprouter.Params) (bird.Parsed, bool) { - return bird.RoutesProto(ps.ByName("protocol")) + protocol, err := ValidateProtocolParam(ps.ByName("protocol")) + if err != nil { + return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false + } + return bird.RoutesProto(protocol) } func TableRoutes(ps httprouter.Params) (bird.Parsed, bool) { From b6d715d6ccd4d8dfe3d2ceb32fc57be8715b5098 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Tue, 6 Dec 2016 13:17:43 +0100 Subject: [PATCH 28/35] whitelist routes --- birdwatcher.go | 74 +++++++++++++++++++++++++++++---------- endpoints/config.go | 3 +- etc/ecix/birdwatcher.conf | 14 ++++++++ 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/birdwatcher.go b/birdwatcher.go index 1b99b2b..6d6ec4f 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -12,20 +12,53 @@ import ( "github.com/julienschmidt/httprouter" ) -func makeRouter() *httprouter.Router { +func isModuleEnabled(module string, modulesEnabled []string) bool { + for _, enabled := range modulesEnabled { + if enabled == module { + return true + } + } + return false +} + +func makeRouter(config endpoints.ServerConfig) *httprouter.Router { + whitelist := config.ModulesEnabled + r := httprouter.New() - r.GET("/status", endpoints.Endpoint(endpoints.Status)) - r.GET("/protocols/bgp", endpoints.Endpoint(endpoints.Bgp)) - r.GET("/symbols", endpoints.Endpoint(endpoints.Symbols)) - r.GET("/symbols/tables", endpoints.Endpoint(endpoints.SymbolTables)) - r.GET("/symbols/protocols", endpoints.Endpoint(endpoints.SymbolProtocols)) - r.GET("/routes/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoRoutes)) - r.GET("/routes/table/:table", endpoints.Endpoint(endpoints.TableRoutes)) - r.GET("/routes/count/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoCount)) - r.GET("/routes/count/table/:table", endpoints.Endpoint(endpoints.TableCount)) - r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet)) - r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable)) - r.GET("/protocols", endpoints.Endpoint(endpoints.Protocols)) + if isModuleEnabled("status", whitelist) { + r.GET("/status", endpoints.Endpoint(endpoints.Status)) + } + if isModuleEnabled("protocols", whitelist) { + r.GET("/protocols", endpoints.Endpoint(endpoints.Protocols)) + } + if isModuleEnabled("protocols_bgp", whitelist) { + r.GET("/protocols/bgp", endpoints.Endpoint(endpoints.Bgp)) + } + if isModuleEnabled("symbols", whitelist) { + r.GET("/symbols", endpoints.Endpoint(endpoints.Symbols)) + } + if isModuleEnabled("symbols_tables", whitelist) { + r.GET("/symbols/tables", endpoints.Endpoint(endpoints.SymbolTables)) + } + if isModuleEnabled("symbols_protocols", whitelist) { + r.GET("/symbols/protocols", endpoints.Endpoint(endpoints.SymbolProtocols)) + } + if isModuleEnabled("routes_protocol", whitelist) { + r.GET("/routes/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoRoutes)) + } + if isModuleEnabled("routes_table", whitelist) { + r.GET("/routes/table/:table", endpoints.Endpoint(endpoints.TableRoutes)) + } + if isModuleEnabled("routes_count_protocol", whitelist) { + r.GET("/routes/count/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoCount)) + } + if isModuleEnabled("routes_count_table", whitelist) { + r.GET("/routes/count/table/:table", endpoints.Endpoint(endpoints.TableCount)) + } + if isModuleEnabled("route_net", whitelist) { + r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet)) + r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable)) + } return r } @@ -34,14 +67,19 @@ func makeRouter() *httprouter.Router { func PrintServiceInfo(conf *Config, birdConf bird.BirdConfig) { // General Info log.Println("Starting Birdwatcher") - log.Println(" Using:", birdConf.BirdCmd) - log.Println(" Listen:", birdConf.Listen) + log.Println(" Using:", birdConf.BirdCmd) + log.Println(" Listen:", birdConf.Listen) // Endpoint Info if len(conf.Server.AllowFrom) == 0 { - log.Println(" AllowFrom: ALL") + log.Println(" AllowFrom: ALL") } else { - log.Println(" AllowFrom:", strings.Join(conf.Server.AllowFrom, ", ")) + log.Println(" AllowFrom:", strings.Join(conf.Server.AllowFrom, ", ")) + } + + log.Println(" ModulesEnabled:") + for _, m := range conf.Server.ModulesEnabled { + log.Println(" -", m) } } @@ -74,6 +112,6 @@ func main() { endpoints.Conf = conf.Server // Make server - r := makeRouter() + r := makeRouter(conf.Server) log.Fatal(http.ListenAndServe(birdConf.Listen, r)) } diff --git a/endpoints/config.go b/endpoints/config.go index b727d4c..a924c87 100644 --- a/endpoints/config.go +++ b/endpoints/config.go @@ -2,5 +2,6 @@ package endpoints // Endpoints / Server configuration type ServerConfig struct { - AllowFrom []string `toml:"allow_from"` + AllowFrom []string `toml:"allow_from"` + ModulesEnabled []string `toml:"modules_enabled"` } diff --git a/etc/ecix/birdwatcher.conf b/etc/ecix/birdwatcher.conf index ce32389..8ab6659 100644 --- a/etc/ecix/birdwatcher.conf +++ b/etc/ecix/birdwatcher.conf @@ -8,6 +8,20 @@ # Restrict access to certain IPs. Leave empty to allow from all. allow_from = [] +# All modules: +# status +# protocols +# protocols_bgp +# symbols +# symbols_tables +# symbols_protocols +# routes_protocol +# routes_table +# routes_count_protocol +# routes_count_table +# route_net +# +modules_enabled = ["status", "protocols_bgp", "routes_protocol"] [status] # From 5df4876b896024d9c8373d9b7b937266ece79b1d Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Tue, 6 Dec 2016 13:18:16 +0100 Subject: [PATCH 29/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e516bb9..bc80560 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.5 +1.5.0 From 652193711dbced5414aae25021d88da4bc0e18ac Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 6 Dec 2016 14:26:47 +0100 Subject: [PATCH 30/35] fix charset validator on utf-8 --- endpoints/filter.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/endpoints/filter.go b/endpoints/filter.go index 4947ae5..4dfa2d5 100644 --- a/endpoints/filter.go +++ b/endpoints/filter.go @@ -17,11 +17,10 @@ func ValidateLength(value string, maxLength int) error { } func ValidateCharset(value string, alphabet string) error { - for i := 0; i < len(value); i++ { - c := value[i] + for _, check := range value { ok := false - for j := 0; j < len(alphabet); j++ { - if alphabet[j] == c { + for _, char := range alphabet { + if char == check { ok = true break } From 75b9e05fdecca04832db0d0e0d23e46aafae82e3 Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Tue, 6 Dec 2016 14:34:45 +0100 Subject: [PATCH 31/35] rebuild rpm --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bc80560..26ca594 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.0 +1.5.1 From 7cdad2d9ca3b58f9ddaec31fbbdae9ef365eda48 Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 6 Dec 2016 14:44:18 +0100 Subject: [PATCH 32/35] added proto counts to validated methods --- endpoints/routes.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/endpoints/routes.go b/endpoints/routes.go index 3d1fcf2..f13becd 100644 --- a/endpoints/routes.go +++ b/endpoints/routes.go @@ -20,7 +20,11 @@ func TableRoutes(ps httprouter.Params) (bird.Parsed, bool) { } func ProtoCount(ps httprouter.Params) (bird.Parsed, bool) { - return bird.RoutesProtoCount(ps.ByName("protocol")) + protocol, err := ValidateProtocolParam(ps.ByName("protocol")) + if err != nil { + return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false + } + return bird.RoutesProtoCount(protocol) } func TableCount(ps httprouter.Params) (bird.Parsed, bool) { From 53e6da37e045c658aa60b070288ac4d43128de65 Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 6 Dec 2016 17:20:27 +0100 Subject: [PATCH 33/35] added filtered routes --- bird/bird.go | 4 ++++ birdwatcher.go | 3 +++ endpoints/routes.go | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/bird/bird.go b/bird/bird.go index 84a2daf..3cc3b4b 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -119,6 +119,10 @@ func RoutesProtoCount(protocol string) (Parsed, bool) { parseRoutesCount) } +func RoutesFiltered(protocol string) (Parsed, bool) { + return RunAndParse("route protocol '"+protocol+"' filtered", parseRoutes) +} + func RoutesExport(protocol string) (Parsed, bool) { return RunAndParse("route export '"+protocol+"' all", parseRoutes) diff --git a/birdwatcher.go b/birdwatcher.go index 6d6ec4f..e9b9d2e 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -55,6 +55,9 @@ func makeRouter(config endpoints.ServerConfig) *httprouter.Router { if isModuleEnabled("routes_count_table", whitelist) { r.GET("/routes/count/table/:table", endpoints.Endpoint(endpoints.TableCount)) } + if isModuleEnabled("routes_filtered", whitelist) { + r.GET("routes/filtered/:protocol", endpoints.Endpoint(endpoints.RoutesFiltered)) + } if isModuleEnabled("route_net", whitelist) { r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet)) r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable)) diff --git a/endpoints/routes.go b/endpoints/routes.go index f13becd..a398ce9 100644 --- a/endpoints/routes.go +++ b/endpoints/routes.go @@ -15,6 +15,14 @@ func ProtoRoutes(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesProto(protocol) } +func RoutesFiltered(ps httprouter.Params) (bird.Parsed, bool) { + protocol, err := ValidateProtocolParam(ps.ByName("protocol")) + if err != nil { + return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false + } + return bird.RoutesFiltered(protocol) +} + func TableRoutes(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesTable(ps.ByName("table")) } From 47e514e9edd9e563edc69e27292f204284ba3c8f Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 6 Dec 2016 17:46:52 +0100 Subject: [PATCH 34/35] allow rpm dir to exist --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c7db02a..bf75803 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ endif rpm: dist # Clear tmp failed build (if any) - mkdir $(LOCAL_RPMS) + mkdir -p $(LOCAL_RPMS) # Create RPM from dist fpm -s dir -t rpm -n $(PROG) -v $(VERSION) -C $(DIST) \ From e6b7d14c23dad1c7c7b9c1e3f3e93a0718b2fd24 Mon Sep 17 00:00:00 2001 From: hellerve Date: Thu, 8 Dec 2016 11:09:25 +0100 Subject: [PATCH 35/35] added prefixes --- bird/bird.go | 4 ++++ birdwatcher.go | 3 +++ endpoints/filter.go | 16 +++++++++++----- endpoints/routes.go | 8 ++++++++ etc/ecix/birdwatcher.conf | 4 +++- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/bird/bird.go b/bird/bird.go index 3cc3b4b..fa0abc0 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -109,6 +109,10 @@ func Symbols() (Parsed, bool) { return RunAndParse("symbols", parseSymbols) } +func RoutesPrefixed(prefix string) (Parsed, bool) { + return RunAndParse("route all '"+prefix+"'", parseRoutes) +} + func RoutesProto(protocol string) (Parsed, bool) { return RunAndParse("route protocol '"+protocol+"' all", parseRoutes) diff --git a/birdwatcher.go b/birdwatcher.go index e9b9d2e..1c2a8d1 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -58,6 +58,9 @@ func makeRouter(config endpoints.ServerConfig) *httprouter.Router { if isModuleEnabled("routes_filtered", whitelist) { r.GET("routes/filtered/:protocol", endpoints.Endpoint(endpoints.RoutesFiltered)) } + if isModuleEnabled("routes_prefixed", whitelist) { + r.GET("routes/prefix/:prefix", endpoints.Endpoint(endpoints.RoutesPrefixed)) + } if isModuleEnabled("route_net", whitelist) { r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet)) r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable)) diff --git a/endpoints/filter.go b/endpoints/filter.go index 4dfa2d5..6386cb3 100644 --- a/endpoints/filter.go +++ b/endpoints/filter.go @@ -32,18 +32,24 @@ func ValidateCharset(value string, alphabet string) error { return nil } -func ValidateProtocolParam(value string) (string, error) { - +func ValidateLengthAndCharset(value string, maxLength int, alphabet string) (string, error) { // Check length - if err := ValidateLength(value, 80); err != nil { + if err := ValidateLength(value, maxLength); err != nil { return "", err } // Check input - allowed := "ID_AS:.abcdef1234567890" - if err := ValidateCharset(value, allowed); err != nil { + if err := ValidateCharset(value, alphabet); err != nil { return "", err } return value, nil } + +func ValidateProtocolParam(value string) (string, error) { + return ValidateLengthAndCharset(value, 80, "ID_AS:.abcdef1234567890") +} + +func ValidatePrefixParam(value string) (string, error) { + return ValidateLengthAndCharset(value, 80, "1234567890abcdef.:/") +} diff --git a/endpoints/routes.go b/endpoints/routes.go index a398ce9..c8a95a4 100644 --- a/endpoints/routes.go +++ b/endpoints/routes.go @@ -23,6 +23,14 @@ func RoutesFiltered(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesFiltered(protocol) } +func RoutesPrefixed(ps httprouter.Params) (bird.Parsed, bool) { + prefix, err := ValidatePrefixParam(ps.ByName("prefix")) + if err != nil { + return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false + } + return bird.RoutesPrefixed(prefix) +} + func TableRoutes(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesTable(ps.ByName("table")) } diff --git a/etc/ecix/birdwatcher.conf b/etc/ecix/birdwatcher.conf index 8ab6659..93cc840 100644 --- a/etc/ecix/birdwatcher.conf +++ b/etc/ecix/birdwatcher.conf @@ -20,7 +20,9 @@ allow_from = [] # routes_count_protocol # routes_count_table # route_net -# +# routes_filtered +# routes_prefixed +# modules_enabled = ["status", "protocols_bgp", "routes_protocol"] [status]