Basics for nftables
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
This commit is contained in:
parent
b8ca3cec9f
commit
f402bce96b
11
go.mod
11
go.mod
@ -3,7 +3,18 @@ module nftables-http-api
|
||||
go 1.22.6
|
||||
|
||||
require (
|
||||
github.com/google/nftables v0.2.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
golang.org/x/crypto v0.26.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.5.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.23.0 // indirect
|
||||
)
|
||||
|
18
go.sum
18
go.sum
@ -1,7 +1,25 @@
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8=
|
||||
github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
|
||||
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
|
||||
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
|
||||
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
106
nft.go
Normal file
106
nft.go
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of nftables-http-api.
|
||||
* Copyright (C) 2024 Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
|
||||
*
|
||||
* The nftables-http-api 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/google/nftables"
|
||||
"log"
|
||||
)
|
||||
|
||||
type nftError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (nfterr nftError) Error() string {
|
||||
return nfterr.Message
|
||||
}
|
||||
|
||||
func handleNft(task string, set string) (any, error) {
|
||||
nft, err := nftables.New()
|
||||
if err != nil {
|
||||
log.Println("handleNft():", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if task == "get" {
|
||||
nftResult, err := getNftSetElements(nft, set)
|
||||
if err == nil {
|
||||
return nftResult, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func getNftTable(nft *nftables.Conn) (*nftables.Table, error) {
|
||||
targetTable := "filter" // TODO: make table configurable or smarter
|
||||
|
||||
foundTables, err := nft.ListTables()
|
||||
if err != nil {
|
||||
log.Printf("getNftTable(): %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exists := false
|
||||
var table *nftables.Table
|
||||
for _, foundTable := range foundTables {
|
||||
if foundTable.Name == targetTable {
|
||||
exists = true
|
||||
table = foundTable
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !exists {
|
||||
log.Printf("Table %s does not exist, cannot proceed", targetTable)
|
||||
return nil, nftError{Message: "Table does not exist"}
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
func getNftSet(nft *nftables.Conn, setName string) (*nftables.Set, error) {
|
||||
foundTable, err := getNftTable(nft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
foundSet, err := nft.GetSetByName(foundTable, setName)
|
||||
if err != nil || foundSet == nil {
|
||||
log.Printf("Set lookup for %s failed, cannot proceed: %s", setName, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return foundSet, nil
|
||||
}
|
||||
|
||||
func getNftSetElements(nft *nftables.Conn, setName string) ([]string, error) {
|
||||
set, err := getNftSet(nft, setName)
|
||||
if err != nil {
|
||||
log.Printf("Could not retrieve set elements")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setElements, err := nft.GetSetElements(set)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var returnElements []string
|
||||
|
||||
for _, element := range setElements {
|
||||
log.Printf("element: %s", element.Key)
|
||||
returnElements = append(returnElements, string(element.Key))
|
||||
}
|
||||
|
||||
return returnElements, nil
|
||||
}
|
@ -13,11 +13,12 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/gorilla/mux"
|
||||
"gopkg.in/yaml.v3"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"github.com/gorilla/mux"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var config Config
|
||||
@ -102,6 +103,12 @@ func handleSetRoute(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("Processing authorized %s request from %s for set %s", method, r.RemoteAddr, set)
|
||||
|
||||
if method == "GET" {
|
||||
doReturn(w, http.StatusOK, "ok")
|
||||
nftResult, err := handleNft("get", set)
|
||||
if err != nil {
|
||||
doReturn(w, http.StatusInternalServerError, "nftables failure")
|
||||
}
|
||||
if nftResult != nil {
|
||||
doReturn(w, http.StatusOK, strings.Join(nftResult.([]string), ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
utils.go
43
utils.go
@ -13,13 +13,15 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"errors"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
RError string `json:"error,omitempty"`
|
||||
RError string `json:"error,omitempty"`
|
||||
RResult string `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
@ -47,3 +49,38 @@ func doCheckToken(token string, hash string) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func parseIPAddress(straddress string) (net.IP, string) {
|
||||
parsedaddress := net.ParseIP(straddress)
|
||||
var address net.IP
|
||||
family, err := getIPAddressFamily(straddress)
|
||||
if err == nil {
|
||||
if family == "ipv4" {
|
||||
address = parsedaddress.To4()
|
||||
} else if family == "ipv6" {
|
||||
address = parsedaddress.To16()
|
||||
} else {
|
||||
log.Println("unknown family, this should not happen")
|
||||
return nil, family
|
||||
}
|
||||
return address, family
|
||||
}
|
||||
log.Println("address parsing failed:", err)
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func getIPAddressFamily(ip string) (string, error) {
|
||||
if net.ParseIP(ip) == nil {
|
||||
return "", errors.New("Not an IP address")
|
||||
}
|
||||
for i := 0; i < len(ip); i++ {
|
||||
switch ip[i] {
|
||||
case '.':
|
||||
return "ipv4", nil
|
||||
case ':':
|
||||
return "ipv6", nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("unknown error")
|
||||
}
|
||||
|
Reference in New Issue
Block a user