Browse Source

REST, code improvement, documentation

pull/1/head v0.0.3
Fred Posner 4 years ago
parent
commit
9eb8f3d2c8
No known key found for this signature in database GPG Key ID: ABAD515F42AE1A40
4 changed files with 176 additions and 72 deletions
  1. +46
    -4
      README.md
  2. +130
    -68
      go/iptables-api.go
  3. BIN
      iptables-api
  4. BIN
      iptables-api-arm

+ 46
- 4
README.md View File

@ -87,6 +87,13 @@ Add an IP to iptables. iptables or ip6tables will be chosen based on the IP.
* **Auth**: None * **Auth**: None
* **RESPONSE**: 200/4xx/5xx * **RESPONSE**: 200/4xx/5xx
or
* **URL**: `/`
* **METHOD**: `POST`
* **Auth**: None
* **RESPONSE**: 200/4xx/5xx
#### Add/Block Success Examples #### Add/Block Success Examples
* GET `/addip/1.2.3.4` * GET `/addip/1.2.3.4`
@ -103,6 +110,13 @@ Add an IP to iptables. iptables or ip6tables will be chosen based on the IP.
{"success":"added"} {"success":"added"}
``` ```
* POST `/` with `{"ipaddress":"1.2.3.4"}`
* RESPONSE `200 OK`
```json
{"success":"added"}
```
#### Add/Block Error Examples #### Add/Block Error Examples
* GET `/addip/1.2.3` * GET `/addip/1.2.3`
@ -119,6 +133,13 @@ Add an IP to iptables. iptables or ip6tables will be chosen based on the IP.
{"error":"only valid ip addresses supported"} {"error":"only valid ip addresses supported"}
``` ```
* POST `/` with `{"address":"1.2.3.4"}`
* RESPONSE `400 Bad Request`
```json
{"error":"ipaddress is missing. "}
```
### Remove/Unblock IP ### Remove/Unblock IP
Remove an IP from iptables. iptables or ip6tables will be chosen based on the IP. Remove an IP from iptables. iptables or ip6tables will be chosen based on the IP.
@ -134,14 +155,21 @@ Remove an IP from iptables. iptables or ip6tables will be chosen based on the IP
* RESPONSE `200 OK` * RESPONSE `200 OK`
```json ```json
{"success":"removed"}
{"success":"deleted"}
``` ```
* GET `/unblockip/2001:db8:3333:4444:5555:6666:7777:8888` * GET `/unblockip/2001:db8:3333:4444:5555:6666:7777:8888`
* RESPONSE `200 OK` * RESPONSE `200 OK`
```json ```json
{"success":"removed"}
{"success":"deleted"}
```
* DELETE `/` with `{"ipaddress":"1.2.3.4"}`
* RESPONSE `200 OK`
```json
{"success":"deleted"}
``` ```
#### Remove/Unblock Error Examples #### Remove/Unblock Error Examples
@ -160,6 +188,13 @@ Remove an IP from iptables. iptables or ip6tables will be chosen based on the IP
{"error":"only valid ip addresses supported"} {"error":"only valid ip addresses supported"}
``` ```
* DELETE `/` with `{"address":"1.2.3.4"}`
* RESPONSE `400 Bad Request`
```json
{"error":"ipaddress is missing. "}
```
### Flush APIBANLOCAL chain ### Flush APIBANLOCAL chain
Flushes the iptables and ip6tables APIBANLOCAL chain. Flushes the iptables and ip6tables APIBANLOCAL chain.
@ -175,10 +210,10 @@ Flushes the iptables and ip6tables APIBANLOCAL chain.
* RESPONSE `200 OK` * RESPONSE `200 OK`
```json ```json
{"success":"flushed"}
{"result":"ipv4 flushed. ipv6 flushed. "}
``` ```
#### Flush Error Example
#### Flush Error Examples
* GET `/flushchain` * GET `/flushchain`
* RESPONSE `500 Internal Server Error` * RESPONSE `500 Internal Server Error`
@ -187,6 +222,13 @@ Flushes the iptables and ip6tables APIBANLOCAL chain.
{"error":"error initializing iptables"} {"error":"error initializing iptables"}
``` ```
* GET `/flushchain`
* RESPONSE `200 OK`
```json
{"result":"ipv4 error. ipv6 flushed. "}
```
## License / Warranty ## License / Warranty
iptables-api 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 2 of the License, or (at your option) any later version iptables-api 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 2 of the License, or (at your option) any later version


+ 130
- 68
go/iptables-api.go View File

