1 /* Shared library add-on to iptables to add MARK 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 /* For 64bit kernel / 32bit userspace */
10 #include "../include/linux/netfilter_ipv4/ipt_MARK.h"
11
12 /* Function which prints out usage message. */
13 static void
help(void)14 help(void)
15 {
16 printf(
17 "MARK target v%s options:\n"
18 " --set-mark value Set nfmark value\n"
19 " --and-mark value Binary AND the nfmark with value\n"
20 " --or-mark value Binary OR the nfmark with value\n"
21 "\n",
22 IPTABLES_VERSION);
23 }
24
25 static struct option opts[] = {
26 { "set-mark", 1, 0, '1' },
27 { "and-mark", 1, 0, '2' },
28 { "or-mark", 1, 0, '3' },
29 { 0 }
30 };
31
32 /* Initialize the target. */
33 static void
init(struct ipt_entry_target * t,unsigned int * nfcache)34 init(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 */
40 static int
parse_v0(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,struct ipt_entry_target ** target)41 parse_v0(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_mark_target_info *markinfo
46 = (struct ipt_mark_target_info *)(*target)->data;
47
48 switch (c) {
49 case '1':
50 #ifdef KERNEL_64_USERSPACE_32
51 if (string_to_number_ll(optarg, 0, 0,
52 &markinfo->mark))
53 #else
54 if (string_to_number_l(optarg, 0, 0,
55 &markinfo->mark))
56 #endif
57 exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
58 if (*flags)
59 exit_error(PARAMETER_PROBLEM,
60 "MARK target: Can't specify --set-mark twice");
61 *flags = 1;
62 break;
63 case '2':
64 exit_error(PARAMETER_PROBLEM,
65 "MARK target: kernel too old for --and-mark");
66 case '3':
67 exit_error(PARAMETER_PROBLEM,
68 "MARK target: kernel too old for --or-mark");
69 default:
70 return 0;
71 }
72
73 return 1;
74 }
75
76 static void
final_check(unsigned int flags)77 final_check(unsigned int flags)
78 {
79 if (!flags)
80 exit_error(PARAMETER_PROBLEM,
81 "MARK target: Parameter --set/and/or-mark"
82 " is required");
83 }
84
85 /* Function which parses command options; returns true if it
86 ate an option */
87 static int
parse_v1(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,struct ipt_entry_target ** target)88 parse_v1(int c, char **argv, int invert, unsigned int *flags,
89 const struct ipt_entry *entry,
90 struct ipt_entry_target **target)
91 {
92 struct ipt_mark_target_info_v1 *markinfo
93 = (struct ipt_mark_target_info_v1 *)(*target)->data;
94
95 switch (c) {
96 case '1':
97 markinfo->mode = IPT_MARK_SET;
98 break;
99 case '2':
100 markinfo->mode = IPT_MARK_AND;
101 break;
102 case '3':
103 markinfo->mode = IPT_MARK_OR;
104 break;
105 default:
106 return 0;
107 }
108
109 #ifdef KERNEL_64_USERSPACE_32
110 if (string_to_number_ll(optarg, 0, 0, &markinfo->mark))
111 #else
112 if (string_to_number_l(optarg, 0, 0, &markinfo->mark))
113 #endif
114 exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
115
116 if (*flags)
117 exit_error(PARAMETER_PROBLEM,
118 "MARK target: Can't specify --set-mark twice");
119
120 *flags = 1;
121 return 1;
122 }
123
124 #ifdef KERNEL_64_USERSPACE_32
125 static void
print_mark(unsigned long long mark)126 print_mark(unsigned long long mark)
127 {
128 printf("0x%llx ", mark);
129 }
130 #else
131 static void
print_mark(unsigned long mark)132 print_mark(unsigned long mark)
133 {
134 printf("0x%lx ", mark);
135 }
136 #endif
137
138 /* Prints out the targinfo. */
139 static void
print_v0(const struct ipt_ip * ip,const struct ipt_entry_target * target,int numeric)140 print_v0(const struct ipt_ip *ip,
141 const struct ipt_entry_target *target,
142 int numeric)
143 {
144 const struct ipt_mark_target_info *markinfo =
145 (const struct ipt_mark_target_info *)target->data;
146 printf("MARK set ");
147 print_mark(markinfo->mark);
148 }
149
150 /* Saves the union ipt_targinfo in parsable form to stdout. */
151 static void
save_v0(const struct ipt_ip * ip,const struct ipt_entry_target * target)152 save_v0(const struct ipt_ip *ip, const struct ipt_entry_target *target)
153 {
154 const struct ipt_mark_target_info *markinfo =
155 (const struct ipt_mark_target_info *)target->data;
156
157 printf("--set-mark ");
158 print_mark(markinfo->mark);
159 }
160
161 /* Prints out the targinfo. */
162 static void
print_v1(const struct ipt_ip * ip,const struct ipt_entry_target * target,int numeric)163 print_v1(const struct ipt_ip *ip,
164 const struct ipt_entry_target *target,
165 int numeric)
166 {
167 const struct ipt_mark_target_info_v1 *markinfo =
168 (const struct ipt_mark_target_info_v1 *)target->data;
169
170 switch (markinfo->mode) {
171 case IPT_MARK_SET:
172 printf("MARK set ");
173 break;
174 case IPT_MARK_AND:
175 printf("MARK and ");
176 break;
177 case IPT_MARK_OR:
178 printf("MARK or ");
179 break;
180 }
181 print_mark(markinfo->mark);
182 }
183
184 /* Saves the union ipt_targinfo in parsable form to stdout. */
185 static void
save_v1(const struct ipt_ip * ip,const struct ipt_entry_target * target)186 save_v1(const struct ipt_ip *ip, const struct ipt_entry_target *target)
187 {
188 const struct ipt_mark_target_info_v1 *markinfo =
189 (const struct ipt_mark_target_info_v1 *)target->data;
190
191 switch (markinfo->mode) {
192 case IPT_MARK_SET:
193 printf("--set-mark ");
194 break;
195 case IPT_MARK_AND:
196 printf("--and-mark ");
197 break;
198 case IPT_MARK_OR:
199 printf("--or-mark ");
200 break;
201 }
202 print_mark(markinfo->mark);
203 }
204
205 static
206 struct iptables_target mark_v0 = {
207 .next = NULL,
208 .name = "MARK",
209 .version = IPTABLES_VERSION,
210 .revision = 0,
211 .size = IPT_ALIGN(sizeof(struct ipt_mark_target_info)),
212 .userspacesize = IPT_ALIGN(sizeof(struct ipt_mark_target_info)),
213 .help = &help,
214 .init = &init,
215 .parse = &parse_v0,
216 .final_check = &final_check,
217 .print = &print_v0,
218 .save = &save_v0,
219 .extra_opts = opts
220 };
221
222 static
223 struct iptables_target mark_v1 = {
224 .next = NULL,
225 .name = "MARK",
226 .version = IPTABLES_VERSION,
227 .revision = 1,
228 .size = IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1)),
229 .userspacesize = IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1)),
230 .help = &help,
231 .init = &init,
232 .parse = &parse_v1,
233 .final_check = &final_check,
234 .print = &print_v1,
235 .save = &save_v1,
236 .extra_opts = opts
237 };
238
ipt_MARK_init(void)239 void ipt_MARK_init(void)
240 {
241 register_target(&mark_v0);
242 register_target(&mark_v1);
243 }
244