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