go-version #1
BIN
build/lg-agent
BIN
build/lg-agent
Binary file not shown.
@@ -1,35 +1,154 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"git.mziesel.nl/mans/lg/internal/socket"
|
"git.mziesel.nl/mans/lg/internal/socket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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() {
|
func main() {
|
||||||
bc := socket.NewBirdSocket("/home/mans/run/bird.ctl", 1024)
|
config := loadConfig()
|
||||||
|
formattedConfig, err := json.MarshalIndent(config, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error formatting config: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("Loaded configuration: %s\n", formattedConfig)
|
||||||
|
|
||||||
err := bc.Connect()
|
mux := http.NewServeMux()
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer bc.Close()
|
|
||||||
|
|
||||||
resp, _, err := bc.Send("show status")
|
mux.HandleFunc("/health", apiMiddlewareChain(healthHandler))
|
||||||
if err != nil {
|
mux.HandleFunc("/bird/status", apiMiddlewareChain(birdStatusHandler))
|
||||||
log.Fatal(err)
|
mux.HandleFunc("/bird/command", apiMiddlewareChain(birdCommandHandler))
|
||||||
}
|
|
||||||
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))
|
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
|
package socket
|
||||||
|
|
||||||
// taken from
|
// taken from, adapted by me
|
||||||
// https://github.com/StatCan/go-birdc/blob/master/socket/socket.go
|
// https://github.com/StatCan/go-birdc/blob/master/socket/socket.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -35,6 +35,7 @@ type BirdSocket struct {
|
|||||||
path string
|
path string
|
||||||
bufferSize int
|
bufferSize int
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
|
restricted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBirdSocket creates a new BirdSocket
|
// NewBirdSocket creates a new BirdSocket
|
||||||
@@ -42,8 +43,8 @@ type BirdSocket struct {
|
|||||||
// `path` is the unix socket path
|
// `path` is the unix socket path
|
||||||
//
|
//
|
||||||
// `bufferSize` is the size of the read buffer
|
// `bufferSize` is the size of the read buffer
|
||||||
func NewBirdSocket(path string, bufferSize int) *BirdSocket {
|
func NewBirdSocket(path string, bufferSize int, restricted bool) *BirdSocket {
|
||||||
return &BirdSocket{path: path, bufferSize: bufferSize}
|
return &BirdSocket{path: path, bufferSize: bufferSize, restricted: restricted}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect opens the unix socket connection
|
// Connect opens the unix socket connection
|
||||||
@@ -57,6 +58,14 @@ func (s *BirdSocket) Connect() (err error) {
|
|||||||
buf := make([]byte, s.bufferSize)
|
buf := make([]byte, s.bufferSize)
|
||||||
_, err = s.conn.Read(buf[:])
|
_, 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user