iptables-1.3.2-20050720
[iptables.git] / extensions / libip6t_udp.c
1 /* Shared library add-on to iptables to add UDP 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/ip6_tables.h>
9
10 /* Function which prints out usage message. */
11 static void
12 help(void)
13 {
14         printf(
15 "UDP v%s options:\n"
16 " --source-port [!] port[:port]\n"
17 " --sport ...\n"
18 "                               match source port(s)\n"
19 " --destination-port [!] port[:port]\n"
20 " --dport ...\n"
21 "                               match destination port(s)\n",
22 IPTABLES_VERSION);
23 }
24
25 static struct option opts[] = {
26         { "source-port", 1, 0, '1' },
27         { "sport", 1, 0, '1' }, /* synonym */
28         { "destination-port", 1, 0, '2' },
29         { "dport", 1, 0, '2' }, /* synonym */
30         {0}
31 };
32
33 static int
34 service_to_port(const char *name)
35 {
36         struct servent *service;
37
38         if ((service = getservbyname(name, "udp")) != NULL)
39                 return ntohs((unsigned short) service->s_port);
40
41                 return -1;
42 }
43
44 static u_int16_t
45 parse_udp_port(const char *port)
46 {
47         unsigned int portnum;
48
49         if (string_to_number(port, 0, 65535, &portnum) != -1 ||
50             (portnum = service_to_port(port)) != -1)
51                 return (u_int16_t)portnum;
52
53                 exit_error(PARAMETER_PROBLEM,
54                            "invalid UDP port/service `%s' specified", port);
55         }
56
57 static void
58 parse_udp_ports(const char *portstring, u_int16_t *ports)
59 {
60         char *buffer;
61         char *cp;
62
63         buffer = strdup(portstring);
64         if ((cp = strchr(buffer, ':')) == NULL)
65                 ports[0] = ports[1] = parse_udp_port(buffer);
66         else {
67                 *cp = '\0';
68                 cp++;
69
70                 ports[0] = buffer[0] ? parse_udp_port(buffer) : 0;
71                 ports[1] = cp[0] ? parse_udp_port(cp) : 0xFFFF;
72
73                 if (ports[0] > ports[1])
74                         exit_error(PARAMETER_PROBLEM,
75                                    "invalid portrange (min > max)");
76         }
77         free(buffer);
78 }
79
80 /* Initialize the match. */
81 static void
82 init(struct ip6t_entry_match *m, unsigned int *nfcache)
83 {
84         struct ip6t_udp *udpinfo = (struct ip6t_udp *)m->data;
85
86         udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
87 }
88
89 #define UDP_SRC_PORTS 0x01
90 #define UDP_DST_PORTS 0x02
91
92 /* Function which parses command options; returns true if it
93    ate an option */
94 static int
95 parse(int c, char **argv, int invert, unsigned int *flags,
96       const struct ip6t_entry *entry,
97       unsigned int *nfcache,
98       struct ip6t_entry_match **match)
99 {
100         struct ip6t_udp *udpinfo = (struct ip6t_udp *)(*match)->data;
101
102         switch (c) {
103         case '1':
104                 if (*flags & UDP_SRC_PORTS)
105                         exit_error(PARAMETER_PROBLEM,
106                                    "Only one `--source-port' allowed");
107                 check_inverse(optarg, &invert, &optind, 0);
108                 parse_udp_ports(argv[optind-1], udpinfo->spts);
109                 if (invert)
110                         udpinfo->invflags |= IP6T_UDP_INV_SRCPT;
111                 *flags |= UDP_SRC_PORTS;
112                 break;
113
114         case '2':
115                 if (*flags & UDP_DST_PORTS)
116                         exit_error(PARAMETER_PROBLEM,
117                                    "Only one `--destination-port' allowed");
118                 check_inverse(optarg, &invert, &optind, 0);
119                 parse_udp_ports(argv[optind-1], udpinfo->dpts);
120                 if (invert)
121                         udpinfo->invflags |= IP6T_UDP_INV_DSTPT;
122                 *flags |= UDP_DST_PORTS;
123                 break;
124
125         default:
126                 return 0;
127         }
128
129         return 1;
130 }
131
132 /* Final check; we don't care. */
133 static void
134 final_check(unsigned int flags)
135 {
136 }
137
138 static char *
139 port_to_service(int port)
140 {
141         struct servent *service;
142
143         if ((service = getservbyport(htons(port), "udp")))
144                 return service->s_name;
145
146         return NULL;
147 }
148
149 static void
150 print_port(u_int16_t port, int numeric)
151 {
152         char *service;
153
154         if (numeric || (service = port_to_service(port)) == NULL)
155                 printf("%u", port);
156         else
157                 printf("%s", service);
158 }
159
160 static void
161 print_ports(const char *name, u_int16_t min, u_int16_t max,
162             int invert, int numeric)
163 {
164         const char *inv = invert ? "!" : "";
165
166         if (min != 0 || max != 0xFFFF || invert) {
167                 printf("%s", name);
168                 if (min == max) {
169                         printf(":%s", inv);
170                         print_port(min, numeric);
171                 } else {
172                         printf("s:%s", inv);
173                         print_port(min, numeric);
174                         printf(":");
175                         print_port(max, numeric);
176                 }
177                 printf(" ");
178         }
179 }
180
181 /* Prints out the union ipt_matchinfo. */
182 static void
183 print(const struct ip6t_ip6 *ip,
184       const struct ip6t_entry_match *match, int numeric)
185 {
186         const struct ip6t_udp *udp = (struct ip6t_udp *)match->data;
187
188         printf("udp ");
189         print_ports("spt", udp->spts[0], udp->spts[1],
190                     udp->invflags & IP6T_UDP_INV_SRCPT,
191                     numeric);
192         print_ports("dpt", udp->dpts[0], udp->dpts[1],
193                     udp->invflags & IP6T_UDP_INV_DSTPT,
194                     numeric);
195         if (udp->invflags & ~IP6T_UDP_INV_MASK)
196                 printf("Unknown invflags: 0x%X ",
197                        udp->invflags & ~IP6T_UDP_INV_MASK);
198 }
199
200 /* Saves the union ipt_matchinfo in parsable form to stdout. */
201 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
202 {
203         const struct ip6t_udp *udpinfo = (struct ip6t_udp *)match->data;
204
205         if (udpinfo->spts[0] != 0
206             || udpinfo->spts[1] != 0xFFFF) {
207                 if (udpinfo->invflags & IP6T_UDP_INV_SRCPT)
208                         printf("! ");
209                 if (udpinfo->spts[0]
210                     != udpinfo->spts[1])
211                         printf("--sport %u:%u ",
212                                udpinfo->spts[0],
213                                udpinfo->spts[1]);
214                 else
215                         printf("--sport %u ",
216                                udpinfo->spts[0]);
217         }
218
219         if (udpinfo->dpts[0] != 0
220             || udpinfo->dpts[1] != 0xFFFF) {
221                 if (udpinfo->invflags & IP6T_UDP_INV_DSTPT)
222                         printf("! ");
223                 if (udpinfo->dpts[0]
224                     != udpinfo->dpts[1])
225                         printf("--dport %u:%u ",
226                                udpinfo->dpts[0],
227                                udpinfo->dpts[1]);
228                 else
229                         printf("--dport %u ",
230                                udpinfo->dpts[0]);
231         }
232 }
233
234 static struct ip6tables_match udp = {
235         .name           = "udp",
236         .version        = IPTABLES_VERSION,
237         .size           = IP6T_ALIGN(sizeof(struct ip6t_udp)),
238         .userspacesize  = IP6T_ALIGN(sizeof(struct ip6t_udp)),
239         .help           = &help,
240         .init           = &init,
241         .parse          = &parse,
242         .final_check    = &final_check,
243         .print          = &print,
244         .save           = &save,
245         .extra_opts     = opts,
246 };
247
248 void
249 _init(void)
250 {
251         register_match6(&udp);
252 }