@ -25,6 +25,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"net" "net"
"net/http" "net/http"
@ -33,6 +34,7 @@ import (
"github.com/coreos/go-iptables/iptables" "github.com/coreos/go-iptables/iptables"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/palner/pgrtools/pgparse"
) )
var logFile string var logFile string
@ -70,9 +72,11 @@ func main() {
router := mux.NewRouter() router := mux.NewRouter()
router.HandleFunc("/addip/{ipaddress}", addIPAddress).Methods("GET") router.HandleFunc("/addip/{ipaddress}", addIPAddress).Methods("GET")
router.HandleFunc("/blockip/{ipaddress}", addIPAddress).Methods("GET") router.HandleFunc("/blockip/{ipaddress}", addIPAddress).Methods("GET")
router.HandleFunc("/flushchain", flushChain).Methods("GET")
router.HandleFunc("/removeip/{ipaddress}", removeIPAddress).Methods("GET") router.HandleFunc("/removeip/{ipaddress}", removeIPAddress).Methods("GET")
router.HandleFunc("/unblockip/{ipaddress}", removeIPAddress).Methods("GET") router.HandleFunc("/unblockip/{ipaddress}", removeIPAddress).Methods("GET")
router.HandleFunc("/flushchain", flushChain).Methods("GET")
router.HandleFunc("/", rAddIPAddress).Methods("POST")
router.HandleFunc("/", rRemoveIPAddress).Methods("DELETE")
http.ListenAndServe("0.0.0.0:"+APIport, router) http.ListenAndServe("0.0.0.0:"+APIport, router)
} }
@ -159,20 +163,11 @@ func initializeIPTables(ipt *iptables.IPTables) (string, error) {
return "chain created", nil return "chain created", nil
} }
func addIPAddress(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
log.Println("processing addIPAddress", params["ipaddress"])
ipType, err := checkIPAddressv4(params["ipaddress"])
if err != nil {
log.Println(params["ipaddress"], "is not a valid ip address")
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
return
}
func iptableHandle(proto string, task string, ipvar string) (string, error) {
log.Println("iptableHandle:", proto, task, ipvar)
var ipProto iptables.Protocol var ipProto iptables.Protocol
switch ipType {
switch proto {
case "ipv6": case "ipv6":
ipProto = iptables.ProtocolIPv6 ipProto = iptables.ProtocolIPv6
default: default:
@ -182,24 +177,65 @@ func addIPAddress(w http.ResponseWriter, r *http.Request) {
// Go connect for IPTABLES // Go connect for IPTABLES
ipt, err := iptables.NewWithProtocol(ipProto) ipt, err := iptables.NewWithProtocol(ipProto)
if err != nil { if err != nil {
log.Println(err)
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
log.Println("iptableHandle:", err)
return "", err
} }
_, err = initializeIPTables(ipt) _, err = initializeIPTables(ipt)
if err != nil { if err != nil {
log.Fatalln("failed to initialize IPTables:", err)
http.Error(w, "{\"error\":\"error initializing iptables\"}", http.StatusInternalServerError)
log.Fatalln("iptableHandler: failed to initialize IPTables:", err)
return "", err
}
switch task {
case "add":
err = ipt.AppendUnique("filter", "APIBANLOCAL", "-s", ipvar, "-d", "0/0", "-j", targetChain)
if err != nil {
log.Println("iptableHandler: error adding address", err)
return "", err
} else {
return "added", nil
}
case "delete":
err = ipt.DeleteIfExists("filter", "APIBANLOCAL", "-s", ipvar, "-d", "0/0", "-j", targetChain)
if err != nil {
log.Println("iptableHandler: error removing address", err)
return "", err
} else {
return "deleted", nil
}
case "flush":
err = ipt.ClearChain("filter", "APIBANLOCAL")
if err != nil {
log.Println("iptableHandler:", proto, err)
return "", err
} else {
return "flushed", nil
}
default:
log.Println("iptableHandler: unknown task")
return "", errors.New("unknown task")
} }
}
func addIPAddress(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
log.Println("processing addIPAddress", params["ipaddress"])
err = ipt.AppendUnique("filter", "APIBANLOCAL", "-s", params["ipaddress"], "-d", "0/0", "-j", targetChain)
ipType, err := checkIPAddressv4(params["ipaddress"])
if err != nil { if err != nil {
log.Println("error adding address", err)
http.Error(w, "{\"error\":\"error adding address\"}", http.StatusBadRequest)
log.Println(params["ipaddress"], "is not a valid ip address")
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
return return
} }
io.WriteString(w, "{\"success\":\"added\"}\n")
status, err := iptableHandle(ipType, "add", params["ipaddress"])
if err != nil {
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
} else {
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
}
} }
func removeIPAddress(w http.ResponseWriter, r *http.Request) { func removeIPAddress(w http.ResponseWriter, r *http.Request) {
@ -214,88 +250,114 @@ func removeIPAddress(w http.ResponseWriter, r *http.Request) {
return return
} }
var ipProto iptables.Protocol
switch ipType {
case "ipv6":
ipProto = iptables.ProtocolIPv6
default:
ipProto = iptables.ProtocolIPv4
status, err := iptableHandle(ipType, "delete", params["ipaddress"])
if err != nil {
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
} else {
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
} }
}
// Go connect for IPTABLES
ipt, err := iptables.NewWithProtocol(ipProto)
func flushChain(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
log.Println("processing flushChain")
var flushResult string
_, err := iptableHandle("ipv4", "flush", "")
if err != nil { if err != nil {
log.Println(err)
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
flushResult = "ipv4" + err.Error() + ". "
} else {
flushResult = "ipv4 flushed. "
} }
_, err = initializeIPTables(ipt)
_, err = iptableHandle("ipv6", "flush", "")
if err != nil { if err != nil {
log.Fatalln("failed to initialize IPTables:", err)
http.Error(w, "{\"error\":\"error initializing iptables\"}", http.StatusInternalServerError)
flushResult = flushResult + "ipv6" + err.Error() + ". "
} else {
flushResult = flushResult + "ipv6 flushed. "
} }
err = ipt.DeleteIfExists("filter", "APIBANLOCAL", "-s", params["ipaddress"], "-d", "0/0", "-j", targetChain)
io.WriteString(w, "{\"result\":\""+flushResult+"\"}\n")
}
func rAddIPAddress(w http.ResponseWriter, r *http.Request) {
log.Println("processing rAddIPAddress")
// parse body
body, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
log.Println("error removing address", err)
http.Error(w, "{\"error\":\"error removing address\"}", http.StatusBadRequest)
log.Println("bodyErr ", err.Error())
http.Error(w, "{\"error\":\"unable to read body\"}", http.StatusBadRequest)
return return
} }
io.WriteString(w, "{\"success\":\"removed\"}\n")
}
log.Println("body received ->", string(body))
keyVal := pgparse.ParseBody(body)
keyVal = pgparse.LowerKeys(keyVal)
log.Println("body (lowercase):", keyVal)
func flushChain(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
log.Println("processing flushChain")
var ipErr string
// check for required fields
requiredfields := []string{"ipaddress"}
_, err = pgparse.CheckFields(keyVal, requiredfields)
// Go connect for IPTABLES
ipt, err := iptables.New()
if err != nil { if err != nil {
log.Println(err)
ipErr = err.Error()
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
log.Println("errors occured:", err)
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
return return
} }
_, err = initializeIPTables(ipt)
ipType, err := checkIPAddressv4(keyVal["ipaddress"])
if err != nil { if err != nil {
log.Fatalln("failed to initialize IPTables:", err)
http.Error(w, "{\"error\":\"error initializing iptables\"}", http.StatusInternalServerError)
log.Println(keyVal["ipaddress"], "is not a valid ip address")
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
return return
} }
err = ipt.ClearChain("filter", "APIBANLOCAL")
status, err := iptableHandle(ipType, "add", keyVal["ipaddress"])
if err != nil { if err != nil {
log.Print("Flushing APIBANLOCAL chain failed. ", err.Error())
ipErr = err.Error() + " "
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
} else { } else {
log.Print("APIBANLOCAL chain flushed.")
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
} }
}
// Go connect for IPTABLES
ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv6)
func rRemoveIPAddress(w http.ResponseWriter, r *http.Request) {
log.Println("processing rRemoveIPAddress")
// parse body
body, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
log.Println(err)
http.Error(w, "{\"error\":\"error with ip6tables\"}", http.StatusInternalServerError)
log.Println("bodyErr ", err.Error())
http.Error(w, "{\"error\":\"unable to read body\"}", http.StatusBadRequest)
return return
} }
_, err = initializeIPTables(ipt)
log.Println("body received ->", string(body))
keyVal := pgparse.ParseBody(body)
keyVal = pgparse.LowerKeys(keyVal)
log.Println("body (lowercase):", keyVal)
// check for required fields
requiredfields := []string{"ipaddress"}
_, err = pgparse.CheckFields(keyVal, requiredfields)
if err != nil { if err != nil {
log.Fatalln("failed to initialize IPTables:", err)
http.Error(w, "{\"error\":\"error initializing ip6tables\"}", http.StatusInternalServerError)
log.Println("errors occured:", err)
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
return
}
ipType, err := checkIPAddressv4(keyVal["ipaddress"])
if err != nil {
log.Println(keyVal["ipaddress"], "is not a valid ip address")
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
return return
} }
err = ipt.ClearChain("filter", "APIBANLOCAL")
status, err := iptableHandle(ipType, "delete", keyVal["ipaddress"])
if err != nil { if err != nil {
log.Print("Flushing ip6 APIBANLOCAL chain failed. ", err.Error())
ipErr = ipErr + err.Error()
http.Error(w, "{\"error\":\""+ipErr+"\"}", http.StatusBadRequest)
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
} else { } else {
log.Print("ip6 APIBANLOCAL chain flushed.")
io.WriteString(w, "{\"success\":\"flushed\"}\n")
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
} }
} }

BIN
iptables-api View File


BIN
iptables-api-arm View File


Loading…
Cancel
Save