ip46tables
wrote `ip46tables` C minimal program to handle both ipv4 and ipv6 at the same time. fix #22
This commit is contained in:
parent
e56b851d15
commit
92e07f5fe6
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/reaction
|
||||
/ip46tables
|
||||
/reaction*.db
|
||||
/reaction*.sock
|
||||
/result
|
||||
|
9
Makefile
Normal file
9
Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
all: reaction ip46tables
|
||||
|
||||
clean:
|
||||
rm -f reaction ip46tables
|
||||
ip46tables: ip46tables.d/ip46tables.c
|
||||
gcc ip46tables.d/ip46tables.c -o ip46tables
|
||||
|
||||
reaction: app/* reaction.go go.mod go.sum
|
||||
go build .
|
21
README.md
21
README.md
@ -32,9 +32,6 @@ definitions:
|
||||
|
||||
patterns:
|
||||
ip: '(([0-9]{1,3}\.){3}[0-9]{1,3})|([0-9a-fA-F:]{2,90})'
|
||||
ignore:
|
||||
- '127.0.0.1'
|
||||
- '::1'
|
||||
|
||||
streams:
|
||||
ssh:
|
||||
@ -63,7 +60,6 @@ local iptablesunban = ['iptables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-
|
||||
patterns: {
|
||||
ip: {
|
||||
regex: @'(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})',
|
||||
ignore: ['127.0.0.1', '::1'],
|
||||
},
|
||||
},
|
||||
streams: {
|
||||
@ -91,7 +87,7 @@ local iptablesunban = ['iptables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-
|
||||
}
|
||||
```
|
||||
|
||||
note that both yaml and jsonnet are extensions of json, so it is also inherently supported.
|
||||
note that both yaml and jsonnet are extensions of json, so json is also inherently supported.
|
||||
|
||||
`/etc/systemd/system/reaction.service`
|
||||
```systemd
|
||||
@ -124,11 +120,24 @@ if you don't know where to start it, `/var/lib/reaction` should be a sane choice
|
||||
|
||||
the socket allowing communication between the cli and server will be created at `/run/reaction/reaction.socket`.
|
||||
|
||||
### `ip46tables`
|
||||
|
||||
`ip46tables` is a minimal c program present in its own subdirectory with only standard posix dependencies.
|
||||
|
||||
it permits to configure `iptables` and `ip6tables` at the same time.
|
||||
it will execute `iptables` when detecting ipv4, `ip6tables` when detecting ipv6 and both if no ip address is present on the command line.
|
||||
|
||||
### compilation
|
||||
|
||||
you'll need the go toolchain.
|
||||
you'll need the go toolchain for reaction and a c compiler for ip46tables.
|
||||
```shell
|
||||
$ make
|
||||
```
|
||||
|
||||
alternatively,
|
||||
```shell
|
||||
$ go build .
|
||||
$ gcc ip46tables.d/ip46tables.c -o ip46tables
|
||||
```
|
||||
|
||||
### nixos
|
||||
|
@ -3,8 +3,10 @@
|
||||
# using YAML anchors `&name` and pointers `*name`
|
||||
# definitions are not readed by reaction
|
||||
definitions:
|
||||
- &iptablesban [ "iptables" "-w" "-A" "reaction" "1" "-s" "<ip>" "-j" "DROP" ]
|
||||
- &iptablesunban [ "iptables" "-w" "-D" "reaction" "1" "-s" "<ip>" "-j" "DROP" ]
|
||||
- &iptablesban [ "ip46tables" "-w" "-A" "reaction" "1" "-s" "<ip>" "-j" "DROP" ]
|
||||
- &iptablesunban [ "ip46tables" "-w" "-D" "reaction" "1" "-s" "<ip>" "-j" "DROP" ]
|
||||
# ip46tables is a minimal C program (only POSIX dependencies) present as a subdirectory.
|
||||
# it permits to handle both ipv4/iptables and ipv6/ip6tables commands
|
||||
|
||||
# patterns are substitued in regexes.
|
||||
# when a filter performs an action, it replaces the found pattern
|
||||
|
@ -3,8 +3,10 @@
|
||||
// JSONNET is a superset of JSON, so one can write plain JSON files if wanted.
|
||||
|
||||
// variables defined for later use.
|
||||
local iptablesban = ['iptables', '-w', '-A', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
|
||||
local iptablesunban = ['iptables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
|
||||
local iptablesban = ['ip46tables', '-w', '-A', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
|
||||
local iptablesunban = ['ip46tables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
|
||||
// ip46tables is a minimal C program (only POSIX dependencies) present as a subdirectory.
|
||||
// it permits to handle both ipv4/iptables and ipv6/ip6tables commands
|
||||
|
||||
{
|
||||
// patterns are substitued in regexes.
|
||||
|
@ -7,20 +7,22 @@ WantedBy=multi-user.target
|
||||
ExecStart=/path/to/reaction -c /etc/reaction.yml
|
||||
|
||||
# Create an iptables chain for reaction
|
||||
ExecStartPre=/path/to/iptables -w -N reaction
|
||||
ExecStartPre=/path/to/ip46tables -w -N reaction
|
||||
# Set its default to ACCEPT
|
||||
ExecStartPre=/path/to/iptables -w -A reaction -j ACCEPT
|
||||
ExecStartPre=/path/to/ip46tables -w -A reaction -j ACCEPT
|
||||
# Always accept 127.0.0.1
|
||||
ExecStartPre=/path/to/iptables -w -I reaction 1 -s 127.0.0.1 -j ACCEPT
|
||||
ExecStartPre=/path/to/ip46tables -w -I reaction 1 -s 127.0.0.1 -j ACCEPT
|
||||
# Always accept ::1
|
||||
ExecStartPre=/path/to/ip46tables -w -I reaction 1 -s ::1 -j ACCEPT
|
||||
# Insert this chain as the first item of the INPUT chain (for incoming connections)
|
||||
ExecStartPre=/path/to/iptables -w -I INPUT -p all -j reaction
|
||||
ExecStartPre=/path/to/ip46tables -w -I INPUT -p all -j reaction
|
||||
|
||||
# Remove the chain from the INPUT chain
|
||||
ExecStopPost=/path/to/iptables -w -D INPUT -p all -j reaction
|
||||
ExecStopPost=/path/to/ip46tables -w -D INPUT -p all -j reaction
|
||||
# Empty the chain
|
||||
ExecStopPost=/path/to/iptables -w -F reaction
|
||||
ExecStopPost=/path/to/ip46tables -w -F reaction
|
||||
# Delete the chain
|
||||
ExecStopPost=/path/to/iptables -w -X reaction
|
||||
ExecStopPost=/path/to/ip46tables -w -X reaction
|
||||
|
||||
# Ask systemd to create /var/lib/reaction (/var/lib/ is implicit)
|
||||
StateDirectory=reaction
|
||||
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
patterns:
|
||||
num:
|
||||
regex: '[0-9]+'
|
||||
ip:
|
||||
regex: '(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})'
|
||||
ignore:
|
||||
- 1.0.0.1
|
||||
|
||||
streams:
|
||||
tailDown1:
|
||||
cmd: [ "sh", "-c", "echo 1 2 3 4 5 1 2 3 4 5 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 | tr ' ' '\n' | while read i; do sleep 2; echo found $(($i % 10)); done" ]
|
||||
filters:
|
||||
findIP:
|
||||
regex:
|
||||
- '^found <num>$'
|
||||
retry: 3
|
||||
retryperiod: 30s
|
||||
actions:
|
||||
damn:
|
||||
cmd: [ "echo", "<num>" ]
|
||||
undamn:
|
||||
cmd: [ "echo", "undamn", "<num>" ]
|
||||
after: 30s
|
||||
onexit: true
|
91
ip46tables.d/ip46tables.c
Normal file
91
ip46tables.d/ip46tables.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include<ctype.h>
|
||||
#include<errno.h>
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#include<unistd.h>
|
||||
|
||||
// If this programs
|
||||
// - receives an ipv4 address in its arguments:
|
||||
// → it will executes iptables with the same arguments in place.
|
||||
//
|
||||
// - receives an ipv6 address in its arguments:
|
||||
// → it will executes ip6tables with the same arguments in place.
|
||||
//
|
||||
// - doesn't receive an ipv4 or ipv6 address in its arguments:
|
||||
// → it will executes both, with the same arguments in place.
|
||||
|
||||
int isIPv4(char *tab) {
|
||||
int i,len;
|
||||
// IPv4 addresses are at least 7 chars long
|
||||
len = strlen(tab);
|
||||
if (len < 7 || !isdigit(tab[0]) || !isdigit(tab[len-1])) {
|
||||
return 0;
|
||||
}
|
||||
// Each char must be a digit or a dot between 2 digits
|
||||
for (i=1; i<len-1; i++) {
|
||||
if (!isdigit(tab[i]) && !(tab[i] == '.' && isdigit(tab[i-1]) && isdigit(tab[i+1]))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int isIPv6(char *tab) {
|
||||
int i,len, twodots = 0;
|
||||
// IPv6 addresses are at least 3 chars long
|
||||
len = strlen(tab);
|
||||
if (len < 3) {
|
||||
return 0;
|
||||
}
|
||||
// Each char must be a digit, :, a-f, or A-F
|
||||
for (i=0; i<len; i++) {
|
||||
if (!isdigit(tab[i]) && tab[i] != ':' && !(tab[i] >= 'a' && tab[i] <= 'f') && !(tab[i] >= 'A' && tab[i] <= 'F')) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int guess_type(int len, char *tab[]) {
|
||||
int i;
|
||||
for (i=0; i<len; i++) {
|
||||
if (isIPv4(tab[i])) {
|
||||
return 4;
|
||||
} else if (isIPv6(tab[i])) {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec(char *str, char **argv) {
|
||||
argv[0] = str;
|
||||
execvp(str, argv);
|
||||
// returns only if fails
|
||||
printf("ip46tables: exec failed %d\n", errno);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("ip46tables: At least one argument has to be given\n");
|
||||
exit(1);
|
||||
}
|
||||
int type;
|
||||
type = guess_type(argc, argv);
|
||||
if (type == 4) {
|
||||
exec("iptables", argv);
|
||||
} else if (type == 6) {
|
||||
exec("ip6tables", argv);
|
||||
} else {
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
printf("ip46tables: fork failed\n");
|
||||
exit(1);
|
||||
} else if (pid) {
|
||||
exec("iptables", argv);
|
||||
} else {
|
||||
exec("ip6tables", argv);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user