mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-06 12:45:13 +02:00
SYSRQ target
This commit is contained in:

committed by
Jan Engelhardt

parent
74880dd6ca
commit
039741e022
@@ -10,6 +10,7 @@ obj-${build_DELUDE} += xt_DELUDE.o
|
||||
obj-${build_ECHO} += xt_ECHO.o
|
||||
obj-${build_IPMARK} += xt_IPMARK.o
|
||||
obj-${build_LOGMARK} += xt_LOGMARK.o
|
||||
obj-${build_SYSRQ} += xt_SYSRQ.o
|
||||
obj-${build_TARPIT} += xt_TARPIT.o
|
||||
obj-${build_TEE} += xt_TEE.o
|
||||
obj-${build_condition} += xt_condition.o
|
||||
|
@@ -3,6 +3,7 @@ obj-${build_DELUDE} += libxt_DELUDE.so
|
||||
obj-${build_ECHO} += libxt_ECHO.so
|
||||
obj-${build_IPMARK} += libxt_IPMARK.so
|
||||
obj-${build_LOGMARK} += libxt_LOGMARK.so
|
||||
obj-${build_SYSRQ} += libxt_SYSRQ.so
|
||||
obj-${build_TARPIT} += libxt_TARPIT.so
|
||||
obj-${build_TEE} += libxt_TEE.so
|
||||
obj-${build_condition} += libxt_condition.so
|
||||
|
50
extensions/libxt_SYSRQ.c
Normal file
50
extensions/libxt_SYSRQ.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* "SYSRQ" target extension to iptables
|
||||
* this file is in the Public Domain
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
|
||||
static void sysrq_tg_help(void)
|
||||
{
|
||||
printf("SYSRQ takes no options\n\n");
|
||||
}
|
||||
|
||||
static int sysrq_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sysrq_tg_check(unsigned int flags)
|
||||
{
|
||||
}
|
||||
|
||||
static struct xtables_target sysrq_tg4_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "SYSRQ",
|
||||
.family = PF_INET,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.help = sysrq_tg_help,
|
||||
.parse = sysrq_tg_parse,
|
||||
.final_check = sysrq_tg_check,
|
||||
};
|
||||
|
||||
static struct xtables_target sysrq_tg6_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "SYSRQ",
|
||||
.family = PF_INET6,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.help = sysrq_tg_help,
|
||||
.parse = sysrq_tg_parse,
|
||||
.final_check = sysrq_tg_check,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_target(&sysrq_tg4_reg);
|
||||
xtables_register_target(&sysrq_tg6_reg);
|
||||
}
|
47
extensions/libxt_SYSRQ.man
Normal file
47
extensions/libxt_SYSRQ.man
Normal file
@@ -0,0 +1,47 @@
|
||||
The SYSRQ target allows to remotely trigger sysrq on the local machine over the
|
||||
network. This can be useful when vital parts of the machine hang, for example
|
||||
an oops in a filesystem causing locks to be not released and processes to get
|
||||
stuck as a result -- if still possible, use /proc/sysrq-trigger. Even when
|
||||
processes are stuck, interrupts are likely to be still processed, and as such,
|
||||
sysrq can be triggered through incoming network packets.
|
||||
.PP
|
||||
This xt_SYSRQ implementation does not use any encryption, so you should change
|
||||
the SYSRQ password after use unless you have made sure it was transmitted
|
||||
securely and no one sniffed the network, e.g. by use of an IPsec tunnel whose
|
||||
endpoint is at the machine where you want to trigger the sysrq. Also, you
|
||||
should limit as to who can issue commands using \fB-s\fP and/or \fB-m mac\fP,
|
||||
and also that the destination is correct using \fB-d\fP (to protect against
|
||||
potential broadcast packets), noting that it is still short of MAC/IP spoofing:
|
||||
.IP
|
||||
-A INPUT -s 10.10.25.1 -m mac --mac-source aa:bb:cc:dd:ee:ff -d 10.10.25.7
|
||||
-p udp --dport 9 -j SYSRQ
|
||||
.IP
|
||||
(with IPsec) -A INPUT -s 10.10.25.1 -d 10.10.25.7 -m policy --dir in --pol
|
||||
ipsec --proto esp --tunnel-src 10.10.25.1 --tunnel-dst 10.10.25.7
|
||||
-p udp --dport 9 -j SYSRQ
|
||||
.PP
|
||||
This extension does not take any options. The \fB-p udp\fP options are
|
||||
required.
|
||||
.PP
|
||||
The SYSRQ password can be changed through
|
||||
/sys/module/xt_SYSRQ/parameters/password; note you need to use `echo -n` to
|
||||
not add a newline to the password, i.e.
|
||||
.IP
|
||||
echo -n "password" >/sys/.../password
|
||||
.PP
|
||||
Alternatively, the password may be specified at modprobe time, but this is
|
||||
insecure as people can possible see it through ps(1). You can use an option
|
||||
line in /etc/modprobe.d/sysrq if it is properly guarded, that is, only readable
|
||||
by root.
|
||||
.IP
|
||||
options xt_SYSRQ password=cookies
|
||||
.PP
|
||||
To trigger SYSRQ from a remote host, just use netcat or socat, specifying the
|
||||
action (only one) as first character, followed by the password:
|
||||
.IP
|
||||
echo -n "scookies" | socat stdin udp-sendto:10.10.25.7:9
|
||||
.IP
|
||||
echo -n "scookies" | netcat -u 10.10.25.7 9
|
||||
.PP
|
||||
See the Linux docs for possible sysrq keys. Important ones are:
|
||||
re(b)oot, power(o)ff, (s)ync filesystems, (u)mount and remount readonly.
|
8
extensions/xt_SYSRQ.Kconfig
Normal file
8
extensions/xt_SYSRQ.Kconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
config NETFILTER_XT_TARGET_SYSRQ
|
||||
tristate '"SYSRQ" target support'
|
||||
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
|
||||
---help---
|
||||
The SYSRQ target allows to remotely trigger sysrq on the
|
||||
local machine over the network. This can be useful when vital
|
||||
parts of the machine hang and sysrq cannot be triggered
|
||||
through, for example, the shell.
|
158
extensions/xt_SYSRQ.c
Normal file
158
extensions/xt_SYSRQ.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* "SYSRQ" target extension for Netfilter
|
||||
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
|
||||
*
|
||||
* Based upon the ipt_SYSRQ idea by Marek Zalem <marek [at] terminus sk>
|
||||
* xt_SYSRQ does not use hashing or timestamps.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 or 3 as published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/ip.h>
|
||||
#include "compat_xtables.h"
|
||||
|
||||
static bool sysrq_once;
|
||||
static char sysrq_password[64];
|
||||
module_param_string(password, sysrq_password, sizeof(sysrq_password),
|
||||
S_IRUSR | S_IWUSR);
|
||||
MODULE_PARM_DESC(password, "password for remote sysrq");
|
||||
|
||||
static unsigned int sysrq_tg(const void *pdata, uint16_t len)
|
||||
{
|
||||
const char *data = pdata;
|
||||
char c;
|
||||
|
||||
if (*sysrq_password == '\0') {
|
||||
if (!sysrq_once)
|
||||
printk(KERN_INFO KBUILD_MODNAME "No password set\n");
|
||||
sysrq_once = true;
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
return NF_DROP;
|
||||
|
||||
c = *data;
|
||||
if (strncmp(&data[1], sysrq_password, len - 1) != 0) {
|
||||
printk(KERN_INFO KBUILD_MODNAME "Failed attempt - "
|
||||
"password mismatch\n");
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
handle_sysrq(c, NULL);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static unsigned int sysrq_tg4(struct sk_buff *skb, const struct net_device *in,
|
||||
const struct net_device *out, unsigned int hooknum,
|
||||
const struct xt_target *target, const void *targinfo)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
const struct udphdr *udph;
|
||||
uint16_t len;
|
||||
|
||||
if (skb_linearize(skb) < 0)
|
||||
return NF_DROP;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
udph = (void *)iph + ip_hdrlen(skb);
|
||||
len = ntohs(udph->len) - sizeof(struct udphdr);
|
||||
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " NIPQUAD_FMT ":%u -> :%u len=%u\n",
|
||||
NIPQUAD(iph->saddr), htons(udph->source), htons(udph->dest),
|
||||
len);
|
||||
return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
|
||||
}
|
||||
|
||||
static unsigned int sysrq_tg6(struct sk_buff *skb, const struct net_device *in,
|
||||
const struct net_device *out, unsigned int hooknum,
|
||||
const struct xt_target *target, const void *targinfo)
|
||||
{
|
||||
const struct ipv6hdr *iph;
|
||||
const struct udphdr *udph;
|
||||
uint16_t len;
|
||||
|
||||
if (skb_linearize(skb) < 0)
|
||||
return NF_DROP;
|
||||
|
||||
iph = ipv6_hdr(skb);
|
||||
udph = udp_hdr(skb);
|
||||
len = ntohs(udph->len) - sizeof(struct udphdr);
|
||||
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " NIP6_FMT ":%hu -> :%hu len=%u\n",
|
||||
NIP6(iph->saddr), ntohs(udph->source),
|
||||
ntohs(udph->dest), len);
|
||||
return sysrq_tg(udph + sizeof(struct udphdr), len);
|
||||
}
|
||||
|
||||
static bool sysrq_tg_check(const char *table, const void *ventry,
|
||||
const struct xt_target *target, void *targinfo, unsigned int hook_mask)
|
||||
{
|
||||
if (target->family == PF_INET) {
|
||||
const struct ipt_entry *entry = ventry;
|
||||
|
||||
if ((entry->ip.proto != IPPROTO_UDP &&
|
||||
entry->ip.proto != IPPROTO_UDPLITE) ||
|
||||
entry->ip.invflags & XT_INV_PROTO)
|
||||
goto out;
|
||||
} else if (target->family == PF_INET6) {
|
||||
const struct ip6t_entry *entry = ventry;
|
||||
|
||||
if ((entry->ipv6.proto != IPPROTO_UDP &&
|
||||
entry->ipv6.proto != IPPROTO_UDPLITE) ||
|
||||
entry->ipv6.invflags & XT_INV_PROTO)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
out:
|
||||
printk(KERN_ERR KBUILD_MODNAME ": only available for UDP and UDP-Lite");
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct xt_target sysrq_tg_reg[] __read_mostly = {
|
||||
{
|
||||
.name = "SYSRQ",
|
||||
.family = PF_INET,
|
||||
.revision = 0,
|
||||
.target = sysrq_tg4,
|
||||
.checkentry = sysrq_tg_check,
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
{
|
||||
.name = "SYSRQ",
|
||||
.family = PF_INET6,
|
||||
.revision = 0,
|
||||
.target = sysrq_tg6,
|
||||
.checkentry = sysrq_tg_check,
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init sysrq_tg_init(void)
|
||||
{
|
||||
return xt_register_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg));
|
||||
}
|
||||
|
||||
static void __exit sysrq_tg_exit(void)
|
||||
{
|
||||
return xt_unregister_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg));
|
||||
}
|
||||
|
||||
module_init(sysrq_tg_init);
|
||||
module_exit(sysrq_tg_exit);
|
||||
MODULE_DESCRIPTION("Xtables: triggering SYSRQ remotely");
|
||||
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
|
||||
MODULE_LICENSE("GPL");
|
Reference in New Issue
Block a user