/* * nftables-http-api * Copyright (C) 2024 Georg Pfuetzenreuter * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. If not, see . */ package main import ( "flag" "github.com/gorilla/mux" "gopkg.in/yaml.v3" "log" "net/http" "os" ) var config Config var configFile string var listen string func init() { flag.StringVar(&configFile, "config", "/etc/nft-set-api.yml", "Path to configuration file") flag.StringVar(&listen, "listen", "[::1]:8082", "Address and port to listen on") } type Config struct { TokenSets map[string][]string } type authMiddleWareMap struct { tokenSets map[string]string } func (authMiddleWare *authMiddleWareMap) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var givenToken = r.Header.Get("TOKEN") params := mux.Vars(r) givenSet := params["set"] if givenToken == "" { doReturn(w, http.StatusUnauthorized, "missing token") return } for configToken, configSets := range config.TokenSets { if doCheckToken(givenToken, configToken) { for _, configSet := range configSets { if givenSet == configSet { next.ServeHTTP(w, r) return } } } } log.Printf("Not processing unauthenticated request from %s", r.RemoteAddr) doReturn(w, http.StatusUnauthorized, "invalid token") }) } func main() { flag.Parse() log.Print("Booting ...") buffer, err := os.ReadFile(configFile) if err != nil { log.Fatalln("Could not read configuration file:", err) return } err = yaml.Unmarshal(buffer, &config) if err != nil { log.Fatalln("Could not parse configuration file:", err) return } log.Printf("%+v\n", config) log.Print("Listening on ", listen) router := mux.NewRouter() router.HandleFunc("/set/{set}", handleSetRoute).Methods("GET") authMiddleWare := authMiddleWareMap{make(map[string]string)} router.Use(authMiddleWare.Middleware) http.ListenAndServe(listen, router) } func handleSetRoute(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") params := mux.Vars(r) method := r.Method set := params["set"] log.Printf("Processing authorized %s request from %s for set %s", method, r.RemoteAddr, set) if method == "GET" { nftResult, err := handleNft("get", set) if err != nil { doReturn(w, http.StatusInternalServerError, "nftables failure") } if nftResult != nil { doReturnSet(w, http.StatusOK, "", nftResult.([]string)) } } }