Skip to content

Commit 9eb8f3d

Browse files
committed
REST, code improvement, documentation
1 parent 958311c commit 9eb8f3d

4 files changed

Lines changed: 176 additions & 72 deletions

File tree

README.md

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ Add an IP to iptables. iptables or ip6tables will be chosen based on the IP.
8787
* **Auth**: None
8888
* **RESPONSE**: 200/4xx/5xx
8989
90+
or
91+
92+
* **URL**: `/`
93+
* **METHOD**: `POST`
94+
* **Auth**: None
95+
* **RESPONSE**: 200/4xx/5xx
96+
9097
#### Add/Block Success Examples
9198
9299
* 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.
103110
{"success":"added"}
104111
```
105112
113+
* POST `/` with `{"ipaddress":"1.2.3.4"}`
114+
* RESPONSE `200 OK`
115+
116+
```json
117+
{"success":"added"}
118+
```
119+
106120
#### Add/Block Error Examples
107121
108122
* GET `/addip/1.2.3`
@@ -119,6 +133,13 @@ Add an IP to iptables. iptables or ip6tables will be chosen based on the IP.
119133
{"error":"only valid ip addresses supported"}
120134
```
121135
136+
* POST `/` with `{"address":"1.2.3.4"}`
137+
* RESPONSE `400 Bad Request`
138+
139+
```json
140+
{"error":"ipaddress is missing. "}
141+
```
142+
122143
### Remove/Unblock IP
123144
124145
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
134155
* RESPONSE `200 OK`
135156
136157
```json
137-
{"success":"removed"}
158+
{"success":"deleted"}
138159
```
139160
140161
* GET `/unblockip/2001:db8:3333:4444:5555:6666:7777:8888`
141162
* RESPONSE `200 OK`
142163
143164
```json
144-
{"success":"removed"}
165+
{"success":"deleted"}
166+
```
167+
168+
* DELETE `/` with `{"ipaddress":"1.2.3.4"}`
169+
* RESPONSE `200 OK`
170+
171+
```json
172+
{"success":"deleted"}
145173
```
146174
147175
#### Remove/Unblock Error Examples
@@ -160,6 +188,13 @@ Remove an IP from iptables. iptables or ip6tables will be chosen based on the IP
160188
{"error":"only valid ip addresses supported"}
161189
```
162190
191+
* DELETE `/` with `{"address":"1.2.3.4"}`
192+
* RESPONSE `400 Bad Request`
193+
194+
```json
195+
{"error":"ipaddress is missing. "}
196+
```
197+
163198
### Flush APIBANLOCAL chain
164199
165200
Flushes the iptables and ip6tables APIBANLOCAL chain.
@@ -175,10 +210,10 @@ Flushes the iptables and ip6tables APIBANLOCAL chain.
175210
* RESPONSE `200 OK`
176211
177212
```json
178-
{"success":"flushed"}
213+
{"result":"ipv4 flushed. ipv6 flushed. "}
179214
```
180215
181-
#### Flush Error Example
216+
#### Flush Error Examples
182217
183218
* GET `/flushchain`
184219
* RESPONSE `500 Internal Server Error`
@@ -187,6 +222,13 @@ Flushes the iptables and ip6tables APIBANLOCAL chain.
187222
{"error":"error initializing iptables"}
188223
```
189224
225+
* GET `/flushchain`
226+
* RESPONSE `200 OK`
227+
228+
```json
229+
{"result":"ipv4 error. ipv6 flushed. "}
230+
```
231+
190232
## License / Warranty
191233
192234
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

go/iptables-api.go

Lines changed: 130 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"flag"
2626
"fmt"
2727
"io"
28+
"io/ioutil"
2829
"log"
2930
"net"
3031
"net/http"
@@ -33,6 +34,7 @@ import (
3334

3435
"github.com/coreos/go-iptables/iptables"
3536
"github.com/gorilla/mux"
37+
"github.com/palner/pgrtools/pgparse"
3638
)
3739

