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
|
/reaction
|
||||||
|
/ip46tables
|
||||||
/reaction*.db
|
/reaction*.db
|
||||||
/reaction*.sock
|
/reaction*.sock
|
||||||
/result
|
/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:
|
patterns:
|
||||||
ip: '(([0-9]{1,3}\.){3}[0-9]{1,3})|([0-9a-fA-F:]{2,90})'
|
ip: '(([0-9]{1,3}\.){3}[0-9]{1,3})|([0-9a-fA-F:]{2,90})'
|
||||||
ignore:
|
|
||||||
- '127.0.0.1'
|
|
||||||
- '::1'
|
|
||||||
|
|
||||||
streams:
|
streams:
|
||||||
ssh:
|
ssh:
|
||||||
@ -63,7 +60,6 @@ local iptablesunban = ['iptables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-
|
|||||||
patterns: {
|
patterns: {
|
||||||
ip: {
|
ip: {
|
||||||
regex: @'(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})',
|
regex: @'(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})',
|
||||||
ignore: ['127.0.0.1', '::1'],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
streams: {
|
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`
|
`/etc/systemd/system/reaction.service`
|
||||||
```systemd
|
```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`.
|
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
|
### 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
|
```shell
|
||||||
$ go build .
|
$ go build .
|
||||||
|
$ gcc ip46tables.d/ip46tables.c -o ip46tables
|
||||||
```
|
```
|
||||||
|
|
||||||
### nixos
|
### nixos
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
# using YAML anchors `&name` and pointers `*name`
|
# using YAML anchors `&name` and pointers `*name`
|
||||||
# definitions are not readed by reaction
|
# definitions are not readed by reaction
|
||||||
definitions:
|
definitions:
|
||||||
- &iptablesban [ "iptables" "-w" "-A" "reaction" "1" "-s" "<ip>" "-j" "DROP" ]
|
- &iptablesban [ "ip46tables" "-w" "-A" "reaction" "1" "-s" "<ip>" "-j" "DROP" ]
|
||||||
- &iptablesunban [ "iptables" "-w" "-D" "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.
|
# patterns are substitued in regexes.
|
||||||
# when a filter performs an action, it replaces the found pattern
|
# 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.
|
// JSONNET is a superset of JSON, so one can write plain JSON files if wanted.
|
||||||
|
|
||||||
// variables defined for later use.
|
// variables defined for later use.
|
||||||
local iptablesban = ['iptables', '-w', '-A', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
|
local iptablesban = ['ip46tables', '-w', '-A', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
|
||||||
local iptablesunban = ['iptables', '-w', '-D', '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.
|
// patterns are substitued in regexes.
|
||||||
|
@ -7,20 +7,22 @@ WantedBy=multi-user.target
|
|||||||
ExecStart=/path/to/reaction -c /etc/reaction.yml
|
ExecStart=/path/to/reaction -c /etc/reaction.yml
|
||||||
|
|
||||||
# Create an iptables chain for reaction
|
# 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
|
# 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
|
# 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)
|
# 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
|
# 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
|
# Empty the chain
|
||||||
ExecStopPost=/path/to/iptables -w -F reaction
|
ExecStopPost=/path/to/ip46tables -w -F reaction
|
||||||
# Delete the chain
|
# 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)
|
# Ask systemd to create /var/lib/reaction (/var/lib/ is implicit)
|
||||||
StateDirectory=reaction
|
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