go-version #1
BIN
build/lg-agent
BIN
build/lg-agent
Binary file not shown.
@@ -1,35 +1,154 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"git.mziesel.nl/mans/lg/internal/socket"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bc := socket.NewBirdSocket("/home/mans/run/bird.ctl", 1024)
|
||||
|
||||
err := bc.Connect()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer bc.Close()
|
||||
|
||||
resp, _, err := bc.Send("show status")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Print(string(resp))
|
||||
resp, _, err = bc.Send("restrict")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Print(string(resp))
|
||||
resp, _, err = bc.Send("show protocols")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Print(string(resp))
|
||||
type LgAgentConfig struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
SocketPath string `json:"socket_path"`
|
||||
SharedSecret string `json:"shared_secret"`
|
||||
}
|
||||
|
||||
var config LgAgentConfig
|
||||
|
||||
func loadConfig() LgAgentConfig {
|
||||
// Default configuration
|
||||
config = LgAgentConfig{
|
||||
Host: "localhost",
|
||||
Port: 3000,
|
||||
SocketPath: "/var/run/bird/bird.ctl",
|
||||
SharedSecret: "", // empty = no secret
|
||||
}
|
||||
|
||||
// Determine the config file path
|
||||
configPath := "/etc/lg-agent/agent.json"
|
||||
if envPath := os.Getenv("LG_AGENT_CONFIG_PATH"); envPath != "" {
|
||||
configPath = envPath
|
||||
}
|
||||
|
||||
// Open the configuration file
|
||||
file, err := os.Open(configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Error opening config file: %v.", err)
|
||||
return config
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Decode the JSON configuration
|
||||
decoder := json.NewDecoder(file)
|
||||
if err := decoder.Decode(&config); err != nil {
|
||||
log.Fatalf("Error decoding config file: %v.", err)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func isAuthenticated(r *http.Request) bool {
|
||||
if config.SharedSecret == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
return authHeader == fmt.Sprintf("Bearer %s", config.SharedSecret)
|
||||
}
|
||||
|
||||
func ensureAuthenticatedMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !isAuthenticated(r) {
|
||||
http.Error(w, `{"error": "Unauthorized access"}`, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func plainTextMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func jsonMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func apiMiddlewareChain(h http.HandlerFunc) http.HandlerFunc {
|
||||
return plainTextMiddleware(ensureAuthenticatedMiddleware(h))
|
||||
}
|
||||
|
||||
func healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte("status: ok"))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func birdStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s := socket.NewBirdSocket(config.SocketPath, 4092, true)
|
||||
s.Connect()
|
||||
defer s.Close()
|
||||
status, _, err := s.Send("show status")
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error: failed to query router status", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err = w.Write([]byte("status: " + string(status)))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func birdCommandHandler(w http.ResponseWriter, r *http.Request) {
|
||||
command := r.URL.Query().Get("c")
|
||||
if command == "" {
|
||||
http.Error(w, "Bad Request: command parameter is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
s := socket.NewBirdSocket(config.SocketPath, 4092, true)
|
||||
s.Connect()
|
||||
defer s.Close()
|
||||
output, _, err := s.Send(command)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error: failed to query bird", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err = w.Write([]byte(string(output)))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
config := loadConfig()
|
||||
formattedConfig, err := json.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("Error formatting config: %v", err)
|
||||
}
|
||||
log.Printf("Loaded configuration: %s\n", formattedConfig)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("/health", apiMiddlewareChain(healthHandler))
|
||||
mux.HandleFunc("/bird/status", apiMiddlewareChain(birdStatusHandler))
|
||||
mux.HandleFunc("/bird/command", apiMiddlewareChain(birdCommandHandler))
|
||||
|
||||
log.Printf("starting listner on %s:%d\n", config.Host, config.Port)
|
||||
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", config.Host, config.Port), mux))
|
||||
}
|
||||
|
6
config/agent.json
Normal file
6
config/agent.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 4242,
|
||||
"socket_path": "/var/run/bird/bird.ctl",
|
||||
"shared_secret": ""
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
host = "127.0.0.1"
|
||||
port = 4242
|
||||
socket_path = "/var/run/bird/bird.ctl"
|
||||
shared_secret = ""
|
31
config/backend.json
Normal file
31
config/backend.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"lg": {
|
||||
"name": "Mans's looking glass"
|
||||
},
|
||||
"rate_limit": {
|
||||
"requests": 20,
|
||||
"time_window": 300
|
||||
},
|
||||
"routers": {
|
||||
"nur01": {
|
||||
"code": "nur01",
|
||||
"description": "BIRD2 router in Wierden",
|
||||
"ipv4": "127.0.0.1",
|
||||
"ipv6": "fe80::1",
|
||||
"agent": {
|
||||
"host": "127.0.0.1",
|
||||
"port": "4242"
|
||||
}
|
||||
},
|
||||
"wie01": {
|
||||
"code": "wie01",
|
||||
"description": "BIRD2 router in Nuremberg",
|
||||
"ipv4": "127.0.0.1",
|
||||
"ipv6": "fe80::1",
|
||||
"agent": {
|
||||
"host": "127.0.0.1",
|
||||
"port": "4243"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
[lg]
|
||||
name = "Mans's looking glass"
|
||||
|
||||
[rate_limit]
|
||||
requests = 20
|
||||
time_window = 300
|
||||
|
||||
[routers]
|
||||
|
||||
[routers.nur01]
|
||||
code = "nur01"
|
||||
description = "BIRD2 router in Wierden"
|
||||
ipv4 = "127.0.0.1"
|
||||
ipv6 = "fe80::1"
|
||||
|
||||
[routers.nur01.agent]
|
||||
host = "127.0.0.1"
|
||||
port = "4242"
|
||||
|
||||
[routers.wie01]
|
||||
code = "wie01"
|
||||
description = "BIRD2 router in Nuremberg"
|
||||
ipv4 = "127.0.0.1"
|
||||
ipv6 = "fe80::1"
|
||||
|
||||
[routers.wie01.agent]
|
||||
host = "127.0.0.1"
|
||||
port = "4243"
|
@@ -1,12 +0,0 @@
|
||||
package bird
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func ParseRawOutput(input string) (string, error) {
|
||||
reader := bufio.NewReader(input)
|
||||
|
||||
return "", errors.New("asdf")
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package socket
|
||||
|
||||
// taken from
|
||||
// taken from, adapted by me
|
||||
// https://github.com/StatCan/go-birdc/blob/master/socket/socket.go
|
||||
|
||||
import (
|
||||
@@ -35,6 +35,7 @@ type BirdSocket struct {
|
||||
path string
|
||||
bufferSize int
|
||||
conn net.Conn
|
||||
restricted bool
|
||||
}
|
||||
|
||||
// NewBirdSocket creates a new BirdSocket
|
||||
@@ -42,8 +43,8 @@ type BirdSocket struct {
|
||||
// `path` is the unix socket path
|
||||
//
|
||||
// `bufferSize` is the size of the read buffer
|
||||
func NewBirdSocket(path string, bufferSize int) *BirdSocket {
|
||||
return &BirdSocket{path: path, bufferSize: bufferSize}
|
||||
func NewBirdSocket(path string, bufferSize int, restricted bool) *BirdSocket {
|
||||
return &BirdSocket{path: path, bufferSize: bufferSize, restricted: restricted}
|
||||
}
|
||||
|
||||
// Connect opens the unix socket connection
|
||||
@@ -57,6 +58,14 @@ func (s *BirdSocket) Connect() (err error) {
|
||||
buf := make([]byte, s.bufferSize)
|
||||
_, err = s.conn.Read(buf[:])
|
||||
|
||||
_, resp_code, err := s.Send("restrict")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if string(resp_code) != "0016" { // access restricted
|
||||
return errors.New("failed to restrict bird session")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user