3840
var logFile string
@@ -70,9 +72,11 @@ func main() {
7072
router := mux.NewRouter()
7173
router.HandleFunc("/addip/{ipaddress}", addIPAddress).Methods("GET")
7274
router.HandleFunc("/blockip/{ipaddress}", addIPAddress).Methods("GET")
75+
router.HandleFunc("/flushchain", flushChain).Methods("GET")
7376
router.HandleFunc("/removeip/{ipaddress}", removeIPAddress).Methods("GET")
7477
router.HandleFunc("/unblockip/{ipaddress}", removeIPAddress).Methods("GET")
75-
router.HandleFunc("/flushchain", flushChain).Methods("GET")
78+
router.HandleFunc("/", rAddIPAddress).Methods("POST")
79+
router.HandleFunc("/", rRemoveIPAddress).Methods("DELETE")
7680
http.ListenAndServe("0.0.0.0:"+APIport, router)
7781
}
7882

@@ -159,20 +163,11 @@ func initializeIPTables(ipt *iptables.IPTables) (string, error) {
159163
return "chain created", nil
160164
}
161165

162-
func addIPAddress(w http.ResponseWriter, r *http.Request) {
163-
w.Header().Set("Content-Type", "application/json")
164-
params := mux.Vars(r)
165-
log.Println("processing addIPAddress", params["ipaddress"])
166-
167-
ipType, err := checkIPAddressv4(params["ipaddress"])
168-
if err != nil {
169-
log.Println(params["ipaddress"], "is not a valid ip address")
170-
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
171-
return
172-
}
166+
func iptableHandle(proto string, task string, ipvar string) (string, error) {
167+
log.Println("iptableHandle:", proto, task, ipvar)
173168

174169
var ipProto iptables.Protocol
175-
switch ipType {
170+
switch proto {
176171
case "ipv6":
177172
ipProto = iptables.ProtocolIPv6
178173
default:
@@ -182,24 +177,65 @@ func addIPAddress(w http.ResponseWriter, r *http.Request) {
182177
// Go connect for IPTABLES
183178
ipt, err := iptables.NewWithProtocol(ipProto)
184179
if err != nil {
185-
log.Println(err)
186-
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
180+
log.Println("iptableHandle:", err)
181+
return "", err
187182
}
188183

189184
_, err = initializeIPTables(ipt)
190185
if err != nil {
191-
log.Fatalln("failed to initialize IPTables:", err)
192-
http.Error(w, "{\"error\":\"error initializing iptables\"}", http.StatusInternalServerError)
186+
log.Fatalln("iptableHandler: failed to initialize IPTables:", err)
187+
return "", err
188+
}
189+
190+
switch task {
191+
case "add":
192+
err = ipt.AppendUnique("filter", "APIBANLOCAL", "-s", ipvar, "-d", "0/0", "-j", targetChain)
193+
if err != nil {
194+
log.Println("iptableHandler: error adding address", err)
195+
return "", err
196+
} else {
197+
return "added", nil
198+
}
199+
case "delete":
200+
err = ipt.DeleteIfExists("filter", "APIBANLOCAL", "-s", ipvar, "-d", "0/0", "-j", targetChain)
201+
if err != nil {
202+
log.Println("iptableHandler: error removing address", err)
203+
return "", err
204+
} else {
205+
return "deleted", nil
206+
}
207+
case "flush":
208+
err = ipt.ClearChain("filter", "APIBANLOCAL")
209+
if err != nil {
210+
log.Println("iptableHandler:", proto, err)
211+
return "", err
212+
} else {
213+
return "flushed", nil
214+
}
215+
default:
216+
log.Println("iptableHandler: unknown task")
217+
return "", errors.New("unknown task")
193218
}
219+
}
220+
221+
func addIPAddress(w http.ResponseWriter, r *http.Request) {
222+
w.Header().Set("Content-Type", "application/json")
223+
params := mux.Vars(r)
224+
log.Println("processing addIPAddress", params["ipaddress"])
194225

195-
err = ipt.AppendUnique("filter", "APIBANLOCAL", "-s", params["ipaddress"], "-d", "0/0", "-j", targetChain)
226+
ipType, err := checkIPAddressv4(params["ipaddress"])
196227
if err != nil {
197-
log.Println("error adding address", err)
198-
http.Error(w, "{\"error\":\"error adding address\"}", http.StatusBadRequest)
228+
log.Println(params["ipaddress"], "is not a valid ip address")
229+
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
199230
return
200231
}
201232

202-
io.WriteString(w, "{\"success\":\"added\"}\n")
233+
status, err := iptableHandle(ipType, "add", params["ipaddress"])
234+
if err != nil {
235+
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
236+
} else {
237+
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
238+
}
203239
}
204240

205241
func removeIPAddress(w http.ResponseWriter, r *http.Request) {
@@ -214,88 +250,114 @@ func removeIPAddress(w http.ResponseWriter, r *http.Request) {
214250
return
215251
}
216252

217-
var ipProto iptables.Protocol
218-
switch ipType {
219-
case "ipv6":
220-
ipProto = iptables.ProtocolIPv6
221-
default:
222-
ipProto = iptables.ProtocolIPv4
253+
status, err := iptableHandle(ipType, "delete", params["ipaddress"])
254+
if err != nil {
255+
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
256+
} else {
257+
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
223258
}
259+
}
224260

225-
// Go connect for IPTABLES
226-
ipt, err := iptables.NewWithProtocol(ipProto)
261+
func flushChain(w http.ResponseWriter, r *http.Request) {
262+
w.Header().Set("Content-Type", "application/json")
263+
log.Println("processing flushChain")
264+
var flushResult string
265+
266+
_, err := iptableHandle("ipv4", "flush", "")
227267
if err != nil {
228-
log.Println(err)
229-
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
268+
flushResult = "ipv4" + err.Error() + ". "
269+
} else {
270+
flushResult = "ipv4 flushed. "
230271
}
231272

232-
_, err = initializeIPTables(ipt)
273+
_, err = iptableHandle("ipv6", "flush", "")
233274
if err != nil {
234-
log.Fatalln("failed to initialize IPTables:", err)
235-
http.Error(w, "{\"error\":\"error initializing iptables\"}", http.StatusInternalServerError)
275+
flushResult = flushResult + "ipv6" + err.Error() + ". "
276+
} else {
277+
flushResult = flushResult + "ipv6 flushed. "
236278
}
237279

238-
err = ipt.DeleteIfExists("filter", "APIBANLOCAL", "-s", params["ipaddress"], "-d", "0/0", "-j", targetChain)
280+
io.WriteString(w, "{\"result\":\""+flushResult+"\"}\n")
281+
}
282+
283+
func rAddIPAddress(w http.ResponseWriter, r *http.Request) {
284+
log.Println("processing rAddIPAddress")
285+
286+
// parse body
287+
body, err := ioutil.ReadAll(r.Body)
239288
if err != nil {
240-
log.Println("error removing address", err)
241-
http.Error(w, "{\"error\":\"error removing address\"}", http.StatusBadRequest)
289+
log.Println("bodyErr ", err.Error())
290+
http.Error(w, "{\"error\":\"unable to read body\"}", http.StatusBadRequest)
242291
return
243292
}
244293

245-
io.WriteString(w, "{\"success\":\"removed\"}\n")
246-
}
294+
log.Println("body received ->", string(body))
295+
keyVal := pgparse.ParseBody(body)
296+
keyVal = pgparse.LowerKeys(keyVal)
297+
log.Println("body (lowercase):", keyVal)
247298

248-
func flushChain(w http.ResponseWriter, r *http.Request) {
249-
w.Header().Set("Content-Type", "application/json")
250-
log.Println("processing flushChain")
251-
var ipErr string
299+
// check for required fields
300+
requiredfields := []string{"ipaddress"}
301+
_, err = pgparse.CheckFields(keyVal, requiredfields)
252302

253-
// Go connect for IPTABLES
254-
ipt, err := iptables.New()
255303
if err != nil {
256-
log.Println(err)
257-
ipErr = err.Error()
258-
http.Error(w, "{\"error\":\"error with iptables\"}", http.StatusInternalServerError)
304+
log.Println("errors occured:", err)
305+
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
259306
return
260307
}
261308

262-
_, err = initializeIPTables(ipt)
309+
ipType, err := checkIPAddressv4(keyVal["ipaddress"])
263310
if err != nil {
264-
log.Fatalln("failed to initialize IPTables:", err)
265-
http.Error(w, "{\"error\":\"error initializing iptables\"}", http.StatusInternalServerError)
311+
log.Println(keyVal["ipaddress"], "is not a valid ip address")
312+
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
266313
return
267314
}
268315

269-
err = ipt.ClearChain("filter", "APIBANLOCAL")
316+
status, err := iptableHandle(ipType, "add", keyVal["ipaddress"])
270317
if err != nil {
271-
log.Print("Flushing APIBANLOCAL chain failed. ", err.Error())
272-
ipErr = err.Error() + " "
318+
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
273319
} else {
274-
log.Print("APIBANLOCAL chain flushed.")
320+
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
275321
}
322+
}
276323

277-
// Go connect for IPTABLES
278-
ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv6)
324+
func rRemoveIPAddress(w http.ResponseWriter, r *http.Request) {
325+
log.Println("processing rRemoveIPAddress")
326+
327+
// parse body
328+
body, err := ioutil.ReadAll(r.Body)
279329
if err != nil {
280-
log.Println(err)
281-
http.Error(w, "{\"error\":\"error with ip6tables\"}", http.StatusInternalServerError)
330+
log.Println("bodyErr ", err.Error())
331+
http.Error(w, "{\"error\":\"unable to read body\"}", http.StatusBadRequest)
282332
return
283333
}
284334

285-
_, err = initializeIPTables(ipt)
335+
log.Println("body received ->", string(body))
336+
keyVal := pgparse.ParseBody(body)
337+
keyVal = pgparse.LowerKeys(keyVal)
338+
log.Println("body (lowercase):", keyVal)
339+
340+
// check for required fields
341+
requiredfields := []string{"ipaddress"}
342+
_, err = pgparse.CheckFields(keyVal, requiredfields)
343+
286344
if err != nil {
287-
log.Fatalln("failed to initialize IPTables:", err)
288-
http.Error(w, "{\"error\":\"error initializing ip6tables\"}", http.StatusInternalServerError)
345+
log.Println("errors occured:", err)
346+
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
347+
return
348+
}
349+
350+
ipType, err := checkIPAddressv4(keyVal["ipaddress"])
351+
if err != nil {
352+
log.Println(keyVal["ipaddress"], "is not a valid ip address")
353+
http.Error(w, "{\"error\":\"only valid ip addresses supported\"}", http.StatusBadRequest)
289354
return
290355
}
291356

292-
err = ipt.ClearChain("filter", "APIBANLOCAL")
357+
status, err := iptableHandle(ipType, "delete", keyVal["ipaddress"])
293358
if err != nil {
294-
log.Print("Flushing ip6 APIBANLOCAL chain failed. ", err.Error())
295-
ipErr = ipErr + err.Error()
296-
http.Error(w, "{\"error\":\""+ipErr+"\"}", http.StatusBadRequest)
359+
http.Error(w, "{\"error\":\""+err.Error()+"\"}", http.StatusBadRequest)
297360
} else {
298-
log.Print("ip6 APIBANLOCAL chain flushed.")
299-
io.WriteString(w, "{\"success\":\"flushed\"}\n")
361+
io.WriteString(w, "{\"success\":\""+status+"\"}\n")
300362
}
301363
}

iptables-api

258 KB
Binary file not shown.

iptables-api-arm

204 KB
Binary file not shown.

0 commit comments

Comments
 (0)