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