1/* Shared library add-on to iptables to add CONNMARK target support.
2 *
3 * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
4 * by Henrik Nordstrom <hno@marasystems.com>
5 *
6 * Version 1.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <getopt.h>
26
27#include <iptables.h>
28#include <linux/netfilter_ipv4/ip_tables.h>
29#include <../include/linux/netfilter_ipv4/ipt_CONNMARK.h>
30
31
32/* Function which prints out usage message. */
33static void
34help(void)
35{
36	printf(
37"CONNMARK target v%s options:\n"
38"  --set-mark value[/mask]       Set conntrack mark value\n"
39"  --set-return [--mask mask]    Set conntrack mark & nfmark, RETURN\n"
40"  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
41"  --restore-mark [--mask mask]  Restore saved nfmark value\n"
42"\n",
43IPTABLES_VERSION);
44}
45
46static struct option opts[] = {
47	{ "set-mark", 1, 0, '1' },
48	{ "save-mark", 0, 0, '2' },
49	{ "restore-mark", 0, 0, '3' },
50	{ "mask", 1, 0, '4' },
51	{ "set-return", 1, 0, '9' },
52	{ 0 }
53};
54
55/* Initialize the target. */
56static void
57init(struct ipt_entry_target *t, unsigned int *nfcache)
58{
59}
60
61/* Function which parses command options; returns true if it
62   ate an option */
63static int
64parse(int c, char **argv, int invert, unsigned int *flags,
65      const struct ipt_entry *entry,
66      struct ipt_entry_target **target)
67{
68	struct ipt_connmark_target_info *markinfo
69		= (struct ipt_connmark_target_info *)(*target)->data;
70
71	markinfo->mask = 0xffffffffUL;
72
73	switch (c) {
74		char *end;
75	case '1':
76	case '9':
77		markinfo->mode = (c == '1') ? IPT_CONNMARK_SET : IPT_CONNMARK_SET_RETURN;
78//		markinfo->mode = IPT_CONNMARK_SET;
79
80		markinfo->mark = strtoul(optarg, &end, 0);
81		if (*end == '/' && end[1] != '\0')
82		    markinfo->mask = strtoul(end+1, &end, 0);
83
84		if (*end != '\0' || end == optarg)
85			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
86		if (*flags)
87			exit_error(PARAMETER_PROBLEM,
88			           "CONNMARK target: Can't specify --set-mark twice");
89		*flags = 1;
90		break;
91	case '2':
92		markinfo->mode = IPT_CONNMARK_SAVE;
93		if (*flags)
94			exit_error(PARAMETER_PROBLEM,
95			           "CONNMARK target: Can't specify --save-mark twice");
96		*flags = 1;
97		break;
98	case '3':
99		markinfo->mode = IPT_CONNMARK_RESTORE;
100		if (*flags)
101			exit_error(PARAMETER_PROBLEM,
102			           "CONNMARK target: Can't specify --restore-mark twice");
103		*flags = 1;
104		break;
105	case '4':
106		if (!*flags)
107			exit_error(PARAMETER_PROBLEM,
108			           "CONNMARK target: Can't specify --mask without a operation");
109		markinfo->mask = strtoul(optarg, &end, 0);
110
111		if (*end != '\0' || end == optarg)
112			exit_error(PARAMETER_PROBLEM, "Bad MASK value `%s'", optarg);
113		break;
114	default:
115		return 0;
116	}
117
118	return 1;
119}
120
121static void
122final_check(unsigned int flags)
123{
124	if (!flags)
125		exit_error(PARAMETER_PROBLEM,
126		           "CONNMARK target: No operation specified");
127}
128
129static void
130print_mark(unsigned long mark)
131{
132	printf("0x%lx", mark);
133}
134
135static void
136print_mask(const char *text, unsigned long mask)
137{
138	if (mask != 0xffffffffUL)
139		printf("%s0x%lx", text, mask);
140}
141
142
143/* Prints out the target info. */
144static void
145print(const struct ipt_ip *ip,
146      const struct ipt_entry_target *target,
147      int numeric)
148{
149	const struct ipt_connmark_target_info *markinfo =
150		(const struct ipt_connmark_target_info *)target->data;
151	switch (markinfo->mode) {
152	case IPT_CONNMARK_SET:
153	case IPT_CONNMARK_SET_RETURN:
154	    printf("CONNMARK set%s ", (markinfo->mode == IPT_CONNMARK_SET_RETURN) ? "-return" : "");
155
156//	    printf("CONNMARK set ");
157	    print_mark(markinfo->mark);
158	    print_mask("/", markinfo->mask);
159	    printf(" ");
160	    break;
161	case IPT_CONNMARK_SAVE:
162	    printf("CONNMARK save ");
163	    print_mask("mask ", markinfo->mask);
164	    printf(" ");
165	    break;
166	case IPT_CONNMARK_RESTORE:
167	    printf("CONNMARK restore ");
168	    print_mask("mask ", markinfo->mask);
169	    break;
170	default:
171	    printf("ERROR: UNKNOWN CONNMARK MODE ");
172	    break;
173	}
174}
175
176/* Saves the target into in parsable form to stdout. */
177static void
178save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
179{
180	const struct ipt_connmark_target_info *markinfo =
181		(const struct ipt_connmark_target_info *)target->data;
182
183	switch (markinfo->mode) {
184	case IPT_CONNMARK_SET:
185	case IPT_CONNMARK_SET_RETURN:
186	    printf("--set-%s ", (markinfo->mode == IPT_CONNMARK_SET_RETURN) ? "return" : "mark");
187
188//	    printf("--set-mark ");
189	    print_mark(markinfo->mark);
190	    print_mask("/", markinfo->mask);
191	    printf(" ");
192	    break;
193	case IPT_CONNMARK_SAVE:
194	    printf("--save-mark ");
195	    print_mask("--mask ", markinfo->mask);
196	    break;
197	case IPT_CONNMARK_RESTORE:
198	    printf("--restore-mark ");
199	    print_mask("--mask ", markinfo->mask);
200	    break;
201	default:
202	    printf("ERROR: UNKNOWN CONNMARK MODE ");
203	    break;
204	}
205}
206
207static struct iptables_target connmark_target = {
208    .name          = "CONNMARK",
209    .version       = IPTABLES_VERSION,
210    .size          = IPT_ALIGN(sizeof(struct ipt_connmark_target_info)),
211    .userspacesize = IPT_ALIGN(sizeof(struct ipt_connmark_target_info)),
212    .help          = &help,
213    .init          = &init,
214    .parse         = &parse,
215    .final_check   = &final_check,
216    .print         = &print,
217    .save          = &save,
218    .extra_opts    = opts
219};
220
221void _init(void)
222{
223	register_target(&connmark_target);
224}
225