2016-10-23 09:44:42 +02:00
|
|
|
package main
|
|
|
|
|
2016-10-23 09:51:40 +02:00
|
|
|
import (
|
2016-10-23 14:02:34 +02:00
|
|
|
"flag"
|
2016-10-23 09:51:40 +02:00
|
|
|
"log"
|
|
|
|
"net/http"
|
2018-05-07 18:11:31 +02:00
|
|
|
"os"
|
2018-05-08 11:33:49 +02:00
|
|
|
|
2016-11-30 15:19:01 +01:00
|
|
|
"strings"
|
2016-10-23 14:02:34 +02:00
|
|
|
|
2018-07-20 14:51:40 +02:00
|
|
|
"github.com/alice-lg/birdwatcher/bird"
|
|
|
|
"github.com/alice-lg/birdwatcher/endpoints"
|
2018-05-07 18:11:31 +02:00
|
|
|
"github.com/gorilla/handlers"
|
2016-11-30 13:40:34 +01:00
|
|
|
|
2016-10-23 14:02:34 +02:00
|
|
|
"github.com/julienschmidt/httprouter"
|
2016-10-23 09:51:40 +02:00
|
|
|
)
|
|
|
|
|
2017-01-26 12:12:02 +01:00
|
|
|
//go:generate versionize
|
2019-05-05 17:44:32 +02:00
|
|
|
var VERSION = "2.0.0"
|
2017-01-26 12:12:02 +01:00
|
|
|
|
2016-12-06 13:17:43 +01:00
|
|
|
func isModuleEnabled(module string, modulesEnabled []string) bool {
|
|
|
|
for _, enabled := range modulesEnabled {
|
|
|
|
if enabled == module {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
2018-01-15 23:04:19 +01:00
|
|
|
|
2016-12-06 13:17:43 +01:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeRouter(config endpoints.ServerConfig) *httprouter.Router {
|
|
|
|
whitelist := config.ModulesEnabled
|
|
|
|
|
2016-11-11 14:14:38 +01:00
|
|
|
r := httprouter.New()
|
2016-12-06 13:17:43 +01:00
|
|
|
if isModuleEnabled("status", whitelist) {
|
2017-02-15 12:20:55 +01:00
|
|
|
r.GET("/version", endpoints.Version(VERSION))
|
2016-12-06 13:17:43 +01:00
|
|
|
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))
|
|
|
|
}
|
2019-02-19 14:07:14 +01:00
|
|
|
if isModuleEnabled("protocols_short", whitelist) {
|
|
|
|
r.GET("/protocols/short", endpoints.Endpoint(endpoints.ProtocolsShort))
|
|
|
|
}
|
2016-12-06 13:17:43 +01:00
|
|
|
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))
|
|
|
|
}
|
2019-01-18 18:10:06 +01:00
|
|
|
if isModuleEnabled("routes_peer", whitelist) {
|
|
|
|
r.GET("/routes/peer/:peer", endpoints.Endpoint(endpoints.PeerRoutes))
|
|
|
|
}
|
2016-12-06 13:17:43 +01:00
|
|
|
if isModuleEnabled("routes_table", whitelist) {
|
|
|
|
r.GET("/routes/table/:table", endpoints.Endpoint(endpoints.TableRoutes))
|
|
|
|
}
|
2019-01-18 18:10:06 +01:00
|
|
|
if isModuleEnabled("routes_table_filtered", whitelist) {
|
|
|
|
r.GET("/routes/table/:table/filtered", endpoints.Endpoint(endpoints.TableRoutesFiltered))
|
|
|
|
}
|
|
|
|
if isModuleEnabled("routes_table_peer", whitelist) {
|
|
|
|
r.GET("/routes/table/:table/peer/:peer", endpoints.Endpoint(endpoints.TableAndPeerRoutes))
|
|
|
|
}
|
2016-12-06 13:17:43 +01:00
|
|
|
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))
|
|
|
|
}
|
2018-09-28 16:44:08 +02:00
|
|
|
if isModuleEnabled("routes_count_primary", whitelist) {
|
|
|
|
r.GET("/routes/count/primary/:protocol", endpoints.Endpoint(endpoints.ProtoPrimaryCount))
|
|
|
|
}
|
2016-12-06 17:20:27 +01:00
|
|
|
if isModuleEnabled("routes_filtered", whitelist) {
|
2016-12-09 11:49:45 +01:00
|
|
|
r.GET("/routes/filtered/:protocol", endpoints.Endpoint(endpoints.RoutesFiltered))
|
2016-12-06 17:20:27 +01:00
|
|
|
}
|
2020-01-26 23:12:06 +09:00
|
|
|
if isModuleEnabled("routes_export", whitelist) {
|
|
|
|
r.GET("/routes/export/:protocol", endpoints.Endpoint(endpoints.RoutesExport))
|
|
|
|
}
|
2017-04-07 11:14:03 +02:00
|
|
|
if isModuleEnabled("routes_noexport", whitelist) {
|
2017-04-07 11:18:51 +02:00
|
|
|
r.GET("/routes/noexport/:protocol", endpoints.Endpoint(endpoints.RoutesNoExport))
|
2017-04-07 11:14:03 +02:00
|
|
|
}
|
2016-12-08 11:09:25 +01:00
|
|
|
if isModuleEnabled("routes_prefixed", whitelist) {
|
2016-12-15 14:42:37 +01:00
|
|
|
r.GET("/routes/prefix", endpoints.Endpoint(endpoints.RoutesPrefixed))
|
2016-12-08 11:09:25 +01:00
|
|
|
}
|
2016-12-06 13:17:43 +01:00
|
|
|
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))
|
|
|
|
}
|
2019-01-18 18:10:06 +01:00
|
|
|
if isModuleEnabled("routes_pipe_filtered_count", whitelist) {
|
|
|
|
r.GET("/routes/pipe/filtered/count", endpoints.Endpoint(endpoints.PipeRoutesFilteredCount))
|
2017-02-15 12:20:55 +01:00
|
|
|
}
|
2019-01-18 18:10:06 +01:00
|
|
|
if isModuleEnabled("routes_pipe_filtered", whitelist) {
|
|
|
|
r.GET("/routes/pipe/filtered", endpoints.Endpoint(endpoints.PipeRoutesFiltered))
|
2017-06-22 15:06:54 +02:00
|
|
|
}
|
2019-01-18 18:10:06 +01:00
|
|
|
|
2016-11-11 14:14:38 +01:00
|
|
|
return r
|
2016-10-23 14:02:34 +02:00
|
|
|
}
|
|
|
|
|
2016-11-30 12:55:22 +01:00
|
|
|
// Print service information like, listen address,
|
|
|
|
// access restrictions and configuration flags
|
2016-11-30 13:40:34 +01:00
|
|
|
func PrintServiceInfo(conf *Config, birdConf bird.BirdConfig) {
|
2016-11-30 12:55:22 +01:00
|
|
|
// General Info
|
|
|
|
log.Println("Starting Birdwatcher")
|
2016-12-06 13:17:43 +01:00
|
|
|
log.Println(" Using:", birdConf.BirdCmd)
|
|
|
|
log.Println(" Listen:", birdConf.Listen)
|
2018-04-12 11:37:02 +02:00
|
|
|
log.Println(" Cache TTL:", birdConf.CacheTtl)
|
2016-11-30 15:19:01 +01:00
|
|
|
|
|
|
|
// Endpoint Info
|
|
|
|
if len(conf.Server.AllowFrom) == 0 {
|
2016-12-06 13:17:43 +01:00
|
|
|
log.Println(" AllowFrom: ALL")
|
2016-11-30 15:19:01 +01:00
|
|
|
} else {
|
2016-12-06 13:17:43 +01:00
|
|
|
log.Println(" AllowFrom:", strings.Join(conf.Server.AllowFrom, ", "))
|
|
|
|
}
|
|
|
|
|
2019-01-24 17:16:35 +01:00
|
|
|
if conf.Cache.UseRedis {
|
|
|
|
log.Println(" Caching backend: REDIS")
|
|
|
|
log.Println(" Using server:", conf.Cache.RedisServer)
|
|
|
|
} else {
|
|
|
|
log.Println(" Caching backend: MEMORY")
|
|
|
|
}
|
|
|
|
|
2016-12-06 13:17:43 +01:00
|
|
|
log.Println(" ModulesEnabled:")
|
|
|
|
for _, m := range conf.Server.ModulesEnabled {
|
|
|
|
log.Println(" -", m)
|
2016-11-30 15:19:01 +01:00
|
|
|
}
|
2016-11-30 12:55:22 +01:00
|
|
|
}
|
|
|
|
|
2018-05-08 11:33:49 +02:00
|
|
|
// MyLogger is our own log.Logger wrapper so we can customize it
|
2018-06-05 14:46:18 +02:00
|
|
|
type MyLogger struct {
|
|
|
|
logger *log.Logger
|
|
|
|
}
|
|
|
|
|
2018-05-08 11:33:49 +02:00
|
|
|
// Write implements the Write method of io.Writer
|
2018-06-05 14:46:18 +02:00
|
|
|
func (m *MyLogger) Write(p []byte) (n int, err error) {
|
2018-06-05 14:52:53 +02:00
|
|
|
m.logger.Print(string(p))
|
2018-06-05 14:46:18 +02:00
|
|
|
return len(p), nil
|
|
|
|
}
|
|
|
|
|
2016-10-23 09:44:42 +02:00
|
|
|
func main() {
|
2018-11-06 17:55:33 +01:00
|
|
|
// Disable timestamps for the default logger, as they are generated by the syslog implementation
|
|
|
|
log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))
|
2016-11-30 12:55:22 +01:00
|
|
|
bird6 := flag.Bool("6", false, "Use bird6 instead of bird")
|
2018-01-28 20:52:53 +01:00
|
|
|
workerPoolSize := flag.Int("worker-pool-size", 8, "Number of go routines used to parse routing tables concurrently")
|
2018-10-29 12:02:27 +01:00
|
|
|
configfile := flag.String("config", "/etc/birdwatcher/birdwatcher.conf", "Configuration file location")
|
2016-10-23 14:02:34 +02:00
|
|
|
flag.Parse()
|
|
|
|
|
2018-01-28 20:52:53 +01:00
|
|
|
bird.WorkerPoolSize = *workerPoolSize
|
|
|
|
|
2018-06-05 14:46:18 +02:00
|
|
|
conf, err := LoadConfigs([]string{*configfile})
|
|
|
|
if err != nil {
|
2018-06-05 14:52:53 +02:00
|
|
|
log.Fatal("Loading birdwatcher configuration failed:", err)
|
2018-05-07 18:11:31 +02:00
|
|
|
}
|
|
|
|
|
2018-06-05 14:46:18 +02:00
|
|
|
if conf.Server.EnableTLS {
|
|
|
|
if len(conf.Server.Crt) == 0 || len(conf.Server.Key) == 0 {
|
|
|
|
log.Fatalln("You have enabled TLS support. Please specify 'crt' and 'key' in birdwatcher config file.")
|
|
|
|
}
|
|
|
|
}
|
2016-11-30 12:55:22 +01:00
|
|
|
|
2018-06-05 14:46:18 +02:00
|
|
|
endpoints.VERSION = VERSION
|
|
|
|
bird.InstallRateLimitReset()
|
|
|
|
|
2016-11-30 12:55:22 +01:00
|
|
|
// Get config according to flags
|
|
|
|
birdConf := conf.Bird
|
|
|
|
if *bird6 {
|
|
|
|
birdConf = conf.Bird6
|
2018-01-15 23:04:19 +01:00
|
|
|
bird.IPVersion = "6"
|
2016-11-30 12:55:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PrintServiceInfo(conf, birdConf)
|
|
|
|
|
2016-11-30 15:19:01 +01:00
|
|
|
// Configuration
|
2016-12-02 17:07:30 +01:00
|
|
|
bird.ClientConf = birdConf
|
|
|
|
bird.StatusConf = conf.Status
|
2018-09-19 11:21:35 +02:00
|
|
|
bird.RateLimitConf.Lock()
|
2016-12-13 11:01:28 +01:00
|
|
|
bird.RateLimitConf.Conf = conf.Ratelimit
|
2018-09-19 11:21:35 +02:00
|
|
|
bird.RateLimitConf.Unlock()
|
2017-02-22 18:09:45 +01:00
|
|
|
bird.ParserConf = conf.Parser
|
2019-02-20 11:17:13 +01:00
|
|
|
bird.CacheConf = conf.Cache
|
|
|
|
bird.InitializeCache()
|
2019-02-28 11:32:40 +01:00
|
|
|
|
2016-11-30 15:19:01 +01:00
|
|
|
endpoints.Conf = conf.Server
|
2016-11-11 16:00:36 +01:00
|
|
|
|
2016-11-30 13:21:40 +01:00
|
|
|
// Make server
|
2016-12-06 13:17:43 +01:00
|
|
|
r := makeRouter(conf.Server)
|
2018-05-07 18:11:31 +02:00
|
|
|
|
2018-11-06 17:55:33 +01:00
|
|
|
// Set up our own custom log.Logger without a prefix
|
|
|
|
myquerylog := log.New(os.Stdout, "", 0)
|
|
|
|
// Disable timestamps, as they are contained in the query log
|
|
|
|
myquerylog.SetFlags(myquerylog.Flags() &^ (log.Ldate | log.Ltime))
|
2018-06-05 14:46:18 +02:00
|
|
|
mylogger := &MyLogger{myquerylog}
|
|
|
|
|
2019-02-20 11:17:13 +01:00
|
|
|
go Housekeeping(conf.Housekeeping, !(bird.CacheConf.UseRedis)) // expire caches only for MemoryCache
|
2019-02-18 17:46:32 +01:00
|
|
|
|
2018-06-05 14:52:53 +02:00
|
|
|
if conf.Server.EnableTLS {
|
|
|
|
if len(conf.Server.Crt) == 0 || len(conf.Server.Key) == 0 {
|
2018-06-05 14:59:26 +02:00
|
|
|
log.Fatalln("You have enabled TLS support but not specified both a .crt and a .key file in the config.")
|
2018-06-05 14:52:53 +02:00
|
|
|
}
|
|
|
|
log.Fatal(http.ListenAndServeTLS(birdConf.Listen, conf.Server.Crt, conf.Server.Key, handlers.LoggingHandler(mylogger, r)))
|
2018-05-07 18:11:31 +02:00
|
|
|
} else {
|
2018-06-05 14:46:18 +02:00
|
|
|
log.Fatal(http.ListenAndServe(birdConf.Listen, handlers.LoggingHandler(mylogger, r)))
|
2018-05-07 18:11:31 +02:00
|
|
|
}
|
2016-10-23 09:44:42 +02:00
|
|
|
}
|