--- /dev/null
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <xtables.h>
+#include "xt_LOGMARK.h"
+
+enum {
+ F_LEVEL = 1 << 0,
+ F_PREFIX = 1 << 1,
+ F_NFMARK = 1 << 2,
+ F_CTMARK = 1 << 3,
+ F_SECMARK = 1 << 4,
+};
+
+static const struct option logmark_tg_opts[] = {
+ {.name = "log-level", .has_arg = true, .val = 'l'},
+ {.name = "log-prefix", .has_arg = true, .val = 'p'},
+ {.name = "log-nfmark", .has_arg = false, .val = 'n'},
+ {.name = "log-ctmark", .has_arg = false, .val = 'c'},
+ {.name = "log-secmark", .has_arg = false, .val = 's'},
+ {},
+};
+
+static void logmark_tg_help(void)
+{
+ printf(
+"LOGMARK target options:\n"
+" --log-level level Level of logging (numeric, 0-8)\n"
+" --log-prefix prefix Prefix log messages with this string\n"
+" --log-nfmark Log the packet mark\n"
+" --log-ctmark Log the connection mark\n"
+" --log-secmark Log the security mark of the packet\n"
+);
+}
+
+static void logmark_tg_init(struct xt_entry_target *target)
+{
+ struct xt_logmark_tginfo *info = (void *)target->data;
+
+ info->level = 4;
+ *info->prefix = '\0';
+}
+
+static int
+logmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct xt_logmark_tginfo *info = (void *)(*target)->data;
+ unsigned int x;
+
+ switch (c) {
+ case 'l': /* --log-level */
+ param_act(P_ONLY_ONCE, "LOGMARK", "--log-level", *flags & F_LEVEL);
+ param_act(P_NO_INVERT, "LOGMARK", "--log-level", invert);
+ if (!strtonum(optarg, NULL, &x, 0, 8))
+ param_act(P_BAD_VALUE, "LOGMARK", "--log-level", optarg);
+ info->level = x;
+ *flags |= F_LEVEL;
+ return true;
+
+ case 'p': /* --log-prefix */
+ param_act(P_ONLY_ONCE, "LOGMARK", "--log-prefix", *flags & F_PREFIX);
+ param_act(P_NO_INVERT, "LOGMARK", "--log-prefix", invert);
+ if (strlen(optarg) > sizeof(info->prefix))
+ exit_error(PARAMETER_PROBLEM, "LOGMARK: Maximum "
+ "prefix length is %zu",
+ sizeof(info->prefix));
+ if (strchr(optarg, '\n'))
+ exit_error(PARAMETER_PROBLEM, "LOGMARK: Newlines not "
+ "allowed in log prefix");
+ strncpy(info->prefix, optarg, sizeof(info->prefix));
+ *flags |= F_PREFIX;
+ return true;
+
+ case 'n': /* --log-nfmark */
+ param_act(P_ONLY_ONCE, "LOGMARK", "--log-nfmark", *flags & F_NFMARK);
+ param_act(P_NO_INVERT, "LOGMARK", "--log-nfmark", invert);
+ info->flags |= XT_LOGMARK_NFMARK;
+ *flags |= F_NFMARK;
+ return true;
+
+ case 'c': /* --log-ctmark */
+ param_act(P_ONLY_ONCE, "LOGMARK", "--log-ctmark", *flags & F_CTMARK);
+ param_act(P_NO_INVERT, "LOGMARK", "--log-ctmark", invert);
+ info->flags |= XT_LOGMARK_CTMARK;
+ *flags |= F_CTMARK;
+ return true;
+
+ case 's': /* --log-secmark */
+ param_act(P_ONLY_ONCE, "LOGMARK", "--log-secmark", *flags & F_SECMARK);
+ param_act(P_NO_INVERT, "LOGMARK", "--log-secmark", invert);
+ info->flags |= XT_LOGMARK_SECMARK;
+ *flags |= F_SECMARK;
+ return true;
+ }
+ return false;
+}
+
+static void
+logmark_tg_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_logmark_tginfo *info = (void *)target->data;
+
+ printf("LOGMARK level %u prefix \"%s\"", info->level, info->prefix);
+ if (info->flags & XT_LOGMARK_NFMARK)
+ printf(" nfmark");
+ if (info->flags & XT_LOGMARK_CTMARK)
+ printf(" ctmark");
+ if (info->flags & XT_LOGMARK_SECMARK)
+ printf(" secmark");
+ printf("; ");
+}
+
+static void
+logmark_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_logmark_tginfo *info = (void *)target->data;
+
+ if (info->level != 4)
+ printf("--log-level %u ", info->level);
+ if (*info->prefix != '\0')
+ printf("--log-prefix \"%s\" ", info->prefix);
+ if (info->flags & XT_LOGMARK_NFMARK)
+ printf("--log-nfmark ");
+ if (info->flags & XT_LOGMARK_CTMARK)
+ printf("--log-ctmark ");
+ if (info->flags & XT_LOGMARK_SECMARK)
+ printf("--log-secmark ");
+}
+
+static struct xtables_target logmark_tg_reg = {
+ .version = IPTABLES_VERSION,
+ .name = "LOGMARK",
+ .revision = 0,
+ .family = AF_INET,
+ .size = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
+ .help = logmark_tg_help,
+ .init = logmark_tg_init,
+ .parse = logmark_tg_parse,
+ .print = logmark_tg_print,
+ .save = logmark_tg_save,
+ .extra_opts = logmark_tg_opts,
+};
+
+static struct xtables_target logmark_tg6_reg = {
+ .version = IPTABLES_VERSION,
+ .name = "LOGMARK",
+ .revision = 0,
+ .family = AF_INET6,
+ .size = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
+ .help = logmark_tg_help,
+ .init = logmark_tg_init,
+ .parse = logmark_tg_parse,
+ .print = logmark_tg_print,
+ .save = logmark_tg_save,
+ .extra_opts = logmark_tg_opts,
+};
+
+void _init(void);
+void _init(void)
+{
+ xtables_register_target(&logmark_tg_reg);
+ xtables_register_target(&logmark_tg6_reg);
+}
--- /dev/null
+/*
+ * xt_LOGMARK - netfilter mark logging
+ * useful for debugging
+ *
+ * Copyright © CC Computer Consultants, 2007 - 2008
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#include <net/netfilter/nf_conntrack.h>
+#include "compat_xtables.h"
+#include "xt_LOGMARK.h"
+
+static unsigned int
+logmark_tg(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 xt_logmark_tginfo *info = targinfo;
+
+ printk("<%u>%.*s", info->level, sizeof(info->prefix), info->prefix);
+
+ if (info->flags & XT_LOGMARK_NFMARK)
+ printk(" nfmark=0x%x", skb->mark);
+ if (info->flags & XT_LOGMARK_CTMARK) {
+ const struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct == NULL)
+ printk(" ctmark=X");
+ else
+ printk(" ctmark=0x%x", ct->mark);
+ }
+ if (info->flags & XT_LOGMARK_SECMARK)
+ printk(" secmark=0x%x", skb->secmark);
+ printk("\n");
+
+ return XT_CONTINUE;
+}
+
+static bool
+logmark_tg_check(const char *tablename, const void *e,
+ const struct xt_target *target, void *targinfo,
+ unsigned int hook_mask)
+{
+ const struct xt_logmark_tginfo *info = targinfo;
+
+ if (info->level >= 8) {
+ pr_debug("LOGMARK: level %u >= 8\n", info->level);
+ return false;
+ }
+
+ return true;
+}
+
+static struct xt_target logmark_tg_reg[] __read_mostly = {
+ {
+ .name = "LOGMARK",
+ .revision = 0,
+ .family = AF_INET,
+ .checkentry = logmark_tg_check,
+ .target = logmark_tg,
+ .targetsize = sizeof(struct xt_logmark_tginfo),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "LOGMARK",
+ .revision = 0,
+ .family = AF_INET6,
+ .checkentry = logmark_tg_check,
+ .target = logmark_tg,
+ .targetsize = sizeof(struct xt_logmark_tginfo),
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init logmark_tg_init(void)
+{
+ return xt_register_targets(logmark_tg_reg, ARRAY_SIZE(logmark_tg_reg));
+}
+
+static void __exit logmark_tg_exit(void)
+{
+ xt_unregister_targets(logmark_tg_reg, ARRAY_SIZE(logmark_tg_reg));
+}
+
+module_init(logmark_tg_init);
+module_exit(logmark_tg_exit);
+MODULE_DESCRIPTION("Xtables: netfilter mark logging to syslog");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_LOGMARK");
+MODULE_ALIAS("ip6t_LOGMARK");