blob: 7fa537e05396679afd8646585e3bf13c629d9122 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add multiple TCP port support. */
Jan Engelhardt32b8e612010-07-23 21:16:14 +02002#include <stdbool.h>
Marc Bouchere6869a82000-03-20 06:03:29 +00003#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +00008
9#include <xtables.h>
10#include <libiptc/libiptc.h>
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +000011#include <libiptc/libip6tc.h>
Jan Engelhardt4e418542009-02-21 03:46:37 +010012#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
Jan Engelhardtafe6b352009-02-21 03:44:36 +010013#include <linux/netfilter_ipv4/ip_tables.h>
Jan Engelhardt2bc9d342009-02-21 03:40:27 +010014#include <linux/netfilter_ipv6/ip6_tables.h>
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020015#include <linux/netfilter/xt_multiport.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000016
17/* Function which prints out usage message. */
Jan Engelhardt181dead2007-10-04 16:27:07 +000018static void multiport_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000019{
20 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020021"multiport match options:\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000022" --source-ports port[,port,port...]\n"
23" --sports ...\n"
24" match source port(s)\n"
25" --destination-ports port[,port,port...]\n"
26" --dports ...\n"
27" match destination port(s)\n"
28" --ports port[,port,port]\n"
Pablo Neira5df95472005-01-03 09:37:07 +000029" match both source and destination port(s)\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020030" NOTE: this kernel does not support port ranges in multiport.\n");
Pablo Neira5df95472005-01-03 09:37:07 +000031}
32
Jan Engelhardt181dead2007-10-04 16:27:07 +000033static void multiport_help_v1(void)
Pablo Neira5df95472005-01-03 09:37:07 +000034{
35 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020036"multiport match options:\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020037"[!] --source-ports port[,port:port,port...]\n"
Pablo Neira5df95472005-01-03 09:37:07 +000038" --sports ...\n"
39" match source port(s)\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020040"[!] --destination-ports port[,port:port,port...]\n"
Pablo Neira5df95472005-01-03 09:37:07 +000041" --dports ...\n"
42" match destination port(s)\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020043"[!] --ports port[,port:port,port]\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020044" match both source and destination port(s)\n");
Marc Bouchere6869a82000-03-20 06:03:29 +000045}
46
Jan Engelhardt181dead2007-10-04 16:27:07 +000047static const struct option multiport_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020048 {.name = "source-ports", .has_arg = true, .val = '1'},
49 {.name = "sports", .has_arg = true, .val = '1'}, /* synonym */
50 {.name = "destination-ports", .has_arg = true, .val = '2'},
51 {.name = "dports", .has_arg = true, .val = '2'}, /* synonym */
52 {.name = "ports", .has_arg = true, .val = '3'},
53 XT_GETOPT_TABLEEND,
Marc Bouchere6869a82000-03-20 06:03:29 +000054};
55
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +020056static const char *
Jan Engelhardt7ac40522011-01-07 12:34:04 +010057proto_to_name(uint8_t proto)
Patrick McHardyJesper Brouerc1eae412006-07-25 01:50:48 +000058{
59 switch (proto) {
60 case IPPROTO_TCP:
61 return "tcp";
62 case IPPROTO_UDP:
63 return "udp";
Patrick McHardy95616062007-01-11 09:08:22 +000064 case IPPROTO_UDPLITE:
65 return "udplite";
Patrick McHardyJesper Brouerc1eae412006-07-25 01:50:48 +000066 case IPPROTO_SCTP:
67 return "sctp";
68 case IPPROTO_DCCP:
69 return "dccp";
70 default:
71 return NULL;
72 }
73}
74
Marc Bouchere6869a82000-03-20 06:03:29 +000075static unsigned int
Jan Engelhardt7ac40522011-01-07 12:34:04 +010076parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto)
Marc Bouchere6869a82000-03-20 06:03:29 +000077{
78 char *buffer, *cp, *next;
79 unsigned int i;
80
81 buffer = strdup(portstring);
Jan Engelhardt1829ed42009-02-21 03:29:44 +010082 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
Marc Bouchere6869a82000-03-20 06:03:29 +000083
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +000084 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
Marc Bouchere6869a82000-03-20 06:03:29 +000085 {
86 next=strchr(cp, ',');
87 if (next) *next++='\0';
Jan Engelhardtaae6be92009-01-30 04:24:47 +010088 ports[i] = xtables_parse_port(cp, proto);
Marc Bouchere6869a82000-03-20 06:03:29 +000089 }
Jan Engelhardt1829ed42009-02-21 03:29:44 +010090 if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
Marc Bouchere6869a82000-03-20 06:03:29 +000091 free(buffer);
92 return i;
93}
94
Pablo Neira5df95472005-01-03 09:37:07 +000095static void
96parse_multi_ports_v1(const char *portstring,
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +000097 struct xt_multiport_v1 *multiinfo,
Pablo Neira5df95472005-01-03 09:37:07 +000098 const char *proto)
99{
100 char *buffer, *cp, *next, *range;
101 unsigned int i;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100102 uint16_t m;
Pablo Neira5df95472005-01-03 09:37:07 +0000103
104 buffer = strdup(portstring);
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100105 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
Pablo Neira5df95472005-01-03 09:37:07 +0000106
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000107 for (i=0; i<XT_MULTI_PORTS; i++)
Pablo Neira5df95472005-01-03 09:37:07 +0000108 multiinfo->pflags[i] = 0;
109
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000110 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
Pablo Neira5df95472005-01-03 09:37:07 +0000111 next=strchr(cp, ',');
112 if (next) *next++='\0';
113 range = strchr(cp, ':');
114 if (range) {
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000115 if (i == XT_MULTI_PORTS-1)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100116 xtables_error(PARAMETER_PROBLEM,
Pablo Neira5df95472005-01-03 09:37:07 +0000117 "too many ports specified");
118 *range++ = '\0';
119 }
Jan Engelhardtaae6be92009-01-30 04:24:47 +0100120 multiinfo->ports[i] = xtables_parse_port(cp, proto);
Pablo Neira5df95472005-01-03 09:37:07 +0000121 if (range) {
122 multiinfo->pflags[i] = 1;
Jan Engelhardtaae6be92009-01-30 04:24:47 +0100123 multiinfo->ports[++i] = xtables_parse_port(range, proto);
Pablo Neira5df95472005-01-03 09:37:07 +0000124 if (multiinfo->ports[i-1] >= multiinfo->ports[i])
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100125 xtables_error(PARAMETER_PROBLEM,
Pablo Neira5df95472005-01-03 09:37:07 +0000126 "invalid portrange specified");
127 m <<= 1;
128 }
129 }
130 multiinfo->count = i;
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100131 if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
Pablo Neira5df95472005-01-03 09:37:07 +0000132 free(buffer);
133}
134
Marc Bouchere6869a82000-03-20 06:03:29 +0000135static const char *
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100136check_proto(uint16_t pnum, uint8_t invflags)
Marc Bouchere6869a82000-03-20 06:03:29 +0000137{
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200138 const char *proto;
Patrick McHardy2452baf2006-04-28 08:10:08 +0000139
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000140 if (invflags & XT_INV_PROTO)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100141 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy95616062007-01-11 09:08:22 +0000142 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
Rusty Russell225f4622005-01-03 09:51:58 +0000143
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000144 if ((proto = proto_to_name(pnum)) != NULL)
Patrick McHardy2452baf2006-04-28 08:10:08 +0000145 return proto;
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000146 else if (!pnum)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100147 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy95616062007-01-11 09:08:22 +0000148 "multiport needs `-p tcp', `-p udp', `-p udplite', "
149 "`-p sctp' or `-p dccp'");
Marc Bouchere6869a82000-03-20 06:03:29 +0000150 else
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100151 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy95616062007-01-11 09:08:22 +0000152 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
Marc Bouchere6869a82000-03-20 06:03:29 +0000153}
154
155/* Function which parses command options; returns true if it
156 ate an option */
157static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000158__multiport_parse(int c, char **argv, int invert, unsigned int *flags,
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100159 struct xt_entry_match **match, uint16_t pnum,
160 uint8_t invflags)
Marc Bouchere6869a82000-03-20 06:03:29 +0000161{
162 const char *proto;
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000163 struct xt_multiport *multiinfo
164 = (struct xt_multiport *)(*match)->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000165
166 switch (c) {
167 case '1':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200168 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000169 proto = check_proto(pnum, invflags);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200170 multiinfo->count = parse_multi_ports(optarg,
Marc Bouchere6869a82000-03-20 06:03:29 +0000171 multiinfo->ports, proto);
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000172 multiinfo->flags = XT_MULTIPORT_SOURCE;
Marc Bouchere6869a82000-03-20 06:03:29 +0000173 break;
174
175 case '2':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200176 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000177 proto = check_proto(pnum, invflags);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200178 multiinfo->count = parse_multi_ports(optarg,
Marc Bouchere6869a82000-03-20 06:03:29 +0000179 multiinfo->ports, proto);
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000180 multiinfo->flags = XT_MULTIPORT_DESTINATION;
Marc Bouchere6869a82000-03-20 06:03:29 +0000181 break;
182
183 case '3':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200184 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000185 proto = check_proto(pnum, invflags);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200186 multiinfo->count = parse_multi_ports(optarg,
Marc Bouchere6869a82000-03-20 06:03:29 +0000187 multiinfo->ports, proto);
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000188 multiinfo->flags = XT_MULTIPORT_EITHER;
Marc Bouchere6869a82000-03-20 06:03:29 +0000189 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000190 }
191
Patrick McHardyd0a2e8a2004-09-18 17:43:36 +0000192 if (invert)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100193 xtables_error(PARAMETER_PROBLEM,
Patrick McHardyd0a2e8a2004-09-18 17:43:36 +0000194 "multiport does not support invert");
195
Marc Bouchere6869a82000-03-20 06:03:29 +0000196 if (*flags)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100197 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +0000198 "multiport can only have one option");
199 *flags = 1;
200 return 1;
201}
202
Pablo Neira5df95472005-01-03 09:37:07 +0000203static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000204multiport_parse(int c, char **argv, int invert, unsigned int *flags,
205 const void *e, struct xt_entry_match **match)
Pablo Neira5df95472005-01-03 09:37:07 +0000206{
Yasuyuki KOZAKAIac8b2712007-07-24 06:06:59 +0000207 const struct ipt_entry *entry = e;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000208 return __multiport_parse(c, argv, invert, flags, match,
209 entry->ip.proto, entry->ip.invflags);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000210}
211
212static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000213multiport_parse6(int c, char **argv, int invert, unsigned int *flags,
214 const void *e, struct xt_entry_match **match)
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000215{
Jan Engelhardtecd48dd2009-06-08 15:46:52 +0200216 const struct ip6t_entry *entry = e;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000217 return __multiport_parse(c, argv, invert, flags, match,
218 entry->ipv6.proto, entry->ipv6.invflags);
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000219}
220
221static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000222__multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags,
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100223 struct xt_entry_match **match, uint16_t pnum,
224 uint8_t invflags)
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000225{
Pablo Neira5df95472005-01-03 09:37:07 +0000226 const char *proto;
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000227 struct xt_multiport_v1 *multiinfo
228 = (struct xt_multiport_v1 *)(*match)->data;
Pablo Neira5df95472005-01-03 09:37:07 +0000229
230 switch (c) {
231 case '1':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200232 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000233 proto = check_proto(pnum, invflags);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200234 parse_multi_ports_v1(optarg, multiinfo, proto);
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000235 multiinfo->flags = XT_MULTIPORT_SOURCE;
Pablo Neira5df95472005-01-03 09:37:07 +0000236 break;
237
238 case '2':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200239 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000240 proto = check_proto(pnum, invflags);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200241 parse_multi_ports_v1(optarg, multiinfo, proto);
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000242 multiinfo->flags = XT_MULTIPORT_DESTINATION;
Pablo Neira5df95472005-01-03 09:37:07 +0000243 break;
244
245 case '3':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200246 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000247 proto = check_proto(pnum, invflags);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200248 parse_multi_ports_v1(optarg, multiinfo, proto);
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000249 multiinfo->flags = XT_MULTIPORT_EITHER;
Pablo Neira5df95472005-01-03 09:37:07 +0000250 break;
Pablo Neira5df95472005-01-03 09:37:07 +0000251 }
252
253 if (invert)
Phil Oesterb2eedcd2005-02-02 19:20:15 +0000254 multiinfo->invert = 1;
Pablo Neira5df95472005-01-03 09:37:07 +0000255
256 if (*flags)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100257 xtables_error(PARAMETER_PROBLEM,
Pablo Neira5df95472005-01-03 09:37:07 +0000258 "multiport can only have one option");
259 *flags = 1;
260 return 1;
261}
262
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000263static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000264multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags,
265 const void *e, struct xt_entry_match **match)
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000266{
267 const struct ipt_entry *entry = e;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000268 return __multiport_parse_v1(c, argv, invert, flags, match,
269 entry->ip.proto, entry->ip.invflags);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000270}
271
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000272static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000273multiport_parse6_v1(int c, char **argv, int invert, unsigned int *flags,
274 const void *e, struct xt_entry_match **match)
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000275{
Jan Engelhardtecd48dd2009-06-08 15:46:52 +0200276 const struct ip6t_entry *entry = e;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000277 return __multiport_parse_v1(c, argv, invert, flags, match,
278 entry->ipv6.proto, entry->ipv6.invflags);
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000279}
280
Marc Bouchere6869a82000-03-20 06:03:29 +0000281/* Final check; must specify something. */
Jan Engelhardt181dead2007-10-04 16:27:07 +0000282static void multiport_check(unsigned int flags)
Marc Bouchere6869a82000-03-20 06:03:29 +0000283{
284 if (!flags)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100285 xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
Marc Bouchere6869a82000-03-20 06:03:29 +0000286}
287
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200288static const char *
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100289port_to_service(int port, uint8_t proto)
Marc Bouchere6869a82000-03-20 06:03:29 +0000290{
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200291 const struct servent *service;
Marc Bouchere6869a82000-03-20 06:03:29 +0000292
Patrick McHardyJesper Brouerc1eae412006-07-25 01:50:48 +0000293 if ((service = getservbyport(htons(port), proto_to_name(proto))))
Marc Bouchere6869a82000-03-20 06:03:29 +0000294 return service->s_name;
295
296 return NULL;
297}
298
299static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100300print_port(uint16_t port, uint8_t protocol, int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000301{
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200302 const char *service;
Marc Bouchere6869a82000-03-20 06:03:29 +0000303
304 if (numeric || (service = port_to_service(port, protocol)) == NULL)
305 printf("%u", port);
306 else
307 printf("%s", service);
308}
309
310/* Prints out the matchinfo. */
311static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000312__multiport_print(const struct xt_entry_match *match, int numeric,
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100313 uint16_t proto)
Marc Bouchere6869a82000-03-20 06:03:29 +0000314{
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000315 const struct xt_multiport *multiinfo
316 = (const struct xt_multiport *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000317 unsigned int i;
318
Jan Engelhardt73866352010-12-18 02:04:59 +0100319 printf(" multiport ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000320
321 switch (multiinfo->flags) {
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000322 case XT_MULTIPORT_SOURCE:
Marc Bouchere6869a82000-03-20 06:03:29 +0000323 printf("sports ");
324 break;
325
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000326 case XT_MULTIPORT_DESTINATION:
Marc Bouchere6869a82000-03-20 06:03:29 +0000327 printf("dports ");
328 break;
329
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000330 case XT_MULTIPORT_EITHER:
Marc Bouchere6869a82000-03-20 06:03:29 +0000331 printf("ports ");
332 break;
333
334 default:
335 printf("ERROR ");
336 break;
337 }
338
339 for (i=0; i < multiinfo->count; i++) {
340 printf("%s", i ? "," : "");
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000341 print_port(multiinfo->ports[i], proto, numeric);
Marc Bouchere6869a82000-03-20 06:03:29 +0000342 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000343}
344
Jan Engelhardt181dead2007-10-04 16:27:07 +0000345static void multiport_print(const void *ip_void,
346 const struct xt_entry_match *match, int numeric)
Pablo Neira5df95472005-01-03 09:37:07 +0000347{
Yasuyuki KOZAKAIac8b2712007-07-24 06:06:59 +0000348 const struct ipt_ip *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000349 __multiport_print(match, numeric, ip->proto);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000350}
351
Jan Engelhardt181dead2007-10-04 16:27:07 +0000352static void multiport_print6(const void *ip_void,
353 const struct xt_entry_match *match, int numeric)
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000354{
Jan Engelhardtecd48dd2009-06-08 15:46:52 +0200355 const struct ip6t_ip6 *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000356 __multiport_print(match, numeric, ip->proto);
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000357}
358
Jan Engelhardt181dead2007-10-04 16:27:07 +0000359static void __multiport_print_v1(const struct xt_entry_match *match,
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100360 int numeric, uint16_t proto)
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000361{
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000362 const struct xt_multiport_v1 *multiinfo
363 = (const struct xt_multiport_v1 *)match->data;
Pablo Neira5df95472005-01-03 09:37:07 +0000364 unsigned int i;
365
Jan Engelhardt73866352010-12-18 02:04:59 +0100366 printf(" multiport ");
Pablo Neira5df95472005-01-03 09:37:07 +0000367
368 switch (multiinfo->flags) {
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000369 case XT_MULTIPORT_SOURCE:
Pablo Neira5df95472005-01-03 09:37:07 +0000370 printf("sports ");
371 break;
372
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000373 case XT_MULTIPORT_DESTINATION:
Pablo Neira5df95472005-01-03 09:37:07 +0000374 printf("dports ");
375 break;
376
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000377 case XT_MULTIPORT_EITHER:
Pablo Neira5df95472005-01-03 09:37:07 +0000378 printf("ports ");
379 break;
380
381 default:
382 printf("ERROR ");
383 break;
384 }
385
Phil Oesterb2eedcd2005-02-02 19:20:15 +0000386 if (multiinfo->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100387 printf(" !");
Phil Oesterb2eedcd2005-02-02 19:20:15 +0000388
Pablo Neira5df95472005-01-03 09:37:07 +0000389 for (i=0; i < multiinfo->count; i++) {
390 printf("%s", i ? "," : "");
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000391 print_port(multiinfo->ports[i], proto, numeric);
Pablo Neira5df95472005-01-03 09:37:07 +0000392 if (multiinfo->pflags[i]) {
393 printf(":");
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000394 print_port(multiinfo->ports[++i], proto, numeric);
Pablo Neira5df95472005-01-03 09:37:07 +0000395 }
396 }
Pablo Neira5df95472005-01-03 09:37:07 +0000397}
398
Jan Engelhardt181dead2007-10-04 16:27:07 +0000399static void multiport_print_v1(const void *ip_void,
400 const struct xt_entry_match *match, int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000401{
Yasuyuki KOZAKAIac8b2712007-07-24 06:06:59 +0000402 const struct ipt_ip *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000403 __multiport_print_v1(match, numeric, ip->proto);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000404}
405
Jan Engelhardt181dead2007-10-04 16:27:07 +0000406static void multiport_print6_v1(const void *ip_void,
407 const struct xt_entry_match *match, int numeric)
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000408{
Jan Engelhardtecd48dd2009-06-08 15:46:52 +0200409 const struct ip6t_ip6 *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000410 __multiport_print_v1(match, numeric, ip->proto);
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000411}
412
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000413/* Saves the union ipt_matchinfo in parsable form to stdout. */
Jan Engelhardt181dead2007-10-04 16:27:07 +0000414static void __multiport_save(const struct xt_entry_match *match,
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100415 uint16_t proto)
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000416{
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000417 const struct xt_multiport *multiinfo
418 = (const struct xt_multiport *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000419 unsigned int i;
420
421 switch (multiinfo->flags) {
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000422 case XT_MULTIPORT_SOURCE:
Jan Engelhardt73866352010-12-18 02:04:59 +0100423 printf(" --sports ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000424 break;
425
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000426 case XT_MULTIPORT_DESTINATION:
Jan Engelhardt73866352010-12-18 02:04:59 +0100427 printf(" --dports ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000428 break;
429
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000430 case XT_MULTIPORT_EITHER:
Jan Engelhardt73866352010-12-18 02:04:59 +0100431 printf(" --ports ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000432 break;
433 }
434
435 for (i=0; i < multiinfo->count; i++) {
436 printf("%s", i ? "," : "");
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000437 print_port(multiinfo->ports[i], proto, 1);
Marc Bouchere6869a82000-03-20 06:03:29 +0000438 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000439}
440
Jan Engelhardt181dead2007-10-04 16:27:07 +0000441static void multiport_save(const void *ip_void,
442 const struct xt_entry_match *match)
Pablo Neira5df95472005-01-03 09:37:07 +0000443{
Yasuyuki KOZAKAIac8b2712007-07-24 06:06:59 +0000444 const struct ipt_ip *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000445 __multiport_save(match, ip->proto);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000446}
447
Jan Engelhardt181dead2007-10-04 16:27:07 +0000448static void multiport_save6(const void *ip_void,
449 const struct xt_entry_match *match)
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000450{
Jan Engelhardtecd48dd2009-06-08 15:46:52 +0200451 const struct ip6t_ip6 *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000452 __multiport_save(match, ip->proto);
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000453}
454
Jan Engelhardt181dead2007-10-04 16:27:07 +0000455static void __multiport_save_v1(const struct xt_entry_match *match,
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100456 uint16_t proto)
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000457{
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000458 const struct xt_multiport_v1 *multiinfo
459 = (const struct xt_multiport_v1 *)match->data;
Pablo Neira5df95472005-01-03 09:37:07 +0000460 unsigned int i;
461
Jan Engelhardtcea9f712008-12-09 15:06:20 +0100462 if (multiinfo->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100463 printf(" !");
Jan Engelhardtcea9f712008-12-09 15:06:20 +0100464
Pablo Neira5df95472005-01-03 09:37:07 +0000465 switch (multiinfo->flags) {
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000466 case XT_MULTIPORT_SOURCE:
Jan Engelhardt73866352010-12-18 02:04:59 +0100467 printf(" --sports ");
Pablo Neira5df95472005-01-03 09:37:07 +0000468 break;
469
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000470 case XT_MULTIPORT_DESTINATION:
Jan Engelhardt73866352010-12-18 02:04:59 +0100471 printf(" --dports ");
Pablo Neira5df95472005-01-03 09:37:07 +0000472 break;
473
Yasuyuki KOZAKAIeb6e65e2007-07-24 06:45:03 +0000474 case XT_MULTIPORT_EITHER:
Jan Engelhardt73866352010-12-18 02:04:59 +0100475 printf(" --ports ");
Pablo Neira5df95472005-01-03 09:37:07 +0000476 break;
477 }
478
479 for (i=0; i < multiinfo->count; i++) {
480 printf("%s", i ? "," : "");
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000481 print_port(multiinfo->ports[i], proto, 1);
Pablo Neira5df95472005-01-03 09:37:07 +0000482 if (multiinfo->pflags[i]) {
483 printf(":");
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000484 print_port(multiinfo->ports[++i], proto, 1);
Pablo Neira5df95472005-01-03 09:37:07 +0000485 }
486 }
Pablo Neira5df95472005-01-03 09:37:07 +0000487}
488
Jan Engelhardt181dead2007-10-04 16:27:07 +0000489static void multiport_save_v1(const void *ip_void,
490 const struct xt_entry_match *match)
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000491{
492 const struct ipt_ip *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000493 __multiport_save_v1(match, ip->proto);
Yasuyuki KOZAKAIf451b572007-07-24 06:46:08 +0000494}
495
Jan Engelhardt181dead2007-10-04 16:27:07 +0000496static void multiport_save6_v1(const void *ip_void,
497 const struct xt_entry_match *match)
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000498{
Jan Engelhardtecd48dd2009-06-08 15:46:52 +0200499 const struct ip6t_ip6 *ip = ip_void;
Jan Engelhardt181dead2007-10-04 16:27:07 +0000500 __multiport_save_v1(match, ip->proto);
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000501}
502
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200503static struct xtables_match multiport_mt_reg[] = {
504 {
505 .family = NFPROTO_IPV4,
506 .name = "multiport",
507 .revision = 0,
508 .version = XTABLES_VERSION,
509 .size = XT_ALIGN(sizeof(struct xt_multiport)),
510 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
511 .help = multiport_help,
512 .parse = multiport_parse,
513 .final_check = multiport_check,
514 .print = multiport_print,
515 .save = multiport_save,
516 .extra_opts = multiport_opts,
517 },
518 {
519 .family = NFPROTO_IPV6,
520 .name = "multiport",
521 .revision = 0,
522 .version = XTABLES_VERSION,
523 .size = XT_ALIGN(sizeof(struct xt_multiport)),
524 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
525 .help = multiport_help,
526 .parse = multiport_parse6,
527 .final_check = multiport_check,
528 .print = multiport_print6,
529 .save = multiport_save6,
530 .extra_opts = multiport_opts,
531 },
532 {
533 .family = NFPROTO_IPV4,
534 .name = "multiport",
535 .version = XTABLES_VERSION,
536 .revision = 1,
537 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
538 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
539 .help = multiport_help_v1,
540 .parse = multiport_parse_v1,
541 .final_check = multiport_check,
542 .print = multiport_print_v1,
543 .save = multiport_save_v1,
544 .extra_opts = multiport_opts,
545 },
546 {
547 .family = NFPROTO_IPV6,
548 .name = "multiport",
549 .version = XTABLES_VERSION,
550 .revision = 1,
551 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
552 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
553 .help = multiport_help_v1,
554 .parse = multiport_parse6_v1,
555 .final_check = multiport_check,
556 .print = multiport_print6_v1,
557 .save = multiport_save6_v1,
558 .extra_opts = multiport_opts,
559 },
Yasuyuki KOZAKAIdf2cf4f2007-07-24 06:49:15 +0000560};
561
Marc Bouchere6869a82000-03-20 06:03:29 +0000562void
563_init(void)
564{
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200565 xtables_register_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
Marc Bouchere6869a82000-03-20 06:03:29 +0000566}