/* * This file is part of nftables-http-api. * Copyright (C) 2024 Georg Pfuetzenreuter * * 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 . */ package main import ( "encoding/json" "errors" "golang.org/x/crypto/bcrypt" "log" "net" "net/http" "strings" ) type Response struct { RError string `json:"error,omitempty"` RResult string `json:"result,omitempty"` } type ResponseSet struct { RError string `json:"error,omitempty"` RResult []string `json:"result,omitempty"` } func doReturn(w http.ResponseWriter, status int, text string) { var response any if status == http.StatusOK || status == http.StatusCreated { response = Response{RResult: text} } else { response = Response{RError: text} } j, err := json.Marshal(response) if err != nil { log.Fatalf("Failed to marshal JSON: %s", err) } w.WriteHeader(status) w.Write(j) } func doReturnSet(w http.ResponseWriter, status int, text string, elements []string) { var response any if status == http.StatusOK { response = ResponseSet{RResult: elements} } else { response = Response{RError: text} } j, err := json.Marshal(response) if err != nil { log.Fatalf("Failed to marshal JSON: %s", err) } w.WriteHeader(status) w.Write(j) } func doCheckToken(token string, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(token)) if err == nil { return true } else { log.Printf("Token check failed: %s", err) return false } } func parseIPAddressOrNetworkString(givenAddress string) (net.IP, *net.IPNet, string, error) { if strings.Contains(givenAddress, "/") { return parseIPNetworkString(givenAddress) } else { address, family, err := parseIPAddressString(givenAddress) return address, nil, family, err } } func parseIPNetworkString(givenAddress string) (net.IP, *net.IPNet, string, error) { ipObject, cidrObject, err := net.ParseCIDR(givenAddress) if err != nil { return nil, nil, "", err } address, family, err := parseIPAddress(ipObject) return address, cidrObject, family, err } func parseIPAddressString(givenAddress string) (net.IP, string, error) { return parseIPAddress(net.ParseIP(givenAddress)) } func parseIPAddress(ipObject net.IP) (net.IP, string, error) { var address net.IP family, err := getIPAddressFamily(ipObject) if err == nil { if family == "ipv4" { address = ipObject.To4() } else if family == "ipv6" { address = ipObject.To16() } else { log.Println("unknown family, this should not happen") return nil, family, errors.New("unknown family") } return address, family, nil } log.Println("address parsing failed:", err) return nil, "", errors.New("invalid address") } func getIPAddressFamily(ipObject net.IP) (string, error) { ipAddress := ipObject.String() for i := 0; i < len(ipAddress); i++ { switch ipAddress[i] { case '.': return "ipv4", nil case ':': return "ipv6", nil } } return "", errors.New("address family detection failed") } func incrementIPAddress(ip net.IP) (net.IP, error) { for i := len(ip) - 1; i >= 0; i-- { ip[i]++ if ip[i] != 0 { break } } return ip, nil }