(no commit message)
[strongswan.git] / src / charon / config / traffic_selector.c
1 /**
2 * @file traffic_selector.c
3 *
4 * @brief Implementation of traffic_selector_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "traffic_selector.h"
24
25 #include <utils/linked_list.h>
26 #include <utils/identification.h>
27 #include <arpa/inet.h>
28 #include <string.h>
29
30 typedef struct private_traffic_selector_t private_traffic_selector_t;
31
32 /**
33 * Private data of an traffic_selector_t object
34 */
35 struct private_traffic_selector_t {
36
37 /**
38 * Public part
39 */
40 traffic_selector_t public;
41
42 /**
43 * Type of address
44 */
45 ts_type_t type;
46
47 /**
48 * IP protocol (UDP, TCP, ICMP, ...)
49 */
50 u_int8_t protocol;
51
52 /**
53 * begin of address range, host order
54 */
55 union {
56 u_int32_t from_addr_ipv4;
57 };
58
59 /**
60 * end of address range, host order
61 */
62 union {
63 u_int32_t to_addr_ipv4;
64 };
65
66 /**
67 * begin of port range
68 */
69 u_int16_t from_port;
70
71 /**
72 * end of port range
73 */
74 u_int16_t to_port;
75 };
76
77 /**
78 * internal generic constructor
79 */
80 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port);
81
82 /**
83 * implements traffic_selector_t.get_subset
84 */
85 static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
86 {
87 if ((this->type == TS_IPV4_ADDR_RANGE) &&
88 (other->type == TS_IPV4_ADDR_RANGE) &&
89 (this->protocol == other->protocol))
90 {
91 u_int32_t from_addr, to_addr;
92 u_int16_t from_port, to_port;
93 private_traffic_selector_t *new_ts;
94
95 /* calculate the maximum address range allowed for both */
96 from_addr = max(this->from_addr_ipv4, other->from_addr_ipv4);
97 to_addr = min(this->to_addr_ipv4, other->to_addr_ipv4);
98 if (from_addr > to_addr)
99 {
100 /* no match */
101 return NULL;
102 }
103
104 /* calculate the maximum port range allowed for both */
105 from_port = max(this->from_port, other->from_port);
106 to_port = min(this->to_port, other->to_port);
107 if (from_port > to_port)
108 {
109 /* no match */
110 return NULL;
111 }
112
113 /* got a match, return it */
114 new_ts = traffic_selector_create(this->protocol, this->type, from_port, to_port);
115 new_ts->from_addr_ipv4 = from_addr;
116 new_ts->to_addr_ipv4 = to_addr;
117 new_ts->type = TS_IPV4_ADDR_RANGE;
118 return &(new_ts->public);
119 }
120 return NULL;
121 }
122
123 /**
124 * Implements traffic_selector_t.get_from_address.
125 */
126 static chunk_t get_from_address(private_traffic_selector_t *this)
127 {
128 chunk_t from_addr = CHUNK_INITIALIZER;
129
130 switch (this->type)
131 {
132 case TS_IPV4_ADDR_RANGE:
133 {
134 u_int32_t network;
135 from_addr.len = sizeof(network);
136 from_addr.ptr = malloc(from_addr.len);
137 /* chunk must contain network order, convert! */
138 network = htonl(this->from_addr_ipv4);
139 memcpy(from_addr.ptr, &network, from_addr.len);
140 break;
141 }
142 case TS_IPV6_ADDR_RANGE:
143 {
144 break;
145 }
146 }
147 return from_addr;
148 }
149
150 /**
151 * Implements traffic_selector_t.get_to_address.
152 */
153 static chunk_t get_to_address(private_traffic_selector_t *this)
154 {
155 chunk_t to_addr = CHUNK_INITIALIZER;
156
157 switch (this->type)
158 {
159 case TS_IPV4_ADDR_RANGE:
160 {
161 u_int32_t network;
162 to_addr.len = sizeof(network);
163 to_addr.ptr = malloc(to_addr.len);
164 /* chunk must contain network order, convert! */
165 network = htonl(this->to_addr_ipv4);
166 memcpy(to_addr.ptr, &network, to_addr.len);
167 break;
168 }
169 case TS_IPV6_ADDR_RANGE:
170 {
171 break;
172 }
173 }
174 return to_addr;
175 }
176
177 /**
178 * Implements traffic_selector_t.get_from_port.
179 */
180 static u_int16_t get_from_port(private_traffic_selector_t *this)
181 {
182 return this->from_port;
183 }
184
185 /**
186 * Implements traffic_selector_t.get_to_port.
187 */
188 static u_int16_t get_to_port(private_traffic_selector_t *this)
189 {
190 return this->to_port;
191 }
192
193 /**
194 * Implements traffic_selector_t.get_type.
195 */
196 static ts_type_t get_type(private_traffic_selector_t *this)
197 {
198 return this->type;
199 }
200
201 /**
202 * Implements traffic_selector_t.get_protocol.
203 */
204 static u_int8_t get_protocol(private_traffic_selector_t *this)
205 {
206 return this->protocol;
207 }
208
209 /**
210 * Implements traffic_selector_t.get_netmask.
211 */
212 static u_int8_t get_netmask(private_traffic_selector_t *this)
213 {
214 switch (this->type)
215 {
216 case TS_IPV4_ADDR_RANGE:
217 {
218 u_int32_t from, to, bit;
219 from = htonl(this->from_addr_ipv4);
220 to = htonl(this->to_addr_ipv4);
221 for (bit = 0; bit < 32; bit++)
222 {
223 if ((1<<bit & from) != (1<<bit & to))
224 {
225 return bit;
226 }
227 }
228 return 32;
229 }
230 case TS_IPV6_ADDR_RANGE:
231 default:
232 {
233 return 0;
234 }
235 }
236 }
237
238 /**
239 * Implements traffic_selector_t.update_address_range.
240 */
241 static void update_address_range(private_traffic_selector_t *this, host_t *host)
242 {
243 if (host->get_family(host) == AF_INET &&
244 this->type == TS_IPV4_ADDR_RANGE)
245 {
246 if (this->from_addr_ipv4 == 0)
247 {
248 chunk_t from = host->get_address_as_chunk(host);
249 this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
250 this->to_addr_ipv4 = this->from_addr_ipv4;
251 chunk_free(&from);
252 }
253 }
254 }
255
256 /**
257 * Implements traffic_selector_t.clone.
258 */
259 static traffic_selector_t *clone(private_traffic_selector_t *this)
260 {
261 private_traffic_selector_t *clone = traffic_selector_create(this->protocol, this->type, this->from_port, this->to_port);
262 clone->type = this->type;
263 switch (clone->type)
264 {
265 case TS_IPV4_ADDR_RANGE:
266 {
267 clone->from_addr_ipv4 = this->from_addr_ipv4;
268 clone->to_addr_ipv4 = this->to_addr_ipv4;
269 return &(clone->public);
270 }
271 case TS_IPV6_ADDR_RANGE:
272 default:
273 {
274 free(this);
275 return NULL;
276 }
277 }
278 }
279
280 /**
281 * Implements traffic_selector_t.destroy.
282 */
283 static void destroy(private_traffic_selector_t *this)
284 {
285 free(this);
286 }
287
288 /*
289 * see header
290 */
291 traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, int16_t from_port, chunk_t to_addr, u_int16_t to_port)
292 {
293 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
294
295 this->type = type;
296 switch (type)
297 {
298 case TS_IPV4_ADDR_RANGE:
299 {
300 if (from_addr.len != 4 || to_addr.len != 4)
301 {
302 free(this);
303 return NULL;
304 }
305 /* chunk contains network order, convert! */
306 this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr));
307 this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr));
308 break;
309 }
310 case TS_IPV6_ADDR_RANGE:
311 default:
312 {
313 free(this);
314 return NULL;
315 }
316 }
317 return (&this->public);
318 }
319
320 /*
321 * see header
322 */
323 traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits)
324 {
325 private_traffic_selector_t *this = traffic_selector_create(0, 0, 0, 65535);
326
327 switch (net->get_family(net))
328 {
329 case AF_INET:
330 {
331 chunk_t from;
332
333 this->type = TS_IPV4_ADDR_RANGE;
334 from = net->get_address_as_chunk(net);
335 this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
336 if (this->from_addr_ipv4 == 0)
337 {
338 /* use /32 for 0.0.0.0 */
339 this->to_addr_ipv4 = 0xFFFFFF;
340 }
341 else
342 {
343 this->to_addr_ipv4 = this->from_addr_ipv4 | ((1 << (32 - netbits)) - 1);
344 }
345 chunk_free(&from);
346 break;
347 }
348 case AF_INET6:
349 default:
350 {
351 free(this);
352 return NULL;
353 }
354 }
355 return (&this->public);
356 }
357
358 /*
359 * see header
360 */
361 traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_type_t type, char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port)
362 {
363 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
364
365 /* public functions */
366 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
367 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
368
369 this->type = type;
370 switch (type)
371 {
372 case TS_IPV4_ADDR_RANGE:
373 {
374 if (inet_aton(from_addr, (struct in_addr*)&(this->from_addr_ipv4)) == 0)
375 {
376 free(this);
377 return NULL;
378 }
379 if (inet_aton(to_addr, (struct in_addr*)&(this->to_addr_ipv4)) == 0)
380 {
381 free(this);
382 return NULL;
383 }
384 /* convert to host order, inet_aton has network order */
385 this->from_addr_ipv4 = ntohl(this->from_addr_ipv4);
386 this->to_addr_ipv4 = ntohl(this->to_addr_ipv4);
387 break;
388 }
389 case TS_IPV6_ADDR_RANGE:
390 {
391 free(this);
392 return NULL;
393 }
394 }
395
396 return (&this->public);
397 }
398
399 /*
400 * see declaration
401 */
402 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port)
403 {
404 private_traffic_selector_t *this = malloc_thing(private_traffic_selector_t);
405
406 /* public functions */
407 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
408 this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
409 this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
410 this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port;
411 this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port;
412 this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
413 this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
414 this->public.get_netmask = (u_int8_t(*)(traffic_selector_t*))get_netmask;
415 this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
416 this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone;
417 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
418
419 this->from_port = from_port;
420 this->to_port = to_port;
421 this->protocol = protocol;
422 this->type = type;
423
424 return this;
425 }