1/* Shared library add-on to iptables to add CONNMARK matching support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7
8#include <iptables.h>
9#include <linux/netfilter_ipv4/ipt_connmark.h>
10
11/* Function which prints out usage message. */
12static void
13help(void)
14{
15	printf(
16"CONNMARK match v%s options:\n"
17"[!] --mark value[/mask]         Match nfmark value with optional mask\n"
18"\n",
19IPTABLES_VERSION);
20}
21
22static struct option opts[] = {
23	{ "mark", 1, 0, '1' },
24	{0}
25};
26
27/* Initialize the match. */
28static void
29init(struct ipt_entry_match *m, unsigned int *nfcache)
30{
31	/* Can't cache this. */
32	*nfcache |= NFC_UNKNOWN;
33}
34
35/* Function which parses command options; returns true if it
36   ate an option */
37static int
38parse(int c, char **argv, int invert, unsigned int *flags,
39      const struct ipt_entry *entry,
40      unsigned int *nfcache,
41      struct ipt_entry_match **match)
42{
43	struct ipt_connmark_info *markinfo = (struct ipt_connmark_info *)(*match)->data;
44
45	switch (c) {
46		char *end;
47	case '1':
48		check_inverse(optarg, &invert, &optind, 0);
49		markinfo->mark = strtoul(optarg, &end, 0);
50		if (*end == '/') {
51			markinfo->mask = strtoul(end+1, &end, 0);
52		} else
53			markinfo->mask = 0xffffffff;
54		if (*end != '\0' || end == optarg)
55			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
56		if (invert)
57			markinfo->invert = 1;
58		*flags = 1;
59		break;
60
61	default:
62		return 0;
63	}
64	return 1;
65}
66
67static void
68print_mark(unsigned long mark, unsigned long mask, int invert, int numeric)
69{
70	if (invert)
71		fputc('!', stdout);
72
73	if(mask != 0xffffffff)
74		printf("0x%lx/0x%lx ", mark, mask);
75	else
76		printf("0x%lx ", mark);
77}
78
79/* Final check; must have specified --mark. */
80static void
81final_check(unsigned int flags)
82{
83	if (!flags)
84		exit_error(PARAMETER_PROBLEM,
85			   "MARK match: You must specify `--mark'");
86}
87
88/* Prints out the matchinfo. */
89static void
90print(const struct ipt_ip *ip,
91      const struct ipt_entry_match *match,
92      int numeric)
93{
94	printf("CONNMARK match ");
95	print_mark(((struct ipt_connmark_info *)match->data)->mark,
96		  ((struct ipt_connmark_info *)match->data)->mask,
97		  ((struct ipt_connmark_info *)match->data)->invert, numeric);
98}
99
100/* Saves the union ipt_matchinfo in parsable form to stdout. */
101static void
102save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
103{
104	printf("--mark ");
105	print_mark(((struct ipt_connmark_info *)match->data)->mark,
106		  ((struct ipt_connmark_info *)match->data)->mask,
107		  ((struct ipt_connmark_info *)match->data)->invert, 0);
108}
109
110static
111struct iptables_match mark
112= { NULL,
113    "connmark",
114    IPTABLES_VERSION,
115    IPT_ALIGN(sizeof(struct ipt_connmark_info)),
116    IPT_ALIGN(sizeof(struct ipt_connmark_info)),
117    &help,
118    &init,
119    &parse,
120    &final_check,
121    &print,
122    &save,
123    opts
124};
125
126void _init(void)
127{
128	register_match(&mark);
129}
130