fc02c67fbca30be25fdf766ba9b4fffb22f6be44
[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.30 2002/03/11 13:14:53 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 void route_neighborsol(vpn_packet_t *packet)
190 {
191   struct ip6_hdr *hdr;
192   struct nd_neighbor_solicit *ns;
193   struct nd_opt_hdr *opt;
194   subnet_t *subnet;
195 cp
196   hdr = (struct ip6_hdr *)(packet->data + 14);
197   ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(struct ip6_hdr));
198   opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(struct ip6_hdr) + sizeof(struct nd_neighbor_solicit));
199
200   /* First, snatch the source address from the neighbor solicitation packet */
201
202   memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
203
204   /* Check if this is a valid neighbor solicitation request */
205   
206   if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
207      opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
208     {
209       if(debug_lvl > DEBUG_TRAFFIC)
210         {
211           syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
212         } 
213       return;
214     }
215
216   /* Check if the IPv6 address exists on the VPN */
217
218   subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
219
220   if(!subnet)
221     {
222       if(debug_lvl >= DEBUG_TRAFFIC)
223         {
224           syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
225                  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]),
226                  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]));
227         }
228
229       return;
230     }
231
232   /* Check if it is for our own subnet */
233   
234   if(subnet->owner == myself)
235     return;     /* silently ignore */
236
237   /* Create neighbor advertation reply */
238
239   memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* copy destination address */
240   packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF;                           /* mangle source address so it looks like it's not from us */
241
242   memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16);                             /* swap destination and source protocol address */
243   memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16);                         /* ... */
244
245   memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
246
247   ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
248   opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
249   
250   write_packet(packet);
251 cp
252 }
253
254 void route_arp(vpn_packet_t *packet)
255 {
256   struct ether_arp *arp;
257   subnet_t *subnet;
258   unsigned char ipbuf[4];
259 cp
260   /* First, snatch the source address from the ARP packet */
261
262   memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
263
264   /* This routine generates replies to ARP requests.
265      You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
266      Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
267    */
268
269   arp = (struct ether_arp *)(packet->data + 14);
270
271   /* Check if this is a valid ARP request */
272
273   if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
274      ntohs(arp->arp_pro) != ETHERTYPE_IP ||
275      (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
276      (int) (arp->arp_pln) != 4 ||
277      ntohs(arp->arp_op) != ARPOP_REQUEST )
278     {
279       if(debug_lvl > DEBUG_TRAFFIC)
280         {
281           syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
282         } 
283       return;
284     }
285
286   /* Check if the IPv4 address exists on the VPN */
287
288   subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
289
290   if(!subnet)
291     {
292       if(debug_lvl >= DEBUG_TRAFFIC)
293         {
294           syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
295                  arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
296         }
297
298       return;
299     }
300
301   /* Check if it is for our own subnet */
302   
303   if(subnet->owner == myself)
304     return;     /* silently ignore */
305
306   memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* copy destination address */
307   packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF;                           /* mangle source address so it looks like it's not from us */
308
309   memcpy(ipbuf, arp->arp_tpa, 4);                                       /* save protocol addr */
310   memcpy(arp->arp_tpa, arp->arp_spa, 4);                                /* swap destination and source protocol address */
311   memcpy(arp->arp_spa, ipbuf, 4);                                       /* ... */
312
313   memcpy(arp->arp_tha, arp->arp_sha, 10);                               /* set target hard/proto addr */
314   memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* add fake source hard addr */
315   arp->arp_op = htons(ARPOP_REPLY);
316   
317   write_packet(packet);
318 cp
319 }
320
321 void route_outgoing(vpn_packet_t *packet)
322 {
323   unsigned short int type;
324   node_t *n = NULL;
325 cp
326   /* FIXME: multicast? */
327
328   switch(routing_mode)
329     {
330       case RMODE_ROUTER:
331         type = ntohs(*((unsigned short*)(&packet->data[12])));
332         switch(type)
333           {
334             case 0x0800:
335               n = route_ipv4(packet);
336               break;
337             case 0x86DD:
338               n = route_ipv6(packet);
339               if(!n && packet->data[6] == 0x33 && packet->data[7] == 0x33 && packet->data[8] == 0xff)
340                 {
341                   route_neighborsol(packet);
342                   return;
343                 }
344               break;
345             case 0x0806:
346               route_arp(packet);
347               return;
348             default:
349               if(debug_lvl >= DEBUG_TRAFFIC)
350                 {
351                   syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
352                 }
353               return;
354            }
355          if(n)
356            send_packet(n, packet);
357          break;
358         
359       case RMODE_SWITCH:
360         n = route_mac(packet);
361         if(n)
362           send_packet(n, packet);
363         else
364           broadcast_packet(myself, packet);
365         break;
366         
367       case RMODE_HUB:
368         broadcast_packet(myself, packet);
369         break;
370     }
371 }
372
373 void route_incoming(node_t *source, vpn_packet_t *packet)
374 {
375   switch(routing_mode)
376     {
377       case RMODE_ROUTER:
378         {
379           node_t *n = NULL;
380           unsigned short int type;
381
382           type = ntohs(*((unsigned short*)(&packet->data[12])));
383           switch(type)
384             {
385               case 0x0800:
386                 n = route_ipv4(packet);
387                 break;
388               case 0x86DD:
389                 n = route_ipv6(packet);
390                 break;
391               default:
392                 n = myself;
393                 break;
394              }
395
396           if(n)
397             {
398               if(n == myself)
399                 {
400                   memcpy(packet->data, mymac.net.mac.address.x, 6);
401                   write_packet(packet);
402                 }
403               else
404                 send_packet(n, packet);
405             }
406           }
407         break;
408       case RMODE_SWITCH:
409         {
410           subnet_t *subnet;
411
412           subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
413
414           if(subnet)
415             {
416               if(subnet->owner == myself)
417                 write_packet(packet);
418               else
419                 send_packet(subnet->owner, packet);
420             }
421           else
422             {
423               broadcast_packet(source, packet);
424               write_packet(packet);
425             }
426           }
427         break;
428       case RMODE_HUB:
429         broadcast_packet(source, packet);                       /* Spread it on */
430         write_packet(packet);
431         break;
432     }
433 }