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
* **RESPONSE**: 200/4xx/5xx
or
* **URL**: `/`
* **METHOD**: `POST`
* **Auth**: None
* **RESPONSE**: 200/4xx/5xx
#### Add/Block Success Examples
* 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"}
```
* POST `/` with `{"ipaddress":"1.2.3.4"}`
* RESPONSE `200 OK`
```json
{"success":"added"}
```
#### Add/Block Error Examples
* 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"}
```
* POST `/` with `{"address":"1.2.3.4"}`
* RESPONSE `400 Bad Request`
```json
{"error":"ipaddress is missing. "}
```
### Remove/Unblock 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`
```json
{"success":"removed"}
{"success":"deleted"}
```
* GET `/unblockip/2001:db8:3333:4444:5555:6666:7777:8888`
* RESPONSE `200 OK`
```json
{"success":"removed"}
{"success":"deleted"}
```
* DELETE `/` with `{"ipaddress":"1.2.3.4"}`
* RESPONSE `200 OK`
```json
{"success":"deleted"}
```
#### 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"}
```
* DELETE `/` with `{"address":"1.2.3.4"}`
* RESPONSE `400 Bad Request`
```json
{"error":"ipaddress is missing. "}
```
### Flush APIBANLOCAL chain
Flushes the iptables and ip6tables APIBANLOCAL chain.
@ -175,10 +210,10 @@ Flushes the iptables and ip6tables APIBANLOCAL chain.
* RESPONSE `200 OK`
```json
{"success":"flushed"}
{"result":"ipv4 flushed. ipv6 flushed. "}
```
#### Flush Error Example
#### Flush Error Examples
* GET `/flushchain`
* RESPONSE `500 Internal Server Error`
@ -187,6 +222,13 @@ Flushes the iptables and ip6tables APIBANLOCAL chain.
{"error":"error initializing iptables"}
```
* GET `/flushchain`
* RESPONSE `200 OK`
```json
{"result":"ipv4 error. ipv6 flushed. "}
```
## 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


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

@ -25,6 +25,7 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@ -33,6 +34,7 @@ import (
"github.com/coreos/go-iptables/iptables"
"github.com/gorilla/mux"
"github.com/palner/pgrtools/pgparse"
)
var logFile string
@ -70,9 +72,11 @@ func main() {
router := mux.NewRouter()
router.HandleFunc("/addip/{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("/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)
}
@ -159,20 +163,11 @@ func initializeIPTables(ipt *iptables.IPTables) (string, error) {
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
switch ipType {
switch proto {
case "ipv6":
ipProto = iptables.ProtocolIPv6
default:
@ -182,24 +177,65 @@ func addIPAddress(w http.ResponseWriter, r *http.Request) {
// Go connect for IPTABLES
ipt, err := iptables.NewWithProtocol(ipProto)
if err != nil {
log.Println(err)
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
log.Println("iptableHandle:", err)
return "", err
}
_, err = initializeIPTables(ipt)
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 {
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
}
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) {
@ -214,88 +250,114 @@ func removeIPAddress(w http.ResponseWriter, r *http.Request) {
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 {
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 {
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 {
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
}
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 {
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
}
_, err = initializeIPTables(ipt)
ipType, err := checkIPAddressv4(keyVal["ipaddress"])
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
}
err = ipt.ClearChain("filter", "APIBANLOCAL")
status, err := iptableHandle(ipType, "add", keyVal["ipaddress"])
if err != nil {
log.Print("Flushing APIBANLOCAL chain failed. ", err.Error())
ipErr = err.Error() + " "
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
} 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 {
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
}
_, 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 {
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
}
err = ipt.ClearChain("filter", "APIBANLOCAL")
status, err := iptableHandle(ipType, "delete", keyVal["ipaddress"])
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 {
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