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
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
--- /dev/null
+/*
+ * "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);
+}
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+/*
+ * "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");
build_ECHO=
build_IPMARK=m
build_LOGMARK=m
+build_SYSRQ=m
build_TARPIT=m
build_TEE=m
build_condition=m