iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libip6t_multiport.c
1 /* Shared library add-on to iptables to add multiple TCP port support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <ip6tables.h>
8 #include <linux/netfilter_ipv6/ip6t_multiport.h>
9
10 /* Function which prints out usage message. */
11 static void
12 help(void)
13 {
14         printf(
15 "multiport v%s options:\n"
16 " --source-ports port[,port,port...]\n"
17 " --sports ...\n"
18 "                               match source port(s)\n"
19 " --destination-ports port[,port,port...]\n"
20 " --dports ...\n"
21 "                               match destination port(s)\n"
22 " --ports port[,port,port]\n"
23 "                               match both source and destination port(s)\n",
24 IPTABLES_VERSION);
25 }
26
27 static struct option opts[] = {
28         { "source-ports", 1, 0, '1' },
29         { "sports", 1, 0, '1' }, /* synonym */
30         { "destination-ports", 1, 0, '2' },
31         { "dports", 1, 0, '2' }, /* synonym */
32         { "ports", 1, 0, '3' },
33         {0}
34 };
35
36 static int
37 service_to_port(const char *name, const char *proto)
38 {
39         struct servent *service;
40
41         if ((service = getservbyname(name, proto)) != NULL)
42                 return ntohs((unsigned short) service->s_port);
43
44                 return -1;
45 }
46
47 static u_int16_t
48 parse_port(const char *port, const char *proto)
49 {
50         unsigned int portnum;
51
52         if ((string_to_number(port, 0, 65535, &portnum)) != -1 ||
53             (portnum = service_to_port(port, proto)) != -1)
54                 return (u_int16_t)portnum;
55
56         exit_error(PARAMETER_PROBLEM,
57                    "invalid port/service `%s' specified", port);
58 }
59
60 static unsigned int
61 parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
62 {
63         char *buffer, *cp, *next;
64         unsigned int i;
65
66         buffer = strdup(portstring);
67         if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
68
69         for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next,i++)
70         {
71                 next=strchr(cp, ',');
72                 if (next) *next++='\0';
73                 ports[i] = parse_port(cp, proto);
74         }
75         if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
76         free(buffer);
77         return i;
78 }
79
80 /* Initialize the match. */
81 static void
82 init(struct ip6t_entry_match *m, unsigned int *nfcache)
83 {
84 }
85
86 static const char *
87 check_proto(const struct ip6t_entry *entry)
88 {
89         if (entry->ipv6.proto == IPPROTO_TCP)
90                 return "tcp";
91         else if (entry->ipv6.proto == IPPROTO_UDP)
92                 return "udp";
93         else if (!entry->ipv6.proto)
94                 exit_error(PARAMETER_PROBLEM,
95                            "multiport needs `-p tcp' or `-p udp'");
96         else
97                 exit_error(PARAMETER_PROBLEM,
98                            "multiport only works with TCP or UDP");
99 }
100
101 /* Function which parses command options; returns true if it
102    ate an option */
103 static int
104 parse(int c, char **argv, int invert, unsigned int *flags,
105       const struct ip6t_entry *entry,
106       unsigned int *nfcache,
107       struct ip6t_entry_match **match)
108 {
109         const char *proto;
110         struct ip6t_multiport *multiinfo
111                 = (struct ip6t_multiport *)(*match)->data;
112
113         switch (c) {
114         case '1':
115                 proto = check_proto(entry);
116                 multiinfo->count = parse_multi_ports(argv[optind-1],
117                                                      multiinfo->ports, proto);
118                 multiinfo->flags = IP6T_MULTIPORT_SOURCE;
119                 *nfcache |= NFC_IP6_SRC_PT;
120                 break;
121
122         case '2':
123                 proto = check_proto(entry);
124                 multiinfo->count = parse_multi_ports(argv[optind-1],
125                                                      multiinfo->ports, proto);
126                 multiinfo->flags = IP6T_MULTIPORT_DESTINATION;
127                 *nfcache |= NFC_IP6_DST_PT;
128                 break;
129
130         case '3':
131                 proto = check_proto(entry);
132                 multiinfo->count = parse_multi_ports(argv[optind-1],
133                                                      multiinfo->ports, proto);
134                 multiinfo->flags = IP6T_MULTIPORT_EITHER;
135                 *nfcache |= NFC_IP6_SRC_PT | NFC_IP6_DST_PT;
136                 break;
137
138         default:
139                 return 0;
140         }
141
142         if (*flags)
143                 exit_error(PARAMETER_PROBLEM,
144                            "multiport can only have one option");
145         *flags = 1;
146         return 1;
147 }
148
149 /* Final check; must specify something. */
150 static void
151 final_check(unsigned int flags)
152 {
153         if (!flags)
154                 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
155 }
156
157 static char *
158 port_to_service(int port, u_int8_t proto)
159 {
160         struct servent *service;
161
162         if ((service = getservbyport(htons(port),
163                                      proto == IPPROTO_TCP ? "tcp" : "udp")))
164                 return service->s_name;
165
166         return NULL;
167 }
168
169 static void
170 print_port(u_int16_t port, u_int8_t protocol, int numeric)
171 {
172         char *service;
173
174         if (numeric || (service = port_to_service(port, protocol)) == NULL)
175                 printf("%u", port);
176         else
177                 printf("%s", service);
178 }
179
180 /* Prints out the matchinfo. */
181 static void
182 print(const struct ip6t_ip6 *ip,
183       const struct ip6t_entry_match *match,
184       int numeric)
185 {
186         const struct ip6t_multiport *multiinfo
187                 = (const struct ip6t_multiport *)match->data;
188         unsigned int i;
189
190         printf("multiport ");
191
192         switch (multiinfo->flags) {
193         case IP6T_MULTIPORT_SOURCE:
194                 printf("sports ");
195                 break;
196
197         case IP6T_MULTIPORT_DESTINATION:
198                 printf("dports ");
199                 break;
200
201         case IP6T_MULTIPORT_EITHER:
202                 printf("ports ");
203                 break;
204
205         default:
206                 printf("ERROR ");
207                 break;
208         }
209
210         for (i=0; i < multiinfo->count; i++) {
211                 printf("%s", i ? "," : "");
212                 print_port(multiinfo->ports[i], ip->proto, numeric);
213         }
214         printf(" ");
215 }
216
217 /* Saves the union ip6t_matchinfo in parsable form to stdout. */
218 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
219 {
220         const struct ip6t_multiport *multiinfo
221                 = (const struct ip6t_multiport *)match->data;
222         unsigned int i;
223
224         switch (multiinfo->flags) {
225         case IP6T_MULTIPORT_SOURCE:
226                 printf("--sports ");
227                 break;
228
229         case IP6T_MULTIPORT_DESTINATION:
230                 printf("--dports ");
231                 break;
232
233         case IP6T_MULTIPORT_EITHER:
234                 printf("--ports ");
235                 break;
236         }
237
238         for (i=0; i < multiinfo->count; i++) {
239                 printf("%s", i ? "," : "");
240                 print_port(multiinfo->ports[i], ip->proto, 1);
241         }
242         printf(" ");
243 }
244
245 static
246 struct ip6tables_match multiport
247 = { NULL,
248     "multiport",
249     IPTABLES_VERSION,
250     IP6T_ALIGN(sizeof(struct ip6t_multiport)),
251     IP6T_ALIGN(sizeof(struct ip6t_multiport)),
252     &help,
253     &init,
254     &parse,
255     &final_check,
256     &print,
257     &save,
258     opts
259 };
260
261 void
262 _init(void)
263 {
264         register_match6(&multiport);
265 }