1/* Shared library add-on to iptables to add CONNMARK target support. */
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <getopt.h>
6
7#include <iptables.h>
8#include <linux/netfilter_ipv4/ip_tables.h>
9#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
10
11
12/* Function which prints out usage message. */
13static void
14help(void)
15{
16	printf(
17"CONNMARK target v%s options:\n"
18"  --set-mark value              Set conntrack mark value\n"
19"  --save-mark                   Save the packet nfmark on the connection\n"
20"  --restore-mark                Restore saved nfmark value\n"
21"\n",
22IPTABLES_VERSION);
23}
24
25static struct option opts[] = {
26	{ "set-mark", 1, 0, '1' },
27	{ "save-mark", 0, 0, '2' },
28	{ "restore-mark", 0, 0, '3' },
29	{ 0 }
30};
31
32/* Initialize the target. */
33static void
34init(struct ipt_entry_target *t, unsigned int *nfcache)
35{
36}
37
38/* Function which parses command options; returns true if it
39   ate an option */
40static int
41parse(int c, char **argv, int invert, unsigned int *flags,
42      const struct ipt_entry *entry,
43      struct ipt_entry_target **target)
44{
45	struct ipt_connmark_target_info *markinfo
46		= (struct ipt_connmark_target_info *)(*target)->data;
47
48	switch (c) {
49		char *end;
50	case '1':
51		markinfo->mode = IPT_CONNMARK_SET;
52		markinfo->mark = strtoul(optarg, &end, 0);
53		if (*end != '\0' || end == optarg)
54			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
55		if (*flags)
56			exit_error(PARAMETER_PROBLEM,
57			           "CONNMARK target: Can't specify --set-mark twice");
58		*flags = 1;
59		break;
60	case '2':
61		markinfo->mode = IPT_CONNMARK_SAVE;
62		if (*flags)
63			exit_error(PARAMETER_PROBLEM,
64			           "CONNMARK target: Can't specify --save-mark twice");
65		*flags = 1;
66		break;
67	case '3':
68		markinfo->mode = IPT_CONNMARK_RESTORE;
69		if (*flags)
70			exit_error(PARAMETER_PROBLEM,
71			           "CONNMARK target: Can't specify --restore-mark twice");
72		*flags = 1;
73		break;
74	default:
75		return 0;
76	}
77
78	return 1;
79}
80
81static void
82final_check(unsigned int flags)
83{
84	if (!flags)
85		exit_error(PARAMETER_PROBLEM,
86		           "CONNMARK target: Parameter --set-mark is required");
87}
88
89static void
90print_mark(unsigned long mark, int numeric)
91{
92	printf("0x%lx ", mark);
93}
94
95/* Prints out the targinfo. */
96static void
97print(const struct ipt_ip *ip,
98      const struct ipt_entry_target *target,
99      int numeric)
100{
101	const struct ipt_connmark_target_info *markinfo =
102		(const struct ipt_connmark_target_info *)target->data;
103	switch (markinfo->mode) {
104	case IPT_CONNMARK_SET:
105	    printf("CONNMARK set ");
106	    print_mark(markinfo->mark, numeric);
107	    break;
108	case IPT_CONNMARK_SAVE:
109	    printf("CONNMARK save ");
110	    break;
111	case IPT_CONNMARK_RESTORE:
112	    printf("CONNMARK restore ");
113	    break;
114	default:
115	    printf("ERROR: UNKNOWN CONNMARK MODE ");
116	    break;
117	}
118}
119
120/* Saves the union ipt_targinfo in parsable form to stdout. */
121static void
122save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
123{
124	const struct ipt_connmark_target_info *markinfo =
125		(const struct ipt_connmark_target_info *)target->data;
126
127	switch (markinfo->mode) {
128	case IPT_CONNMARK_SET:
129	    printf("--set-mark 0x%lx ", markinfo->mark);
130	    break;
131	case IPT_CONNMARK_SAVE:
132	    printf("--save-mark ");
133	    break;
134	case IPT_CONNMARK_RESTORE:
135	    printf("--restore-mark ");
136	    break;
137	default:
138	    printf("ERROR: UNKNOWN CONNMARK MODE ");
139	    break;
140	}
141}
142
143static
144struct iptables_target mark
145= { NULL,
146    "CONNMARK",
147    IPTABLES_VERSION,
148    IPT_ALIGN(sizeof(struct ipt_connmark_target_info)),
149    IPT_ALIGN(sizeof(struct ipt_connmark_target_info)),
150    &help,
151    &init,
152    &parse,
153    &final_check,
154    &print,
155    &save,
156    opts
157};
158
159void _init(void)
160{
161	register_target(&mark);
162}
163