Use Ed25519 keys.
[oweals/tinc.git] / src / subnet_parse.c
1 /*
2     subnet_parse.c -- handle subnet parsing
3     Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
4                   2000-2005 Ivo Timmermans
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 along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "system.h"
22
23 #include "logger.h"
24 #include "net.h"
25 #include "netutl.h"
26 #include "subnet.h"
27 #include "utils.h"
28 #include "xalloc.h"
29
30 /* Subnet mask handling */
31
32 int maskcmp(const void *va, const void *vb, int masklen) {
33         int i, m, result;
34         const char *a = va;
35         const char *b = vb;
36
37         for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
38                 result = a[i] - b[i];
39                 if(result)
40                         return result;
41         }
42
43         if(m)
44                 return (a[i] & (0x100 - (1 << (8 - m)))) -
45                         (b[i] & (0x100 - (1 << (8 - m))));
46
47         return 0;
48 }
49
50 void mask(void *va, int masklen, int len) {
51         int i;
52         char *a = va;
53
54         i = masklen / 8;
55         masklen %= 8;
56
57         if(masklen)
58                 a[i++] &= (0x100 - (1 << (8 - masklen)));
59
60         for(; i < len; i++)
61                 a[i] = 0;
62 }
63
64 void maskcpy(void *va, const void *vb, int masklen, int len) {
65         int i, m;
66         char *a = va;
67         const char *b = vb;
68
69         for(m = masklen, i = 0; m >= 8; m -= 8, i++)
70                 a[i] = b[i];
71
72         if(m) {
73                 a[i] = b[i] & (0x100 - (1 << (8 - m)));
74                 i++;
75         }
76
77         for(; i < len; i++)
78                 a[i] = 0;
79 }
80
81 bool maskcheck(const void *va, int masklen, int len) {
82         int i;
83         const char *a = va;
84
85         i = masklen / 8;
86         masklen %= 8;
87
88         if(masklen && a[i++] & (0xff >> masklen))
89                 return false;
90
91         for(; i < len; i++)
92                 if(a[i] != 0)
93                         return false;
94
95         return true;
96 }
97
98 /* Subnet comparison */
99
100 static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
101         int result;
102
103         result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address);
104
105         if(result)
106                 return result;
107
108         result = a->weight - b->weight;
109
110         if(result || !a->owner || !b->owner)
111                 return result;
112
113         return strcmp(a->owner->name, b->owner->name);
114 }
115
116 static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
117         int result;
118
119         result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength;
120
121         if(result)
122                 return result;
123
124         result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
125
126         if(result)
127                 return result;
128
129         result = a->weight - b->weight;
130
131         if(result || !a->owner || !b->owner)
132                 return result;
133
134         return strcmp(a->owner->name, b->owner->name);
135 }
136
137 static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
138         int result;
139
140         result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength;
141
142         if(result)
143                 return result;
144
145         result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
146
147         if(result)
148                 return result;
149
150         result = a->weight - b->weight;
151
152         if(result || !a->owner || !b->owner)
153                 return result;
154
155         return strcmp(a->owner->name, b->owner->name);
156 }
157
158 int subnet_compare(const subnet_t *a, const subnet_t *b) {
159         int result;
160
161         result = a->type - b->type;
162
163         if(result)
164                 return result;
165
166         switch (a->type) {
167         case SUBNET_MAC:
168                 return subnet_compare_mac(a, b);
169         case SUBNET_IPV4:
170                 return subnet_compare_ipv4(a, b);
171         case SUBNET_IPV6:
172                 return subnet_compare_ipv6(a, b);
173         default:
174                 logger(DEBUG_ALWAYS, LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!", a->type);
175                 exit(1);
176         }
177
178         return 0;
179 }
180
181 /* Ascii representation of subnets */
182
183 bool str2net(subnet_t *subnet, const char *subnetstr) {
184         int i, l;
185         uint16_t x[8];
186         int weight = 10;
187
188         if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d",
189                           &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) {
190                 if(l < 0 || l > 32)
191                         return false;
192
193                 subnet->type = SUBNET_IPV4;
194                 subnet->net.ipv4.prefixlength = l;
195                 subnet->weight = weight;
196
197                 for(int i = 0; i < 4; i++) {
198                         if(x[i] > 255)
199                                 return false;
200                         subnet->net.ipv4.address.x[i] = x[i];
201                 }
202
203                 return true;
204         }
205
206         if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
207                           &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
208                           &l, &weight) >= 9) {
209                 if(l < 0 || l > 128)
210                         return false;
211
212                 subnet->type = SUBNET_IPV6;
213                 subnet->net.ipv6.prefixlength = l;
214                 subnet->weight = weight;
215
216                 for(i = 0; i < 8; i++)
217                         subnet->net.ipv6.address.x[i] = htons(x[i]);
218
219                 return true;
220         }
221
222         if(sscanf(subnetstr, "%hu.%hu.%hu.%hu#%d", &x[0], &x[1], &x[2], &x[3], &weight) >= 4) {
223                 subnet->type = SUBNET_IPV4;
224                 subnet->net.ipv4.prefixlength = 32;
225                 subnet->weight = weight;
226
227                 for(i = 0; i < 4; i++) {
228                         if(x[i] > 255)
229                                 return false;
230                         subnet->net.ipv4.address.x[i] = x[i];
231                 }
232
233                 return true;
234         }
235
236         if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d",
237                           &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) {
238                 subnet->type = SUBNET_IPV6;
239                 subnet->net.ipv6.prefixlength = 128;
240                 subnet->weight = weight;
241
242                 for(i = 0; i < 8; i++)
243                         subnet->net.ipv6.address.x[i] = htons(x[i]);
244
245                 return true;
246         }
247
248         if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
249                           &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) {
250                 subnet->type = SUBNET_MAC;
251                 subnet->weight = weight;
252
253                 for(i = 0; i < 6; i++)
254                         subnet->net.mac.address.x[i] = x[i];
255
256                 return true;
257         }
258
259         // IPv6 short form
260         if(strstr(subnetstr, "::")) {
261                 const char *p;
262                 char *q;
263                 int colons = 0;
264
265                 // Count number of colons
266                 for(p = subnetstr; *p; p++)
267                         if(*p == ':')
268                                 colons++;
269
270                 if(colons > 7)
271                         return false;
272
273                 // Scan numbers before the double colon
274                 p = subnetstr;
275                 for(i = 0; i < colons; i++) {
276                         if(*p == ':')
277                                 break;
278                         x[i] = strtoul(p, &q, 0x10);
279                         if(!q || p == q || *q != ':')
280                                 return false;
281                         p = ++q;
282                 }
283
284                 p++;
285                 colons -= i;
286                 if(!i) {
287                         p++;
288                         colons--;
289                 }
290
291                 if(!*p || *p == '/' || *p == '#')
292                         colons--;
293
294                 // Fill in the blanks
295                 for(; i < 8 - colons; i++)
296                         x[i] = 0;
297
298                 // Scan the remaining numbers
299                 for(; i < 8; i++) {
300                         x[i] = strtoul(p, &q, 0x10);
301                         if(!q || p == q)
302                                 return false;
303                         if(i == 7) {
304                                 p = q;
305                                 break;
306                         }
307                         if(*q != ':')
308                                 return false;
309                         p = ++q;
310                 }
311
312                 l = 128;
313                 if(*p == '/')
314                         sscanf(p, "/%d#%d", &l, &weight);
315                 else if(*p == '#')
316                         sscanf(p, "#%d", &weight);
317
318                 if(l < 0 || l > 128)
319                         return false;
320
321                 subnet->type = SUBNET_IPV6;
322                 subnet->net.ipv6.prefixlength = l;
323                 subnet->weight = weight;
324
325                 for(i = 0; i < 8; i++)
326                         subnet->net.ipv6.address.x[i] = htons(x[i]);
327
328                 return true;
329         }
330
331         return false;
332 }
333
334 bool net2str(char *netstr, int len, const subnet_t *subnet) {
335         if(!netstr || !subnet) {
336                 logger(DEBUG_ALWAYS, LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!", netstr, subnet);
337                 return false;
338         }
339
340         switch (subnet->type) {
341                 case SUBNET_MAC:
342                         snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
343                                          subnet->net.mac.address.x[0],
344                                          subnet->net.mac.address.x[1],
345                                          subnet->net.mac.address.x[2],
346                                          subnet->net.mac.address.x[3],
347                                          subnet->net.mac.address.x[4],
348                                          subnet->net.mac.address.x[5],
349                                          subnet->weight);
350                         break;
351
352                 case SUBNET_IPV4:
353                         snprintf(netstr, len, "%hu.%hu.%hu.%hu/%d#%d",
354                                          subnet->net.ipv4.address.x[0],
355                                          subnet->net.ipv4.address.x[1],
356                                          subnet->net.ipv4.address.x[2],
357                                          subnet->net.ipv4.address.x[3],
358                                          subnet->net.ipv4.prefixlength,
359                                          subnet->weight);
360                         break;
361
362                 case SUBNET_IPV6:
363                         snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
364                                          ntohs(subnet->net.ipv6.address.x[0]),
365                                          ntohs(subnet->net.ipv6.address.x[1]),
366                                          ntohs(subnet->net.ipv6.address.x[2]),
367                                          ntohs(subnet->net.ipv6.address.x[3]),
368                                          ntohs(subnet->net.ipv6.address.x[4]),
369                                          ntohs(subnet->net.ipv6.address.x[5]),
370                                          ntohs(subnet->net.ipv6.address.x[6]),
371                                          ntohs(subnet->net.ipv6.address.x[7]),
372                                          subnet->net.ipv6.prefixlength,
373                                          subnet->weight);
374                         break;
375
376                 default:
377                         logger(DEBUG_ALWAYS, LOG_ERR, "net2str() was called with unknown subnet type %d, exiting!", subnet->type);
378                         exit(1);
379         }
380
381         return true;
382 }