iptables-1.2.9-2.3.1.src.rpm
[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                 *nfcache |= NFC_IP6_SRC_PT;
113                 break;
114
115         case '2':
116                 if (*flags & UDP_DST_PORTS)
117                         exit_error(PARAMETER_PROBLEM,
118                                    "Only one `--destination-port' allowed");
119                 check_inverse(optarg, &invert, &optind, 0);
120                 parse_udp_ports(argv[optind-1], udpinfo->dpts);
121                 if (invert)
122                         udpinfo->invflags |= IP6T_UDP_INV_DSTPT;
123                 *flags |= UDP_DST_PORTS;
124                 *nfcache |= NFC_IP6_DST_PT;
125                 break;
126
127         default:
128                 return 0;
129         }
130
131         return 1;
132 }
133
134 /* Final check; we don't care. */
135 static void
136 final_check(unsigned int flags)
137 {
138 }
139
140 static char *
141 port_to_service(int port)
142 {
143         struct servent *service;
144
145         if ((service = getservbyport(htons(port), "udp")))
146                 return service->s_name;
147
148         return NULL;
149 }
150
151 static void
152 print_port(u_int16_t port, int numeric)
153 {
154         char *service;
155
156         if (numeric || (service = port_to_service(port)) == NULL)
157                 printf("%u", port);
158         else
159                 printf("%s", service);
160 }
161
162 static void
163 print_ports(const char *name, u_int16_t min, u_int16_t max,
164             int invert, int numeric)
165 {
166         const char *inv = invert ? "!" : "";
167
168         if (min != 0 || max != 0xFFFF || invert) {
169                 printf("%s", name);
170                 if (min == max) {
171                         printf(":%s", inv);
172                         print_port(min, numeric);
173                 } else {
174                         printf("s:%s", inv);
175                         print_port(min, numeric);
176                         printf(":");
177                         print_port(max, numeric);
178                 }
179                 printf(" ");
180         }
181 }
182
183 /* Prints out the union ipt_matchinfo. */
184 static void
185 print(const struct ip6t_ip6 *ip,
186       const struct ip6t_entry_match *match, int numeric)
187 {
188         const struct ip6t_udp *udp = (struct ip6t_udp *)match->data;
189
190         printf("udp ");
191         print_ports("spt", udp->spts[0], udp->spts[1],
192                     udp->invflags & IP6T_UDP_INV_SRCPT,
193                     numeric);
194         print_ports("dpt", udp->dpts[0], udp->dpts[1],
195                     udp->invflags & IP6T_UDP_INV_DSTPT,
196                     numeric);
197         if (udp->invflags & ~IP6T_UDP_INV_MASK)
198                 printf("Unknown invflags: 0x%X ",
199                        udp->invflags & ~IP6T_UDP_INV_MASK);
200 }
201
202 /* Saves the union ipt_matchinfo in parsable form to stdout. */
203 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
204 {
205         const struct ip6t_udp *udpinfo = (struct ip6t_udp *)match->data;
206
207         if (udpinfo->spts[0] != 0
208             || udpinfo->spts[1] != 0xFFFF) {
209                 if (udpinfo->invflags & IP6T_UDP_INV_SRCPT)
210                         printf("! ");
211                 if (udpinfo->spts[0]
212                     != udpinfo->spts[1])
213                         printf("--sport %u:%u ",
214                                udpinfo->spts[0],
215                                udpinfo->spts[1]);
216                 else
217                         printf("--sport %u ",
218                                udpinfo->spts[0]);
219         }
220
221         if (udpinfo->dpts[0] != 0
222             || udpinfo->dpts[1] != 0xFFFF) {
223                 if (udpinfo->invflags & IP6T_UDP_INV_DSTPT)
224                         printf("! ");
225                 if (udpinfo->dpts[0]
226                     != udpinfo->dpts[1])
227                         printf("--dport %u:%u ",
228                                udpinfo->dpts[0],
229                                udpinfo->dpts[1]);
230                 else
231                         printf("--dport %u ",
232                                udpinfo->dpts[0]);
233         }
234 }
235
236 static
237 struct ip6tables_match udp
238 = { NULL,
239     "udp",
240     IPTABLES_VERSION,
241     IP6T_ALIGN(sizeof(struct ip6t_udp)),
242     IP6T_ALIGN(sizeof(struct ip6t_udp)),
243     &help,
244     &init,
245     &parse,
246     &final_check,
247     &print,
248     &save,
249     opts
250 };
251
252 void
253 _init(void)
254 {
255         register_match6(&udp);
256 }