]>
Commit | Line | Data |
---|---|---|
9b198fe6 JE |
1 | /* |
2 | * Shared library add-on to iptables to add interface state matching | |
3 | * support. | |
4 | * | |
5 | * (C) 2008 Gáspár Lajos <gaspar.lajos@glsys.eu> | |
6 | * | |
7 | * This program is released under the terms of GNU GPL version 2. | |
8 | */ | |
9 | ||
10 | #include <getopt.h> | |
11 | #include <stdbool.h> | |
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <string.h> | |
15 | ||
16 | #include <xtables.h> | |
17 | #include "xt_iface.h" | |
b5e2c725 | 18 | #include "compat_user.h" |
9b198fe6 | 19 | |
21cdf786 JE |
20 | enum { |
21 | XT_IFACE_IFACE = 1 << 16, | |
22 | }; | |
23 | ||
be2061c5 | 24 | static const struct option iface_mt_opts[] = { |
f5ed98fb | 25 | {.name = "iface", .has_arg = true, .val = 'i'}, |
db76ea9a JE |
26 | {.name = "dev-in", .has_arg = false, .val = 'I'}, |
27 | {.name = "dev-out", .has_arg = false, .val = 'O'}, | |
f5ed98fb JE |
28 | {.name = "up", .has_arg = false, .val = 'u'}, |
29 | {.name = "down", .has_arg = false, .val = 'U'}, /* not up */ | |
30 | {.name = "broadcast", .has_arg = false, .val = 'b'}, | |
31 | {.name = "loopback", .has_arg = false, .val = 'l'}, | |
32 | {.name = "pointopoint", .has_arg = false, .val = 'p'}, | |
33 | {.name = "pointtopoint", .has_arg = false, .val = 'p'}, /* eq pointopoint */ | |
34 | {.name = "running", .has_arg = false, .val = 'r'}, | |
35 | {.name = "noarp", .has_arg = false, .val = 'n'}, | |
36 | {.name = "arp", .has_arg = false, .val = 'N'}, /* not noarp */ | |
37 | {.name = "promisc", .has_arg = false, .val = 'o'}, | |
38 | {.name = "multicast", .has_arg = false, .val = 'm'}, | |
39 | {.name = "dynamic", .has_arg = false, .val = 'd'}, | |
40 | {.name = "lower-up", .has_arg = false, .val = 'w'}, | |
41 | {.name = "dormant", .has_arg = false, .val = 'a'}, | |
42 | {NULL}, | |
9b198fe6 JE |
43 | }; |
44 | ||
45 | static void iface_print_opt(const struct xt_iface_mtinfo *info, | |
46 | const unsigned int option, const char *command) | |
47 | { | |
9b198fe6 | 48 | if (info->flags & option) |
67332653 | 49 | printf(" %s%s", (info->invflags & option) ? "! " : "", command); |
9b198fe6 JE |
50 | } |
51 | ||
52 | static void iface_setflag(struct xt_iface_mtinfo *info, | |
53 | unsigned int *flags, int invert, u_int16_t flag, const char *command) | |
54 | { | |
9b198fe6 JE |
55 | if (*flags & flag) |
56 | xtables_error(PARAMETER_PROBLEM, | |
57 | "iface: \"--%s\" flag already specified", command); | |
67332653 | 58 | info->flags |= flag; |
9b198fe6 JE |
59 | if (invert) |
60 | info->invflags |= flag; | |
9b198fe6 JE |
61 | *flags |= flag; |
62 | } | |
63 | ||
64 | static bool iface_valid_name(const char *name) | |
65 | { | |
be2061c5 | 66 | static const char invalid_chars[] = ".+!*"; |
9b198fe6 | 67 | |
0d36136f | 68 | return strlen(name) < IFNAMSIZ && strpbrk(name, invalid_chars) == NULL; |
9b198fe6 JE |
69 | } |
70 | ||
71 | static void iface_mt_help(void) | |
72 | { | |
73 | printf( | |
6d8ce3ac | 74 | "iface match options:\n" |
db76ea9a JE |
75 | " --iface interface Name of interface\n" |
76 | " --dev-in / --dev-out Use incoming/outgoing interface instead\n" | |
77 | "[!] --up / --down match if UP flag (not) set\n" | |
78 | "[!] --broadcast match if BROADCAST flag (not) set\n" | |
79 | "[!] --loopback match if LOOPBACK flag (not) set\n" | |
9b198fe6 | 80 | "[!] --pointopoint\n" |
db76ea9a JE |
81 | "[!] --pointtopoint match if POINTOPOINT flag (not) set\n" |
82 | "[!] --running match if RUNNING flag (not) set\n" | |
83 | "[!] --noarp / --arp match if NOARP flag (not) set\n" | |
84 | "[!] --promisc match if PROMISC flag (not) set\n" | |
85 | "[!] --multicast match if MULTICAST flag (not) set\n" | |
86 | "[!] --dynamic match if DYNAMIC flag (not) set\n" | |
87 | "[!] --lower-up match if LOWER_UP flag (not) set\n" | |
88 | "[!] --dormant match if DORMANT flag (not) set\n"); | |
9b198fe6 JE |
89 | } |
90 | ||
9b198fe6 JE |
91 | static int iface_mt_parse(int c, char **argv, int invert, unsigned int *flags, |
92 | const void *entry, struct xt_entry_match **match) | |
93 | { | |
9b198fe6 JE |
94 | struct xt_iface_mtinfo *info = (void *)(*match)->data; |
95 | ||
96 | switch (c) { | |
97 | case 'U': | |
98 | c = 'u'; | |
99 | invert = !invert; | |
100 | break; | |
101 | case 'N': | |
102 | c = 'n'; | |
103 | invert = !invert; | |
104 | break; | |
105 | } | |
106 | ||
107 | switch (c) { | |
108 | case 'i': /* interface name */ | |
109 | if (*flags & XT_IFACE_IFACE) | |
110 | xtables_error(PARAMETER_PROBLEM, | |
111 | "iface: Interface name already specified"); | |
112 | if (!iface_valid_name(optarg)) | |
113 | xtables_error(PARAMETER_PROBLEM, | |
114 | "iface: Invalid interface name!"); | |
115 | strcpy(info->ifname, optarg); | |
116 | *flags |= XT_IFACE_IFACE; | |
a6ba463c | 117 | return true; |
db76ea9a JE |
118 | case 'I': /* --dev-in */ |
119 | xtables_param_act(XTF_ONLY_ONCE, "iface", "--dev-in", | |
120 | *flags & XT_IFACE_IFACE); | |
121 | *flags |= XT_IFACE_IFACE; | |
122 | iface_setflag(info, flags, invert, XT_IFACE_DEV_IN, "dev-in"); | |
123 | return true; | |
124 | case 'O': /* --dev-out */ | |
125 | xtables_param_act(XTF_ONLY_ONCE, "iface", "--dev-out", | |
126 | *flags & XT_IFACE_IFACE); | |
127 | *flags |= XT_IFACE_IFACE; | |
128 | iface_setflag(info, flags, invert, XT_IFACE_DEV_OUT, "dev-out"); | |
129 | return true; | |
9b198fe6 JE |
130 | case 'u': /* UP */ |
131 | iface_setflag(info, flags, invert, XT_IFACE_UP, "up"); | |
a6ba463c | 132 | return true; |
9b198fe6 JE |
133 | case 'b': /* BROADCAST */ |
134 | iface_setflag(info, flags, invert, XT_IFACE_BROADCAST, "broadcast"); | |
a6ba463c | 135 | return true; |
9b198fe6 JE |
136 | case 'l': /* LOOPBACK */ |
137 | iface_setflag(info, flags, invert, XT_IFACE_LOOPBACK, "loopback"); | |
a6ba463c | 138 | return true; |
9b198fe6 JE |
139 | case 'p': /* POINTOPOINT */ |
140 | iface_setflag(info, flags, invert, XT_IFACE_POINTOPOINT, "pointopoint"); | |
a6ba463c | 141 | return true; |
9b198fe6 JE |
142 | case 'r': /* RUNNING */ |
143 | iface_setflag(info, flags, invert, XT_IFACE_RUNNING, "running"); | |
a6ba463c | 144 | return true; |
9b198fe6 JE |
145 | case 'n': /* NOARP */ |
146 | iface_setflag(info, flags, invert, XT_IFACE_NOARP, "noarp"); | |
a6ba463c | 147 | return true; |
9b198fe6 JE |
148 | case 'o': /* PROMISC */ |
149 | iface_setflag(info, flags, invert, XT_IFACE_PROMISC, "promisc"); | |
a6ba463c | 150 | return true; |
9b198fe6 JE |
151 | case 'm': /* MULTICAST */ |
152 | iface_setflag(info, flags, invert, XT_IFACE_MULTICAST, "multicast"); | |
a6ba463c | 153 | return true; |
9b198fe6 JE |
154 | case 'd': /* DYNAMIC */ |
155 | iface_setflag(info, flags, invert, XT_IFACE_DYNAMIC, "dynamic"); | |
a6ba463c | 156 | return true; |
9b198fe6 JE |
157 | case 'w': /* LOWER_UP */ |
158 | iface_setflag(info, flags, invert, XT_IFACE_LOWER_UP, "lower_up"); | |
a6ba463c | 159 | return true; |
9b198fe6 JE |
160 | case 'a': /* DORMANT */ |
161 | iface_setflag(info, flags, invert, XT_IFACE_DORMANT, "dormant"); | |
a6ba463c | 162 | return true; |
9b198fe6 | 163 | } |
a6ba463c | 164 | return false; |
9b198fe6 JE |
165 | } |
166 | ||
167 | static void iface_mt_check(unsigned int flags) | |
168 | { | |
9b198fe6 JE |
169 | if (!(flags & XT_IFACE_IFACE)) |
170 | xtables_error(PARAMETER_PROBLEM, | |
171 | "iface: You must specify an interface"); | |
db76ea9a JE |
172 | if ((flags & ~(XT_IFACE_IFACE | XT_IFACE_DEV_IN | |
173 | XT_IFACE_DEV_OUT)) == 0) | |
9b198fe6 JE |
174 | xtables_error(PARAMETER_PROBLEM, |
175 | "iface: You must specify at least one option"); | |
176 | } | |
177 | ||
9b198fe6 JE |
178 | static void iface_mt_save(const void *ip, const struct xt_entry_match *match) |
179 | { | |
9b198fe6 JE |
180 | const struct xt_iface_mtinfo *info = (const void *)match->data; |
181 | ||
db76ea9a | 182 | if (info->flags & XT_IFACE_DEV_IN) |
ebfa7779 | 183 | printf(" --dev-in"); |
db76ea9a | 184 | else if (info->flags & XT_IFACE_DEV_OUT) |
ebfa7779 | 185 | printf(" --dev-out"); |
db76ea9a | 186 | else |
ebfa7779 | 187 | printf(" --iface %s", info->ifname); |
9b198fe6 JE |
188 | iface_print_opt(info, XT_IFACE_UP, "--up"); |
189 | iface_print_opt(info, XT_IFACE_BROADCAST, "--broadcast"); | |
190 | iface_print_opt(info, XT_IFACE_LOOPBACK, "--loopback"); | |
191 | iface_print_opt(info, XT_IFACE_POINTOPOINT, "--pointopoint"); | |
192 | iface_print_opt(info, XT_IFACE_RUNNING, "--running"); | |
193 | iface_print_opt(info, XT_IFACE_NOARP, "--noarp"); | |
194 | iface_print_opt(info, XT_IFACE_PROMISC, "--promisc"); | |
195 | iface_print_opt(info, XT_IFACE_MULTICAST, "--multicast"); | |
196 | iface_print_opt(info, XT_IFACE_DYNAMIC, "--dynamic"); | |
197 | iface_print_opt(info, XT_IFACE_LOWER_UP, "--lower_up"); | |
198 | iface_print_opt(info, XT_IFACE_DORMANT, "--dormant"); | |
199 | printf(" "); | |
200 | } | |
201 | ||
13db8d78 JE |
202 | static void iface_mt_print(const void *ip, const struct xt_entry_match *match, |
203 | int numeric) | |
204 | { | |
205 | printf(" -m iface"); | |
206 | iface_mt_save(ip, match); | |
207 | } | |
208 | ||
9b198fe6 JE |
209 | static struct xtables_match iface_mt_reg = { |
210 | .version = XTABLES_VERSION, | |
6d8ce3ac JE |
211 | .name = "iface", |
212 | .revision = 0, | |
414e95ff | 213 | .family = NFPROTO_UNSPEC, |
9b198fe6 JE |
214 | .size = XT_ALIGN(sizeof(struct xt_iface_mtinfo)), |
215 | .userspacesize = XT_ALIGN(sizeof(struct xt_iface_mtinfo)), | |
216 | .help = iface_mt_help, | |
9b198fe6 JE |
217 | .parse = iface_mt_parse, |
218 | .final_check = iface_mt_check, | |
219 | .print = iface_mt_print, | |
220 | .save = iface_mt_save, | |
221 | .extra_opts = iface_mt_opts, | |
222 | }; | |
223 | ||
a711985a | 224 | static __attribute__((constructor)) void iface_mt_ldr(void) |
9b198fe6 | 225 | { |
9b198fe6 | 226 | xtables_register_match(&iface_mt_reg); |
9b198fe6 | 227 | } |