diff --git a/README.md b/README.md index da46251..d192612 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/go/iptables-api.go b/go/iptables-api.go index 71fc5c8..9e575c3 100644 --- a/go/iptables-api.go +++ b/go/iptables-api.go @@ -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") } } diff --git a/iptables-api b/iptables-api index 1ddf78c..22b6cd2 100755 Binary files a/iptables-api and b/iptables-api differ diff --git a/iptables-api-arm b/iptables-api-arm index bb366fe..4f72bd2 100755 Binary files a/iptables-api-arm and b/iptables-api-arm differ