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