Run graph() after edge_del() when updating an edge.
[tinc] / src / route.c
1 /*
2     route.c -- routing
3     Copyright (C) 2000-2002 Ivo Timmermans <ivo@o2w.nl>,
4                   2000-2002 Guus Sliepen <guus@sliepen.eu.org>
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: route.c,v 1.1.2.46 2002/09/09 22:33:16 guus Exp $
21 */
22
23 #include "config.h"
24
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
27 #endif
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #ifdef HAVE_NET_IF_H
31 #include <net/if.h>
32 #endif
33 #ifdef HAVE_NET_ETHERNET_H
34 #include <net/ethernet.h>
35 #endif
36 #ifdef HAVE_NETINET_IN_SYSTM_H
37 #include <netinet/in_systm.h>
38 #endif
39 #include <netinet/ip6.h>
40 #include <netinet/icmp6.h>
41 #include <netinet/if_ether.h>
42 #include <utils.h>
43 #include <xalloc.h>
44 #include <syslog.h>
45 #include <string.h>
46 #ifdef HAVE_INTTYPES_H
47 #include <inttypes.h>
48 #endif
49
50 #include <avl_tree.h>
51
52 #include "net.h"
53 #include "connection.h"
54 #include "subnet.h"
55 #include "route.h"
56 #include "protocol.h"
57 #include "device.h"
58
59 #include "system.h"
60
61 #ifndef ETHER_ADDR_LEN
62 #define ETHER_ADDR_LEN 6
63 #endif
64
65 int routing_mode = RMODE_ROUTER;
66 int priorityinheritance = 0;
67 int macexpire = 600;
68 subnet_t mymac;
69
70 void learn_mac(mac_t *address)
71 {
72         subnet_t *subnet;
73         avl_node_t *node;
74         connection_t *c;
75
76         cp();
77
78         subnet = lookup_subnet_mac(address);
79
80         /* If we don't know this MAC address yet, store it */
81
82         if(!subnet || subnet->owner != myself) {
83                 if(debug_lvl >= DEBUG_TRAFFIC)
84                         syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
85                                    address->x[0], address->x[1], address->x[2], address->x[3],
86                                    address->x[4], address->x[5]);
87
88                 subnet = new_subnet();
89                 subnet->type = SUBNET_MAC;
90                 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
91                 subnet_add(myself, subnet);
92
93                 /* And tell all other tinc daemons it's our MAC */
94
95                 for(node = connection_tree->head; node; node = node->next) {
96                         c = (connection_t *) node->data;
97                         if(c->status.active)
98                                 send_add_subnet(c, subnet);
99                 }
100         }
101
102         subnet->net.mac.lastseen = now;
103 }
104
105 void age_mac(void)
106 {
107         subnet_t *s;
108         connection_t *c;
109         avl_node_t *node, *next, *node2;
110
111         cp();
112
113         for(node = myself->subnet_tree->head; node; node = next) {
114                 next = node->next;
115                 s = (subnet_t *) node->data;
116                 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
117                         if(debug_lvl >= DEBUG_TRAFFIC)
118                                 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
119                                            s->net.mac.address.x[0], s->net.mac.address.x[1],
120                                            s->net.mac.address.x[2], s->net.mac.address.x[3],
121                                            s->net.mac.address.x[4], s->net.mac.address.x[5]);
122
123                         for(node2 = connection_tree->head; node2; node2 = node2->next) {
124                                 c = (connection_t *) node2->data;
125                                 if(c->status.active)
126                                         send_del_subnet(c, s);
127                         }
128
129                         subnet_del(myself, s);
130                 }
131         }
132 }
133
134 node_t *route_mac(vpn_packet_t *packet)
135 {
136         subnet_t *subnet;
137
138         cp();
139
140         /* Learn source address */
141
142         learn_mac((mac_t *)(&packet->data[6]));
143
144         /* Lookup destination address */
145
146         subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
147
148         if(subnet)
149                 return subnet->owner;
150         else
151                 return NULL;
152 }
153
154 node_t *route_ipv4(vpn_packet_t *packet)
155 {
156         subnet_t *subnet;
157
158         cp();
159
160         if(priorityinheritance)
161                 packet->priority = packet->data[15];
162
163         subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
164
165         if(!subnet) {
166                 if(debug_lvl >= DEBUG_TRAFFIC) {
167                         syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
168                                    packet->data[30], packet->data[31], packet->data[32],
169                                    packet->data[33]);
170                 }
171
172                 return NULL;
173         }
174
175         return subnet->owner;
176 }
177
178 node_t *route_ipv6(vpn_packet_t *packet)
179 {
180         subnet_t *subnet;
181
182         cp();
183
184         subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
185
186         if(!subnet) {
187                 if(debug_lvl >= DEBUG_TRAFFIC) {
188                         syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
189                                    ntohs(*(uint16_t *) & packet->data[38]),
190                                    ntohs(*(uint16_t *) & packet->data[40]),
191                                    ntohs(*(uint16_t *) & packet->data[42]),
192                                    ntohs(*(uint16_t *) & packet->data[44]),
193                                    ntohs(*(uint16_t *) & packet->data[46]),
194                                    ntohs(*(uint16_t *) & packet->data[48]),
195                                    ntohs(*(uint16_t *) & packet->data[50]),
196                                    ntohs(*(uint16_t *) & packet->data[52]));
197                 }
198
199                 return NULL;
200         }
201
202         return subnet->owner;
203 }
204
205 uint16_t inet_checksum(uint16_t *data, int len, uint16_t prevsum)
206 {
207         uint32_t checksum = prevsum ^ 0xFFFF;
208
209         while(len--)
210                 checksum += ntohs(*data++);
211
212         while(checksum >> 16)
213                 checksum = (checksum & 0xFFFF) + (checksum >> 16);
214
215         return checksum ^ 0xFFFF;
216 }
217
218 void route_neighborsol(vpn_packet_t *packet)
219 {
220         struct ip6_hdr *hdr;
221         struct nd_neighbor_solicit *ns;
222         struct nd_opt_hdr *opt;
223         subnet_t *subnet;
224         uint16_t checksum;
225
226         struct {
227                 struct in6_addr ip6_src;        /* source address */
228                 struct in6_addr ip6_dst;        /* destination address */
229                 uint32_t length;
230                 uint8_t junk[4];
231         } pseudo;
232
233         cp();
234
235         hdr = (struct ip6_hdr *)(packet->data + 14);
236         ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
237         opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
238
239         /* First, snatch the source address from the neighbor solicitation packet */
240
241         memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
242
243         /* Check if this is a valid neighbor solicitation request */
244
245         if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
246            opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
247                 if(debug_lvl > DEBUG_TRAFFIC) {
248                         syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
249                 }
250                 return;
251         }
252
253         /* Create pseudo header */
254
255         memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
256         memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
257         pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
258         pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
259         pseudo.junk[3] = IPPROTO_ICMPV6;
260
261         /* Generate checksum */
262
263         checksum = inet_checksum((uint16_t *) & pseudo, sizeof(pseudo) / 2, ~0);
264         checksum = inet_checksum((uint16_t *) ns, sizeof(*ns) / 2 + 4, checksum);
265
266         if(checksum) {
267                 if(debug_lvl >= DEBUG_TRAFFIC)
268                         syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
269                 return;
270         }
271
272         /* Check if the IPv6 address exists on the VPN */
273
274         subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
275
276         if(!subnet) {
277                 if(debug_lvl >= DEBUG_TRAFFIC) {
278                         syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
279                                    ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
280                                    ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
281                                    ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
282                                    ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
283                                    ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
284                                    ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
285                                    ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
286                                    ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
287                 }
288
289                 return;
290         }
291
292         /* Check if it is for our own subnet */
293
294         if(subnet->owner == myself)
295                 return;                                 /* silently ignore */
296
297         /* Create neighbor advertation reply */
298
299         memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);    /* copy destination address */
300         packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF;   /* mangle source address so it looks like it's not from us */
301
302         memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16);       /* swap destination and source protocol address */
303         memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16);   /* ... */
304
305         memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6);  /* add fake source hard addr */
306
307         ns->nd_ns_hdr.icmp6_cksum = 0;
308         ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
309         ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40;    /* Set solicited flag */
310         ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
311                 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
312                 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
313         opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
314
315         /* Create pseudo header */
316
317         memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
318         memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
319         pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
320         pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
321         pseudo.junk[3] = IPPROTO_ICMPV6;
322
323         /* Generate checksum */
324
325         checksum = inet_checksum((uint16_t *) & pseudo, sizeof(pseudo) / 2, ~0);
326         checksum = inet_checksum((uint16_t *) ns, sizeof(*ns) / 2 + 4, checksum);
327
328         ns->nd_ns_hdr.icmp6_cksum = htons(checksum);
329
330         write_packet(packet);
331 }
332
333 void route_arp(vpn_packet_t *packet)
334 {
335         struct ether_arp *arp;
336         subnet_t *subnet;
337         uint8_t ipbuf[4];
338
339         cp();
340
341         /* First, snatch the source address from the ARP packet */
342
343         memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
344
345         /* This routine generates replies to ARP requests.
346            You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
347            Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
348          */
349
350         arp = (struct ether_arp *)(packet->data + 14);
351
352         /* Check if this is a valid ARP request */
353
354         if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
355            arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
356                 if(debug_lvl > DEBUG_TRAFFIC) {
357                         syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
358                 }
359                 return;
360         }
361
362         /* Check if the IPv4 address exists on the VPN */
363
364         subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
365
366         if(!subnet) {
367                 if(debug_lvl >= DEBUG_TRAFFIC) {
368                         syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
369                                    arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
370                                    arp->arp_tpa[3]);
371                 }
372
373                 return;
374         }
375
376         /* Check if it is for our own subnet */
377
378         if(subnet->owner == myself)
379                 return;                                 /* silently ignore */
380
381         memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);    /* copy destination address */
382         packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF;   /* mangle source address so it looks like it's not from us */
383
384         memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
385         memcpy(arp->arp_tpa, arp->arp_spa, 4);  /* swap destination and source protocol address */
386         memcpy(arp->arp_spa, ipbuf, 4); /* ... */
387
388         memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
389         memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);    /* add fake source hard addr */
390         arp->arp_op = htons(ARPOP_REPLY);
391
392         write_packet(packet);
393 }
394
395 void route_outgoing(vpn_packet_t *packet)
396 {
397         uint16_t type;
398         node_t *n = NULL;
399
400         cp();
401
402         /* FIXME: multicast? */
403
404         switch (routing_mode) {
405                 case RMODE_ROUTER:
406                         type = ntohs(*((uint16_t *)(&packet->data[12])));
407                         switch (type) {
408                                 case 0x0800:
409                                         n = route_ipv4(packet);
410                                         break;
411
412                                 case 0x86DD:
413                                         if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
414                                                 route_neighborsol(packet);
415                                                 return;
416                                         }
417                                         n = route_ipv6(packet);
418                                         break;
419
420                                 case 0x0806:
421                                         route_arp(packet);
422                                         return;
423
424                                 default:
425                                         if(debug_lvl >= DEBUG_TRAFFIC)
426                                                 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
427                                         return;
428                         }
429                         if(n)
430                                 send_packet(n, packet);
431                         break;
432
433                 case RMODE_SWITCH:
434                         n = route_mac(packet);
435                         if(n)
436                                 send_packet(n, packet);
437                         else
438                                 broadcast_packet(myself, packet);
439                         break;
440
441                 case RMODE_HUB:
442                         broadcast_packet(myself, packet);
443                         break;
444         }
445 }
446
447 void route_incoming(node_t *source, vpn_packet_t *packet)
448 {
449         switch (routing_mode) {
450                 case RMODE_ROUTER:
451                         {
452                                 node_t *n = NULL;
453                                 uint16_t type;
454
455                                 type = ntohs(*((uint16_t *)(&packet->data[12])));
456                                 switch (type) {
457                                         case 0x0800:
458                                                 n = route_ipv4(packet);
459                                                 break;
460
461                                         case 0x86DD:
462                                                 n = route_ipv6(packet);
463                                                 break;
464
465                                         default:
466                                                 n = myself;
467                                                 break;
468                                 }
469
470                                 if(n) {
471                                         if(n == myself) {
472                                                 memcpy(packet->data, mymac.net.mac.address.x, 6);
473                                                 write_packet(packet);
474                                         } else
475                                                 send_packet(n, packet);
476                                 }
477                         }
478                         break;
479
480                 case RMODE_SWITCH:
481                         {
482                                 subnet_t *subnet;
483
484                                 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
485
486                                 if(subnet) {
487                                         if(subnet->owner == myself)
488                                                 write_packet(packet);
489                                         else
490                                                 send_packet(subnet->owner, packet);
491                                 } else {
492                                         broadcast_packet(source, packet);
493                                         write_packet(packet);
494                                 }
495                         }
496                         break;
497
498                 case RMODE_HUB:
499                         broadcast_packet(source, packet);       /* Spread it on */
500                         write_packet(packet);
501                         break;
502         }
503 }