]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
SYSRQ target
authorJan Engelhardt <jengelh@computergmbh.de>
Sun, 27 Apr 2008 09:39:24 +0000 (11:39 +0200)
committerJan Engelhardt <jengelh@medozas.de>
Sun, 3 Aug 2008 16:26:09 +0000 (12:26 -0400)
extensions/Kbuild
extensions/Mbuild
extensions/libxt_SYSRQ.c [new file with mode: 0644]
extensions/libxt_SYSRQ.man [new file with mode: 0644]
extensions/xt_SYSRQ.Kconfig [new file with mode: 0644]
extensions/xt_SYSRQ.c [new file with mode: 0644]
mconfig

index e5c01e443a3ac77ec0acac356cd2a1c22b98c9fc..571f3d5657b6a04636ac84def268e8667ca0c99c 100644 (file)
@@ -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
index dbc25b0e7f9c2a23d74e94730766bb586453ab37..9a7fa0e077782dcbc3042447eb042900f7c16a59 100644 (file)
@@ -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
diff --git a/extensions/libxt_SYSRQ.c b/extensions/libxt_SYSRQ.c
new file mode 100644 (file)
index 0000000..6041805
--- /dev/null
@@ -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);
+}
diff --git a/extensions/libxt_SYSRQ.man b/extensions/libxt_SYSRQ.man
new file mode 100644 (file)
index 0000000..91c945d
--- /dev/null
@@ -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.
diff --git a/extensions/xt_SYSRQ.Kconfig b/extensions/xt_SYSRQ.Kconfig
new file mode 100644 (file)
index 0000000..c92fec6
--- /dev/null
@@ -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.
diff --git a/extensions/xt_SYSRQ.c b/extensions/xt_SYSRQ.c
new file mode 100644 (file)
index 0000000..cb12b9f
--- /dev/null
@@ -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");
diff --git a/mconfig b/mconfig
index 8d8fcdcb6412718c8867f5a33e1825db1a85dca4..02bc21c1aafe88a584e07325b34c82d5fb66c4a1 100644 (file)
--- a/mconfig
+++ b/mconfig
@@ -5,6 +5,7 @@ build_DELUDE=m
 build_ECHO=
 build_IPMARK=m
 build_LOGMARK=m
+build_SYSRQ=m
 build_TARPIT=m
 build_TEE=m
 build_condition=m