Merge to iptables-1.3.5
[iptables.git] / extensions / libipt_physdev.c
1 /* Shared library add-on to iptables to add bridge port matching support. */
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <getopt.h>
6 #include <ctype.h>
7 #include <iptables.h>
8 #include <linux/netfilter_ipv4/ipt_physdev.h>
9 #if defined(__GLIBC__) && __GLIBC__ == 2
10 #include <net/ethernet.h>
11 #else
12 #include <linux/if_ether.h>
13 #endif
14
15 static void
16 help(void)
17 {
18         printf(
19 "physdev v%s options:\n"
20 " --physdev-in [!] input name[+]                bridge port name ([+] for wildcard)\n"
21 " --physdev-out [!] output name[+]      bridge port name ([+] for wildcard)\n"
22 " [!] --physdev-is-in                   arrived on a bridge device\n"
23 " [!] --physdev-is-out                  will leave on a bridge device\n"
24 " [!] --physdev-is-bridged              it's a bridged packet\n"
25 "\n", IPTABLES_VERSION);
26 }
27
28 static struct option opts[] = {
29         { "physdev-in", 1, 0, '1' },
30         { "physdev-out", 1, 0, '2' },
31         { "physdev-is-in", 0, 0, '3' },
32         { "physdev-is-out", 0, 0, '4' },
33         { "physdev-is-bridged", 0, 0, '5' },
34         {0}
35 };
36
37 static void
38 init(struct ipt_entry_match *m, unsigned int *nfcache)
39 {
40 }
41
42 static int
43 parse(int c, char **argv, int invert, unsigned int *flags,
44       const struct ipt_entry *entry,
45       unsigned int *nfcache,
46       struct ipt_entry_match **match)
47 {
48         struct ipt_physdev_info *info =
49                 (struct ipt_physdev_info*)(*match)->data;
50
51         switch (c) {
52         case '1':
53                 if (*flags & IPT_PHYSDEV_OP_IN)
54                         goto multiple_use;
55                 check_inverse(optarg, &invert, &optind, 0);
56                 parse_interface(argv[optind-1], info->physindev,
57                                 (unsigned char *)info->in_mask);
58                 if (invert)
59                         info->invert |= IPT_PHYSDEV_OP_IN;
60                 info->bitmask |= IPT_PHYSDEV_OP_IN;
61                 *flags |= IPT_PHYSDEV_OP_IN;
62                 break;
63
64         case '2':
65                 if (*flags & IPT_PHYSDEV_OP_OUT)
66                         goto multiple_use;
67                 check_inverse(optarg, &invert, &optind, 0);
68                 parse_interface(argv[optind-1], info->physoutdev,
69                                 (unsigned char *)info->out_mask);
70                 if (invert)
71                         info->invert |= IPT_PHYSDEV_OP_OUT;
72                 info->bitmask |= IPT_PHYSDEV_OP_OUT;
73                 *flags |= IPT_PHYSDEV_OP_OUT;
74                 break;
75
76         case '3':
77                 if (*flags & IPT_PHYSDEV_OP_ISIN)
78                         goto multiple_use;
79                 check_inverse(optarg, &invert, &optind, 0);
80                 info->bitmask |= IPT_PHYSDEV_OP_ISIN;
81                 if (invert)
82                         info->invert |= IPT_PHYSDEV_OP_ISIN;
83                 *flags |= IPT_PHYSDEV_OP_ISIN;
84                 break;
85
86         case '4':
87                 if (*flags & IPT_PHYSDEV_OP_ISOUT)
88                         goto multiple_use;
89                 check_inverse(optarg, &invert, &optind, 0);
90                 info->bitmask |= IPT_PHYSDEV_OP_ISOUT;
91                 if (invert)
92                         info->invert |= IPT_PHYSDEV_OP_ISOUT;
93                 *flags |= IPT_PHYSDEV_OP_ISOUT;
94                 break;
95
96         case '5':
97                 if (*flags & IPT_PHYSDEV_OP_BRIDGED)
98                         goto multiple_use;
99                 check_inverse(optarg, &invert, &optind, 0);
100                 if (invert)
101                         info->invert |= IPT_PHYSDEV_OP_BRIDGED;
102                 *flags |= IPT_PHYSDEV_OP_BRIDGED;
103                 info->bitmask |= IPT_PHYSDEV_OP_BRIDGED;
104                 break;
105
106         default:
107                 return 0;
108         }
109
110         return 1;
111 multiple_use:
112         exit_error(PARAMETER_PROBLEM,
113            "multiple use of the same physdev option is not allowed");
114
115 }
116
117 static void final_check(unsigned int flags)
118 {
119         if (flags == 0)
120                 exit_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified");
121 }
122
123 static void
124 print(const struct ipt_ip *ip,
125       const struct ipt_entry_match *match,
126       int numeric)
127 {
128         struct ipt_physdev_info *info =
129                 (struct ipt_physdev_info*)match->data;
130
131         printf("PHYSDEV match");
132         if (info->bitmask & IPT_PHYSDEV_OP_ISIN)
133                 printf("%s --physdev-is-in",
134                        info->invert & IPT_PHYSDEV_OP_ISIN ? " !":"");
135         if (info->bitmask & IPT_PHYSDEV_OP_IN)
136                 printf("%s --physdev-in %s",
137                 (info->invert & IPT_PHYSDEV_OP_IN) ? " !":"", info->physindev);
138
139         if (info->bitmask & IPT_PHYSDEV_OP_ISOUT)
140                 printf("%s --physdev-is-out",
141                        info->invert & IPT_PHYSDEV_OP_ISOUT ? " !":"");
142         if (info->bitmask & IPT_PHYSDEV_OP_OUT)
143                 printf("%s --physdev-out %s",
144                 (info->invert & IPT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
145         if (info->bitmask & IPT_PHYSDEV_OP_BRIDGED)
146                 printf("%s --physdev-is-bridged",
147                        info->invert & IPT_PHYSDEV_OP_BRIDGED ? " !":"");
148         printf(" ");
149 }
150
151 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
152 {
153         struct ipt_physdev_info *info =
154                 (struct ipt_physdev_info*)match->data;
155
156         if (info->bitmask & IPT_PHYSDEV_OP_ISIN)
157                 printf("%s --physdev-is-in",
158                        info->invert & IPT_PHYSDEV_OP_ISIN ? " !":"");
159         if (info->bitmask & IPT_PHYSDEV_OP_IN)
160                 printf("%s --physdev-in %s",
161                 (info->invert & IPT_PHYSDEV_OP_IN) ? " !":"", info->physindev);
162
163         if (info->bitmask & IPT_PHYSDEV_OP_ISOUT)
164                 printf("%s --physdev-is-out",
165                        info->invert & IPT_PHYSDEV_OP_ISOUT ? " !":"");
166         if (info->bitmask & IPT_PHYSDEV_OP_OUT)
167                 printf("%s --physdev-out %s",
168                 (info->invert & IPT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
169         if (info->bitmask & IPT_PHYSDEV_OP_BRIDGED)
170                 printf("%s --physdev-is-bridged",
171                        info->invert & IPT_PHYSDEV_OP_BRIDGED ? " !":"");
172         printf(" ");
173 }
174
175 static struct iptables_match physdev = { 
176         .next           = NULL,
177         .name           = "physdev",
178         .version        = IPTABLES_VERSION,
179         .size           = IPT_ALIGN(sizeof(struct ipt_physdev_info)),
180         .userspacesize  = IPT_ALIGN(sizeof(struct ipt_physdev_info)),
181         .help           = &help,
182         .init           = &init,
183         .parse          = &parse,
184         .final_check    = &final_check,
185         .print          = &print,
186         .save           = &save,
187         .extra_opts     = opts
188 };
189
190 void _init(void)
191 {
192         register_match(&physdev);
193 }