Cleanups, spelling fixes, allow symbol names for signals (-k option),
[tinc] / src / subnet.c
1 /*
2     subnet.c -- handle subnet lookups and lists
3     Copyright (C) 2000-2002 Guus Sliepen <guus@sliepen.warande.net>,
4                   2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: subnet.c,v 1.1.2.32 2002/03/11 11:23:04 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <syslog.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <netdb.h>
31 #include <netinet/in.h>
32
33 #include <utils.h>
34 #include <xalloc.h>
35 #include <avl_tree.h>
36
37 #include "conf.h"
38 #include "net.h"
39 #include "node.h"
40 #include "subnet.h"
41 #include "netutl.h"
42
43 #include "system.h"
44
45 int cache_mac_valid = 0;
46 int cache_ipv4_valid = 0;
47 int cache_ipv6_valid = 0;
48
49 /* lists type of subnet */
50
51 avl_tree_t *subnet_tree;
52
53 /* Subnet comparison */
54
55 int subnet_compare_mac(subnet_t *a, subnet_t *b)
56 {
57 cp
58   return memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
59 }
60
61 int subnet_compare_ipv4(subnet_t *a, subnet_t *b)
62 {
63   int result;
64 cp
65   result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
66   
67   if(result)
68     return result;
69
70   return a->net.ipv4.masklength - b->net.ipv4.masklength;
71 }
72
73 int subnet_compare_ipv6(subnet_t *a, subnet_t *b)
74 {
75   int result;
76 cp
77   result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
78   
79   if(result)
80     return result;
81
82   return a->net.ipv6.masklength - b->net.ipv6.masklength;
83 }
84
85 int subnet_compare(subnet_t *a, subnet_t *b)
86 {
87   int result;
88 cp  
89   result = a->type - b->type;
90  
91   if(result)
92     return result;
93     
94   switch(a->type)
95     {
96       case SUBNET_MAC:
97         return subnet_compare_mac(a, b);
98       case SUBNET_IPV4:
99         return subnet_compare_ipv4(a, b);
100       case SUBNET_IPV6:
101         return subnet_compare_ipv6(a, b);
102       default:
103         syslog(LOG_ERR, _("subnet_compare() was called with unknown subnet type %d, exitting!"), a->type);
104         cp_trace();
105         exit(0);
106     }
107
108   return 0;
109 }
110
111 /* Initialising trees */
112
113 void init_subnets(void)
114 {
115 cp
116   subnet_tree = avl_alloc_tree((avl_compare_t)subnet_compare, (avl_action_t)free_subnet);
117 cp
118 }
119
120 void exit_subnets(void)
121 {
122 cp
123   avl_delete_tree(subnet_tree);
124 cp
125 }
126
127 avl_tree_t *new_subnet_tree(void)
128 {
129 cp
130   return avl_alloc_tree((avl_compare_t)subnet_compare, NULL);
131 cp
132 }
133
134 void free_subnet_tree(avl_tree_t *subnet_tree)
135 {
136 cp
137   avl_delete_tree(subnet_tree);
138 cp
139 }
140
141 /* Allocating and freeing space for subnets */
142
143 subnet_t *new_subnet(void)
144 {
145 cp
146   return (subnet_t *)xmalloc(sizeof(subnet_t));
147 }
148
149 void free_subnet(subnet_t *subnet)
150 {
151 cp
152   free(subnet);
153 }
154
155 /* Adding and removing subnets */
156
157 void cache_invalidate(void)
158 {
159   cache_mac_valid = 0;
160   cache_ipv4_valid = 0;
161   cache_ipv6_valid = 0;
162 }
163
164 void subnet_add(node_t *n, subnet_t *subnet)
165 {
166 cp
167   subnet->owner = n;
168
169   cache_invalidate();
170
171   avl_insert(subnet_tree, subnet);
172 cp
173   avl_insert(n->subnet_tree, subnet);
174 cp
175 }
176
177 void subnet_del(node_t *n, subnet_t *subnet)
178 {
179 cp
180   cache_invalidate();
181
182   avl_delete(n->subnet_tree, subnet);
183 cp
184   avl_delete(subnet_tree, subnet);
185 cp
186 }
187
188 /* Ascii representation of subnets */
189
190 subnet_t *str2net(char *subnetstr)
191 {
192   int i, l;
193   subnet_t *subnet;
194   unsigned short int x[8];
195 cp
196   subnet = new_subnet();
197 cp
198   if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
199               &x[0], &x[1], &x[2], &x[3],
200               &l) == 5)
201     {
202       subnet->type = SUBNET_IPV4;
203       subnet->net.ipv4.masklength = l;
204       for(i = 0; i < 4; i++)
205         subnet->net.ipv4.address.x[i] = x[i];
206       return subnet;
207     }
208               
209   if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
210              &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
211              &l) == 9)
212     {
213       subnet->type = SUBNET_IPV6;
214       subnet->net.ipv6.masklength = l;
215       for(i = 0; i < 8; i++)
216         subnet->net.ipv6.address.x[i] = htons(x[i]);
217       return subnet;
218     }
219
220   if(sscanf(subnetstr, "%hu.%hu.%hu.%hu",
221               &x[0], &x[1], &x[2], &x[3]) == 4)
222     {
223       subnet->type = SUBNET_IPV4;
224       subnet->net.ipv4.masklength = 32;
225       for(i = 0; i < 4; i++)
226         subnet->net.ipv4.address.x[i] = x[i];
227       return subnet;
228     }
229               
230   if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
231              &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7]) == 8)
232     {
233       subnet->type = SUBNET_IPV6;
234       subnet->net.ipv6.masklength = 128;
235       for(i = 0; i < 8; i++)
236         subnet->net.ipv6.address.x[i] = htons(x[i]);
237       return subnet;
238     }
239
240   if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
241               &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]) == 6)
242     {
243       subnet->type = SUBNET_MAC;
244       for(i = 0; i < 6; i++)
245         subnet->net.mac.address.x[i] = x[i];
246       return subnet;
247     }
248
249   free(subnet);
250   return NULL;
251 }
252
253 char *net2str(subnet_t *subnet)
254 {
255   char *netstr;
256 cp
257   switch(subnet->type)
258     {
259       case SUBNET_MAC:
260         asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx",
261                    subnet->net.mac.address.x[0],
262                    subnet->net.mac.address.x[1],
263                    subnet->net.mac.address.x[2],
264                    subnet->net.mac.address.x[3],
265                    subnet->net.mac.address.x[4],
266                    subnet->net.mac.address.x[5]);
267         break;
268       case SUBNET_IPV4:
269         asprintf(&netstr, "%hu.%hu.%hu.%hu/%d",
270                    subnet->net.ipv4.address.x[0],
271                    subnet->net.ipv4.address.x[1],
272                    subnet->net.ipv4.address.x[2],
273                    subnet->net.ipv4.address.x[3],
274                    subnet->net.ipv4.masklength);
275         break;
276       case SUBNET_IPV6:
277         asprintf(&netstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
278                    ntohs(subnet->net.ipv6.address.x[0]),
279                    ntohs(subnet->net.ipv6.address.x[1]),
280                    ntohs(subnet->net.ipv6.address.x[2]),
281                    ntohs(subnet->net.ipv6.address.x[3]),
282                    ntohs(subnet->net.ipv6.address.x[4]),
283                    ntohs(subnet->net.ipv6.address.x[5]),
284                    ntohs(subnet->net.ipv6.address.x[6]),
285                    ntohs(subnet->net.ipv6.address.x[7]),
286                    subnet->net.ipv6.masklength);
287         break;
288       default:
289         syslog(LOG_ERR, _("net2str() was called with unknown subnet type %d, exitting!"), subnet->type);
290         cp_trace();
291         exit(0);
292     }
293 cp
294   return netstr;
295 }
296
297 /* Subnet lookup routines */
298
299 subnet_t *lookup_subnet(node_t *owner, subnet_t *subnet)
300 {
301 cp  
302   return avl_search(owner->subnet_tree, subnet);
303 }
304
305 subnet_t *lookup_subnet_mac(mac_t *address)
306 {
307   static subnet_t subnet, *p;
308 cp
309   if(cache_mac_valid && !memcmp(&subnet.net.mac.address, address, sizeof(mac_t)))
310     return p;
311
312   subnet.type = SUBNET_MAC;
313   memcpy(&subnet.net.mac.address, address, sizeof(mac_t));
314
315   p = (subnet_t *)avl_search(subnet_tree, &subnet);
316   cache_mac_valid = 1;
317 cp
318   return p;
319 }
320
321 subnet_t *lookup_subnet_ipv4(ipv4_t *address)
322 {
323   static subnet_t subnet, *p;
324 cp
325   if(cache_ipv4_valid && !memcmp(&subnet.net.ipv4.address, address, sizeof(ipv4_t)))
326     return p;
327
328   subnet.type = SUBNET_IPV4;
329   memcpy(&subnet.net.ipv4.address, address, sizeof(ipv4_t));
330   subnet.net.ipv4.masklength = 32;
331
332   do
333   {
334     /* Go find subnet */
335   
336     p = (subnet_t *)avl_search_closest_smaller(subnet_tree, &subnet);
337
338   /* Check if the found subnet REALLY matches */
339 cp
340     if(p)
341       {
342         if(p->type != SUBNET_IPV4)
343           {
344             p = NULL;
345             break;
346           }
347
348         if (!maskcmp((char *)address, (char *)&p->net.ipv4.address, p->net.ipv4.masklength, sizeof(ipv4_t)))
349           break;
350         else
351           {
352             /* Otherwise, see if there is a bigger enclosing subnet */
353
354             subnet.net.ipv4.masklength = p->net.ipv4.masklength - 1;
355             maskcpy((char *)&subnet.net.ipv4.address, (char *)&p->net.ipv4.address, subnet.net.ipv4.masklength, sizeof(ipv4_t));
356           }
357       }
358   } while (p);
359    
360   memcpy(&subnet.net.ipv4.address, address, sizeof(ipv4_t));
361   cache_ipv4_valid = 1; 
362 cp
363   return p;
364 }
365
366 subnet_t *lookup_subnet_ipv6(ipv6_t *address)
367 {
368   static subnet_t subnet, *p;
369 cp
370   if(cache_ipv6_valid && !memcmp(&subnet.net.ipv6.address, address, sizeof(ipv6_t)))
371     return p;
372
373   subnet.type = SUBNET_IPV6;
374   memcpy(&subnet.net.ipv6.address, address, sizeof(ipv6_t));
375   subnet.net.ipv6.masklength = 128;
376   
377   do
378   {
379     /* Go find subnet */
380   
381     p = (subnet_t *)avl_search_closest_smaller(subnet_tree, &subnet);
382
383     /* Check if the found subnet REALLY matches */
384
385 cp
386     if(p)
387       {
388         if(p->type != SUBNET_IPV6)
389           return NULL;
390
391         if (!maskcmp((char *)address, (char *)&p->net.ipv6.address, p->net.ipv6.masklength, sizeof(ipv6_t)))
392           break;
393         else
394           {
395             /* Otherwise, see if there is a bigger enclosing subnet */
396
397             subnet.net.ipv6.masklength = p->net.ipv6.masklength - 1;
398             maskcpy((char *)&subnet.net.ipv6.address, (char *)&p->net.ipv6.address, subnet.net.ipv6.masklength, sizeof(ipv6_t));
399           }
400       }
401    } while (p);
402
403   memcpy(&subnet.net.ipv6.address, address, sizeof(ipv6_t));
404   cache_ipv6_valid = 1; 
405 cp   
406   return p;
407 }
408
409 void dump_subnets(void)
410 {
411   char *netstr;
412   subnet_t *subnet;
413   avl_node_t *node;
414 cp
415   syslog(LOG_DEBUG, _("Subnet list:"));
416   for(node = subnet_tree->head; node; node = node->next)
417     {
418       subnet = (subnet_t *)node->data;
419       netstr = net2str(subnet);
420       syslog(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name);
421       free(netstr);
422     }
423   syslog(LOG_DEBUG, _("End of subnet list."));
424 cp
425 }