mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-06 04:35:12 +02:00
pknock: implement automatic closing
Added the optional "--autoclose" parameter (takes minutes) that closes the pknock-opened rule in a specified time. Signed-off-by: Jan Rafaj <jr+netfilter-devel@cedric.unob.cz>
This commit is contained in:

committed by
Jan Engelhardt

parent
284c0e9493
commit
9e5c2e7ee9
@@ -21,8 +21,9 @@ static const struct option pknock_mt_opts[] = {
|
|||||||
/* .name, .has_arg, .flag, .val */
|
/* .name, .has_arg, .flag, .val */
|
||||||
{.name = "knockports", .has_arg = true, .val = 'k'},
|
{.name = "knockports", .has_arg = true, .val = 'k'},
|
||||||
{.name = "time", .has_arg = true, .val = 't'},
|
{.name = "time", .has_arg = true, .val = 't'},
|
||||||
|
{.name = "autoclose", .has_arg = true, .val = 'a'},
|
||||||
{.name = "name", .has_arg = true, .val = 'n'},
|
{.name = "name", .has_arg = true, .val = 'n'},
|
||||||
{.name = "opensecret", .has_arg = true, .val = 'a'},
|
{.name = "opensecret", .has_arg = true, .val = 'o'},
|
||||||
{.name = "closesecret", .has_arg = true, .val = 'z'},
|
{.name = "closesecret", .has_arg = true, .val = 'z'},
|
||||||
{.name = "strict", .has_arg = false, .val = 'x'},
|
{.name = "strict", .has_arg = false, .val = 'x'},
|
||||||
{.name = "checkip", .has_arg = false, .val = 'c'},
|
{.name = "checkip", .has_arg = false, .val = 'c'},
|
||||||
@@ -36,6 +37,9 @@ static void pknock_mt_help(void)
|
|||||||
"Matches destination port(s).\n"
|
"Matches destination port(s).\n"
|
||||||
" --time seconds\n"
|
" --time seconds\n"
|
||||||
"Max allowed time between knocks.\n"
|
"Max allowed time between knocks.\n"
|
||||||
|
" --autoclose minutes\n"
|
||||||
|
"Time after which to automatically close opened\n"
|
||||||
|
"\t\t\t\t\tport(s).\n"
|
||||||
" --strict "
|
" --strict "
|
||||||
"Knocks sequence must be exact.\n"
|
"Knocks sequence must be exact.\n"
|
||||||
" --name rule_name "
|
" --name rule_name "
|
||||||
@@ -106,6 +110,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
{
|
{
|
||||||
const char *proto;
|
const char *proto;
|
||||||
struct xt_pknock_mtinfo *info = (void *)(*match)->data;
|
struct xt_pknock_mtinfo *info = (void *)(*match)->data;
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'k': /* --knockports */
|
case 'k': /* --knockports */
|
||||||
@@ -131,6 +136,18 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
*flags |= XT_PKNOCK_TIME;
|
*flags |= XT_PKNOCK_TIME;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'a': /* --autoclose */
|
||||||
|
if (*flags & XT_PKNOCK_AUTOCLOSE)
|
||||||
|
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
||||||
|
"cannot use --autoclose twice.\n");
|
||||||
|
if (!xtables_strtoui(optarg, NULL, &tmp, 0, ~0U))
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, PKNOCK,
|
||||||
|
"--autoclose", optarg);
|
||||||
|
info->autoclose_time = tmp;
|
||||||
|
info->option |= XT_PKNOCK_AUTOCLOSE;
|
||||||
|
*flags |= XT_PKNOCK_AUTOCLOSE;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'n': /* --name */
|
case 'n': /* --name */
|
||||||
if (*flags & XT_PKNOCK_NAME)
|
if (*flags & XT_PKNOCK_NAME)
|
||||||
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
||||||
@@ -146,7 +163,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a': /* --opensecret */
|
case 'o': /* --opensecret */
|
||||||
if (*flags & XT_PKNOCK_OPENSECRET)
|
if (*flags & XT_PKNOCK_OPENSECRET)
|
||||||
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
||||||
"cannot use --opensecret twice.\n");
|
"cannot use --opensecret twice.\n");
|
||||||
@@ -236,6 +253,9 @@ static void pknock_mt_check(unsigned int flags)
|
|||||||
if (flags & XT_PKNOCK_TIME)
|
if (flags & XT_PKNOCK_TIME)
|
||||||
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
||||||
"cannot specify --time with --checkip.\n");
|
"cannot specify --time with --checkip.\n");
|
||||||
|
if (flags & XT_PKNOCK_AUTOCLOSE)
|
||||||
|
xtables_error(PARAMETER_PROBLEM, PKNOCK
|
||||||
|
"cannot specify --autoclose with --checkip.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +274,8 @@ static void pknock_mt_print(const void *ip,
|
|||||||
}
|
}
|
||||||
if (info->option & XT_PKNOCK_TIME)
|
if (info->option & XT_PKNOCK_TIME)
|
||||||
printf("time %ld ", (long)info->max_time);
|
printf("time %ld ", (long)info->max_time);
|
||||||
|
if (info->option & XT_PKNOCK_AUTOCLOSE)
|
||||||
|
printf("autoclose %lu ", (unsigned long)info->autoclose_time);
|
||||||
if (info->option & XT_PKNOCK_NAME)
|
if (info->option & XT_PKNOCK_NAME)
|
||||||
printf("name %s ", info->rule_name);
|
printf("name %s ", info->rule_name);
|
||||||
if (info->option & XT_PKNOCK_OPENSECRET)
|
if (info->option & XT_PKNOCK_OPENSECRET)
|
||||||
@@ -279,6 +301,9 @@ static void pknock_mt_save(const void *ip, const struct xt_entry_match *match)
|
|||||||
}
|
}
|
||||||
if (info->option & XT_PKNOCK_TIME)
|
if (info->option & XT_PKNOCK_TIME)
|
||||||
printf("--time %ld ", (long)info->max_time);
|
printf("--time %ld ", (long)info->max_time);
|
||||||
|
if (info->option & XT_PKNOCK_AUTOCLOSE)
|
||||||
|
printf("--autoclose %lu ",
|
||||||
|
(unsigned long)info->autoclose_time);
|
||||||
if (info->option & XT_PKNOCK_NAME)
|
if (info->option & XT_PKNOCK_NAME)
|
||||||
printf("--name %s ", info->rule_name);
|
printf("--name %s ", info->rule_name);
|
||||||
if (info->option & XT_PKNOCK_OPENSECRET)
|
if (info->option & XT_PKNOCK_OPENSECRET)
|
||||||
|
@@ -68,6 +68,7 @@ struct xt_pknock_rule {
|
|||||||
struct list_head *peer_head;
|
struct list_head *peer_head;
|
||||||
struct proc_dir_entry *status_proc;
|
struct proc_dir_entry *status_proc;
|
||||||
unsigned long max_time;
|
unsigned long max_time;
|
||||||
|
unsigned long autoclose_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,6 +245,7 @@ pknock_seq_show(struct seq_file *s, void *v)
|
|||||||
{
|
{
|
||||||
const struct list_head *pos, *n;
|
const struct list_head *pos, *n;
|
||||||
const struct peer *peer;
|
const struct peer *peer;
|
||||||
|
unsigned long time;
|
||||||
unsigned long expir_time;
|
unsigned long expir_time;
|
||||||
|
|
||||||
const struct list_head *peer_head = v;
|
const struct list_head *peer_head = v;
|
||||||
@@ -264,6 +266,15 @@ pknock_seq_show(struct seq_file *s, void *v)
|
|||||||
seq_printf(s, "expir_time=%ld ", expir_time);
|
seq_printf(s, "expir_time=%ld ", expir_time);
|
||||||
seq_printf(s, "accepted_knock_count=%lu ",
|
seq_printf(s, "accepted_knock_count=%lu ",
|
||||||
(unsigned long)peer->accepted_knock_count);
|
(unsigned long)peer->accepted_knock_count);
|
||||||
|
if (rule->autoclose_time != 0) {
|
||||||
|
time = 0;
|
||||||
|
if (time_before(get_seconds(), peer->login_sec +
|
||||||
|
rule->autoclose_time * 60))
|
||||||
|
time = peer->login_sec +
|
||||||
|
rule->autoclose_time * 60 -
|
||||||
|
get_seconds();
|
||||||
|
seq_printf(s, "autoclose_time=%lu [secs] ", time);
|
||||||
|
}
|
||||||
seq_printf(s, "\n");
|
seq_printf(s, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +325,19 @@ static void update_rule_timer(struct xt_pknock_rule *rule)
|
|||||||
add_timer(&rule->timer);
|
add_timer(&rule->timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @peer
|
||||||
|
* @autoclose_time
|
||||||
|
*
|
||||||
|
* Returns true if autoclose due, or false if still valid.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
autoclose_time_passed(const struct peer *peer, unsigned int autoclose_time)
|
||||||
|
{
|
||||||
|
return peer != NULL && autoclose_time != 0 && time_after(get_seconds(),
|
||||||
|
peer->login_sec + autoclose_time * 60);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @peer
|
* @peer
|
||||||
* @max_time
|
* @max_time
|
||||||
@@ -352,8 +376,10 @@ peer_gc(unsigned long r)
|
|||||||
hashtable_for_each_safe(pos, n, rule->peer_head, peer_hashsize, i) {
|
hashtable_for_each_safe(pos, n, rule->peer_head, peer_hashsize, i) {
|
||||||
peer = list_entry(pos, struct peer, head);
|
peer = list_entry(pos, struct peer, head);
|
||||||
|
|
||||||
if (!has_logged_during_this_minute(peer) &&
|
if ((!has_logged_during_this_minute(peer) &&
|
||||||
is_time_exceeded(peer, rule->max_time))
|
is_time_exceeded(peer, rule->max_time)) ||
|
||||||
|
(peer->status == ST_ALLOWED &&
|
||||||
|
autoclose_time_passed(peer, rule->autoclose_time)))
|
||||||
{
|
{
|
||||||
pk_debug("DESTROYED", peer);
|
pk_debug("DESTROYED", peer);
|
||||||
list_del(pos);
|
list_del(pos);
|
||||||
@@ -440,9 +466,10 @@ add_rule(struct xt_pknock_mtinfo *info)
|
|||||||
strncpy(rule->rule_name, info->rule_name, info->rule_name_len);
|
strncpy(rule->rule_name, info->rule_name, info->rule_name_len);
|
||||||
rule->rule_name_len = info->rule_name_len;
|
rule->rule_name_len = info->rule_name_len;
|
||||||
|
|
||||||
rule->ref_count = 1;
|
rule->ref_count = 1;
|
||||||
rule->max_time = info->max_time;
|
rule->max_time = info->max_time;
|
||||||
rule->peer_head = alloc_hashtable(peer_hashsize);
|
rule->autoclose_time = info->autoclose_time;
|
||||||
|
rule->peer_head = alloc_hashtable(peer_hashsize);
|
||||||
if (rule->peer_head == NULL)
|
if (rule->peer_head == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -994,7 +1021,7 @@ static bool pknock_mt(const struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_first_knock(peer, info, hdr.port)) {
|
if (is_first_knock(peer, info, hdr.port)) {
|
||||||
@@ -1008,7 +1035,16 @@ static bool pknock_mt(const struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret != 0)
|
/* Handle cur.peer matching and deletion after autoclose_time passed */
|
||||||
|
if (ret && autoclose_time_passed(peer, rule->autoclose_time)) {
|
||||||
|
pk_debug("AUTOCLOSE TIME PASSED => BLOCKED", peer);
|
||||||
|
ret = false;
|
||||||
|
if (iph->protocol == IPPROTO_TCP ||
|
||||||
|
!has_logged_during_this_minute(peer))
|
||||||
|
remove_peer(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
pk_debug("PASS OK", peer);
|
pk_debug("PASS OK", peer);
|
||||||
spin_unlock_bh(&list_lock);
|
spin_unlock_bh(&list_lock);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1061,6 +1097,8 @@ static bool pknock_mt_check(const struct xt_mtchk_param *par)
|
|||||||
#endif
|
#endif
|
||||||
if (info->option & XT_PKNOCK_TIME)
|
if (info->option & XT_PKNOCK_TIME)
|
||||||
RETURN_ERR("Can't specify --time with --checkip.\n");
|
RETURN_ERR("Can't specify --time with --checkip.\n");
|
||||||
|
if (info->option & XT_PKNOCK_AUTOCLOSE)
|
||||||
|
RETURN_ERR("Can't specify --autoclose with --checkip.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PK_CRYPTO
|
#ifdef PK_CRYPTO
|
||||||
|
@@ -21,6 +21,7 @@ enum {
|
|||||||
XT_PKNOCK_CHECKIP = 1 << 4,
|
XT_PKNOCK_CHECKIP = 1 << 4,
|
||||||
XT_PKNOCK_OPENSECRET = 1 << 5,
|
XT_PKNOCK_OPENSECRET = 1 << 5,
|
||||||
XT_PKNOCK_CLOSESECRET = 1 << 6,
|
XT_PKNOCK_CLOSESECRET = 1 << 6,
|
||||||
|
XT_PKNOCK_AUTOCLOSE = 1 << 7,
|
||||||
|
|
||||||
/* Can never change these, as they are make up the user protocol. */
|
/* Can never change these, as they are make up the user protocol. */
|
||||||
XT_PKNOCK_MAX_PORTS = 15,
|
XT_PKNOCK_MAX_PORTS = 15,
|
||||||
@@ -41,6 +42,7 @@ struct xt_pknock_mtinfo {
|
|||||||
uint8_t ports_count; /* number of ports */
|
uint8_t ports_count; /* number of ports */
|
||||||
uint16_t port[XT_PKNOCK_MAX_PORTS]; /* port[,port,port,...] */
|
uint16_t port[XT_PKNOCK_MAX_PORTS]; /* port[,port,port,...] */
|
||||||
uint32_t max_time; /* max matching time between ports */
|
uint32_t max_time; /* max matching time between ports */
|
||||||
|
uint32_t autoclose_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xt_pknock_nl_msg {
|
struct xt_pknock_nl_msg {
|
||||||
|
Reference in New Issue
Block a user