1/* Shared library add-on to iptables to add IPMARK target support.
2 * (C) 2003 by Grzegorz Janoszka <Grzegorz.Janoszka@pro.onet.pl>
3 *
4 * based on original MARK target
5 *
6 * This program is distributed under the terms of GNU GPL
7 */
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <getopt.h>
12
13#include <iptables.h>
14#include <linux/netfilter_ipv4/ip_tables.h>
15#include <linux/netfilter_ipv4/ipt_IPMARK.h>
16
17#define IPT_ADDR_USED        1
18#define IPT_AND_MASK_USED    2
19#define IPT_OR_MASK_USED     4
20
21struct ipmarkinfo {
22	struct ipt_entry_target t;
23	struct ipt_ipmark_target_info ipmark;
24};
25
26/* Function which prints out usage message. */
27static void
28help(void)
29{
30	printf(
31"IPMARK target v%s options:\n"
32"  --addr src/dst         use source or destination ip address\n"
33"  --and-mask value       logical AND ip address with this value becomes MARK\n"
34"  --or-mask value        logical OR ip address with this value becomes MARK\n"
35"\n",
36IPTABLES_VERSION);
37}
38
39static struct option opts[] = {
40	{ "addr", 1, 0, '1' },
41	{ "and-mask", 1, 0, '2' },
42	{ "or-mask", 1, 0, '3' },
43	{ 0 }
44};
45
46/* Initialize the target. */
47static void
48init(struct ipt_entry_target *t, unsigned int *nfcache)
49{
50	struct ipt_ipmark_target_info *ipmarkinfo =
51		(struct ipt_ipmark_target_info *)t->data;
52
53	ipmarkinfo->andmask=0xffffffff;
54	ipmarkinfo->ormask=0;
55
56}
57
58/* Function which parses command options; returns true if it
59   ate an option */
60static int
61parse(int c, char **argv, int invert, unsigned int *flags,
62      const struct ipt_entry *entry,
63      struct ipt_entry_target **target)
64{
65	struct ipt_ipmark_target_info *ipmarkinfo
66		= (struct ipt_ipmark_target_info *)(*target)->data;
67
68	switch (c) {
69		char *end;
70	case '1':
71		if(!strcmp(optarg, "src")) ipmarkinfo->addr=IPT_IPMARK_SRC;
72		  else if(!strcmp(optarg, "dst")) ipmarkinfo->addr=IPT_IPMARK_DST;
73		    else exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg);
74		if (*flags & IPT_ADDR_USED)
75			exit_error(PARAMETER_PROBLEM,
76			           "IPMARK target: Can't specify --addr twice");
77		*flags |= IPT_ADDR_USED;
78		break;
79
80	case '2':
81		ipmarkinfo->andmask = strtoul(optarg, &end, 0);
82		if (*end != '\0' || end == optarg)
83			exit_error(PARAMETER_PROBLEM, "Bad and-mask value `%s'", optarg);
84		if (*flags & IPT_AND_MASK_USED)
85			exit_error(PARAMETER_PROBLEM,
86			           "IPMARK target: Can't specify --and-mask twice");
87		*flags |= IPT_AND_MASK_USED;
88		break;
89	case '3':
90		ipmarkinfo->ormask = strtoul(optarg, &end, 0);
91		if (*end != '\0' || end == optarg)
92			exit_error(PARAMETER_PROBLEM, "Bad or-mask value `%s'", optarg);
93		if (*flags & IPT_OR_MASK_USED)
94			exit_error(PARAMETER_PROBLEM,
95			           "IPMARK target: Can't specify --or-mask twice");
96		*flags |= IPT_OR_MASK_USED;
97		break;
98
99	default:
100		return 0;
101	}
102
103	return 1;
104}
105
106static void
107final_check(unsigned int flags)
108{
109	if (!(flags & IPT_ADDR_USED))
110		exit_error(PARAMETER_PROBLEM,
111		           "IPMARK target: Parameter --addr is required");
112	if (!(flags & (IPT_AND_MASK_USED | IPT_OR_MASK_USED)))
113		exit_error(PARAMETER_PROBLEM,
114		           "IPMARK target: Parameter --and-mask or --or-mask is required");
115}
116
117/* Prints out the targinfo. */
118static void
119print(const struct ipt_ip *ip,
120      const struct ipt_entry_target *target,
121      int numeric)
122{
123	const struct ipt_ipmark_target_info *ipmarkinfo =
124		(const struct ipt_ipmark_target_info *)target->data;
125
126	if(ipmarkinfo->addr == IPT_IPMARK_SRC)
127	  printf("IPMARK src");
128	else
129	  printf("IPMARK dst");
130	printf(" ip and 0x%lx or 0x%lx", ipmarkinfo->andmask, ipmarkinfo->ormask);
131}
132
133/* Saves the union ipt_targinfo in parsable form to stdout. */
134static void
135save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
136{
137	const struct ipt_ipmark_target_info *ipmarkinfo =
138		(const struct ipt_ipmark_target_info *)target->data;
139
140	if(ipmarkinfo->addr == IPT_IPMARK_SRC)
141	  printf("--addr=src ");
142	else
143	  printf("--addr=dst ");
144	if(ipmarkinfo->andmask != 0xffffffff)
145	  printf("--and-mask 0x%lx ", ipmarkinfo->andmask);
146	if(ipmarkinfo->ormask != 0)
147	  printf("--or-mask 0x%lx ", ipmarkinfo->ormask);
148}
149
150static struct iptables_target ipmark = {
151	.next		= NULL,
152	.name		= "IPMARK",
153	.version	= IPTABLES_VERSION,
154	.size		= IPT_ALIGN(sizeof(struct ipt_ipmark_target_info)),
155	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_ipmark_target_info)),
156	.help		= &help,
157	.init		= &init,
158	.parse		= &parse,
159	.final_check	= &final_check,
160	.print		= &print,
161	.save		= &save,
162	.extra_opts	= opts
163};
164
165void _init(void)
166{
167	register_target(&ipmark);
168}
169