mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-07 05:05:12 +02:00
Merge branch 'pknock'
This commit is contained in:
@@ -19,6 +19,7 @@ HEAD
|
|||||||
- pknock: check interknock time only for !ST_ALLOWED peers
|
- pknock: check interknock time only for !ST_ALLOWED peers
|
||||||
- pknock: preserve time/autoclose values for rules added in
|
- pknock: preserve time/autoclose values for rules added in
|
||||||
reverse/arbitrary order
|
reverse/arbitrary order
|
||||||
|
- pknock: add a manpage
|
||||||
|
|
||||||
|
|
||||||
Xtables-addons 1.18 (September 09 2009)
|
Xtables-addons 1.18 (September 09 2009)
|
||||||
|
113
extensions/libxt_pknock.man
Normal file
113
extensions/libxt_pknock.man
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
Pknock match implements so-called "port knocking", a stealthy system
|
||||||
|
for network authentication: a client sends packets to selected
|
||||||
|
ports in a specific sequence (= simple mode, see example 1 below), or a HMAC
|
||||||
|
payload to a single port (= complex mode, see example 2 below),
|
||||||
|
to a target machine that has pknock rule(s) installed. The target machine
|
||||||
|
then decides whether to unblock or block (again) the pknock-protected port(s).
|
||||||
|
This can be used, for instance, to avoid brute force
|
||||||
|
attacks on ssh or ftp services.
|
||||||
|
.PP
|
||||||
|
Example prerequisites:
|
||||||
|
.IP
|
||||||
|
modprobe cn
|
||||||
|
.IP
|
||||||
|
modprobe xt_pknock
|
||||||
|
.PP
|
||||||
|
Example 1 (TCP mode, manual closing of opened port not possible):
|
||||||
|
.IP
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
.IP
|
||||||
|
iptables -A INPUT -p tcp -m pknock --knockports 4002,4001,4004 --strict
|
||||||
|
--name SSH --time 10 --autoclose 60 --dport 22 -j ACCEPT
|
||||||
|
.PP
|
||||||
|
The rule will allow tcp port 22 for the attempting IP address after the successful reception of TCP SYN packets
|
||||||
|
to ports 4002, 4001 and 4004, in this order (a.k.a. port-knocking).
|
||||||
|
Port numbers in the connect sequence must follow the exact specification, no
|
||||||
|
other ports may be "knocked" inbetween. The rule is named '\fBSSH\fP' \(em a file of
|
||||||
|
the same name for tracking port knocking states will be created in
|
||||||
|
\fB/proc/net/xt_pknock\fP .
|
||||||
|
Successive port knocks must occur with delay of at most 10 seconds. Port 22 (from the example) will
|
||||||
|
be automatiaclly dropped after 60 minutes after it was previously allowed.
|
||||||
|
.PP
|
||||||
|
Example 2 (UDP mode \(em non-replayable and non-spoofable, manual closing
|
||||||
|
of opened port possible, secure, also called "SPA" = Secure Port
|
||||||
|
Authorization):
|
||||||
|
.IP
|
||||||
|
iptables -A INPUT -p udp -m pknock --knockports 4000 --name FTP
|
||||||
|
--opensecret foo --closesecret bar --autoclose 240 -j DROP
|
||||||
|
.IP
|
||||||
|
iptables -A INPUT -p tcp -m pknock --checkip --name FTP --dport 21 -j ACCEPT
|
||||||
|
.PP
|
||||||
|
The first rule will create an "ALLOWED" record in /proc/net/xt_pknock/FTP after
|
||||||
|
the successful reception of an UDP packet to port 4000. The packet payload must be
|
||||||
|
constructed as a HMAC256 using "foo" as a key. The HMAC content is the particular client's IP address as a 32-bit network byteorder quantity,
|
||||||
|
plus the number of minutes since the Unix epoch, also as a 32-bit value.
|
||||||
|
(This is known as Simple Packet Authorization, also called "SPA".)
|
||||||
|
In such case, any subsequent attempt to connect to port 21 from the client's IP
|
||||||
|
address will cause such packets to be accepted in the second rule.
|
||||||
|
.PP
|
||||||
|
Similarly, upon reception of an UDP packet constructed the same way, but with
|
||||||
|
the key "bar", the first rule will remove a previously installed "ALLOWED" state
|
||||||
|
record from /proc/net/xt_pknock/FTP, which means that the second rule will
|
||||||
|
stop matching for subsequent connection attempts to port 21.
|
||||||
|
In case no close-secret packet is received within 4 hours, the first rule
|
||||||
|
will remove "ALLOWED" record from /proc/net/xt_pknock/FTP itself.
|
||||||
|
.PP
|
||||||
|
Things worth noting:
|
||||||
|
.PP
|
||||||
|
\fBGeneral\fP:
|
||||||
|
.PP
|
||||||
|
Specifying \fB--autoclose 0\fP means that no automatic close will be performed at all.
|
||||||
|
.PP
|
||||||
|
xt_pknock is capable of sending information about successful matches
|
||||||
|
via a netlink socket to userspace, should you need to implement your own
|
||||||
|
way of receiving and handling portknock notifications.
|
||||||
|
Be sure to read the documentation in the doc/pknock/ directory,
|
||||||
|
or visit the original site \(em http://portknocko.berlios.de/ .
|
||||||
|
.PP
|
||||||
|
\fBTCP mode\fP:
|
||||||
|
.PP
|
||||||
|
This mode is not immune against eavesdropping, spoofing and
|
||||||
|
replaying of the port knock sequence by someone else (but its use may still
|
||||||
|
be sufficient for scenarios where these factors are not necessarily
|
||||||
|
this important, such as bare shielding of the SSH port from brute-force attacks).
|
||||||
|
However, if you need these features, you should use UDP mode.
|
||||||
|
.PP
|
||||||
|
It is always wise to specify three or more ports that are not monotonically
|
||||||
|
increasing or decreasing with a small stepsize (e.g. 1024,1025,1026)
|
||||||
|
to avoid accidentally triggering
|
||||||
|
the rule by a portscan.
|
||||||
|
.PP
|
||||||
|
Specifying the inter-knock timeout with \fB--time\fP is mandatory in TCP mode,
|
||||||
|
to avoid permanent denial of services by clogging up the peer knock-state tracking table
|
||||||
|
that xt_pknock internally keeps, should there be a DDoS on the
|
||||||
|
first-in-row knock port from more hostile IP addresses than what the actual size
|
||||||
|
of this table is (defaults to 16, can be changed via the "peer_hasht_ents" module parameter).
|
||||||
|
It is also wise to use as short a time as possible (1 second) for \fB--time\fP
|
||||||
|
for this very reason. You may also consider increasing the size
|
||||||
|
of the peer knock-state tracking table. Using \fB--strict\fP also helps,
|
||||||
|
as it requires the knock sequence to be exact. This means that if the
|
||||||
|
hostile client sends more knocks to the same port, xt_pknock will
|
||||||
|
mark such attempt as failed knock sequence and will forget it immediately.
|
||||||
|
To completely thwart this kind of DDoS, knock-ports would need to have
|
||||||
|
an additional rate-limit protection. Or you may consider using UDP mode.
|
||||||
|
.PP
|
||||||
|
\fBUDP mode\fP:
|
||||||
|
.PP
|
||||||
|
This mode is immune against eavesdropping, replaying and spoofing attacks.
|
||||||
|
It is also immune against DDoS attack on the knockport.
|
||||||
|
.PP
|
||||||
|
For this mode to work, the clock difference on the client and on the server
|
||||||
|
must be below 1 minute. Synchronizing time on both ends by means
|
||||||
|
of NTP or rdate is strongly suggested.
|
||||||
|
.PP
|
||||||
|
There is a rate limiter built into xt_pknock which blocks any subsequent
|
||||||
|
open attempt in UDP mode should the request arrive within less than one
|
||||||
|
minute since the first successful open. This is intentional;
|
||||||
|
it thwarts eventual spoofing attacks.
|
||||||
|
.PP
|
||||||
|
Because the payload value of an UDP knock packet is influenced by client's IP address,
|
||||||
|
UDP mode cannot be used across NAT.
|
||||||
|
.PP
|
||||||
|
For sending UDP "SPA" packets, you may use either \fBknock.sh\fP or
|
||||||
|
\fBknock-orig.sh\fP. These may be found in doc/pknock/util.
|
1
extensions/pknock/.gitignore
vendored
Normal file
1
extensions/pknock/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/pknlusr
|
@@ -1,3 +1,5 @@
|
|||||||
# -*- Makefile -*-
|
# -*- Makefile -*-
|
||||||
|
|
||||||
include ../../Makefile.extra
|
include ../../Makefile.extra
|
||||||
|
|
||||||
|
noinst_PROGRAMS = pknlusr
|
||||||
|
93
extensions/pknock/pknlusr.c
Normal file
93
extensions/pknock/pknlusr.c
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/connector.h>
|
||||||
|
|
||||||
|
#include "xt_pknock.h"
|
||||||
|
|
||||||
|
#define GROUP 1
|
||||||
|
|
||||||
|
static struct sockaddr_nl src_addr, dest_addr;
|
||||||
|
static struct msghdr msg;
|
||||||
|
static int sock_fd;
|
||||||
|
|
||||||
|
static unsigned char *buf;
|
||||||
|
|
||||||
|
static struct xt_pknock_nl_msg *nlmsg;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
socklen_t addrlen;
|
||||||
|
int status;
|
||||||
|
int group = GROUP;
|
||||||
|
struct cn_msg *cnmsg;
|
||||||
|
|
||||||
|
int i, buf_size;
|
||||||
|
|
||||||
|
const char *ip;
|
||||||
|
char ipbuf[48];
|
||||||
|
|
||||||
|
sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
|
||||||
|
|
||||||
|
if (sock_fd == -1) {
|
||||||
|
perror("socket()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&src_addr, 0, sizeof(src_addr));
|
||||||
|
src_addr.nl_family = AF_NETLINK;
|
||||||
|
src_addr.nl_pid = getpid();
|
||||||
|
src_addr.nl_groups = group;
|
||||||
|
|
||||||
|
status = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
|
||||||
|
|
||||||
|
if (status == -1) {
|
||||||
|
close(sock_fd);
|
||||||
|
perror("bind()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&dest_addr, 0, sizeof(dest_addr));
|
||||||
|
dest_addr.nl_family = AF_NETLINK;
|
||||||
|
dest_addr.nl_pid = 0;
|
||||||
|
dest_addr.nl_groups = group;
|
||||||
|
|
||||||
|
buf_size = sizeof(struct xt_pknock_nl_msg) + sizeof(struct cn_msg) + sizeof(struct nlmsghdr);
|
||||||
|
buf = malloc(buf_size);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
perror("malloc()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addrlen = sizeof(dest_addr);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
|
||||||
|
memset(buf, 0, buf_size);
|
||||||
|
|
||||||
|
status = recvfrom(sock_fd, buf, buf_size, 0, (struct sockaddr *)&dest_addr, &addrlen);
|
||||||
|
|
||||||
|
if (status <= 0) {
|
||||||
|
perror("recvfrom()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlmsg = (struct xt_pknock_nl_msg *) (buf + sizeof(struct cn_msg) + sizeof(struct nlmsghdr));
|
||||||
|
|
||||||
|
ip = inet_ntop(AF_INET, &nlmsg->peer_ip, ipbuf, sizeof(ipbuf));
|
||||||
|
printf("rule_name: %s - ip %s\n", nlmsg->rule_name, ip);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock_fd);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user