- Global time_t now, so that we don't have to call time() too often.
[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.26 2002/03/01 14:09:31 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/if_ether.h>
37 #include <utils.h>
38 #include <xalloc.h>
39 #include <syslog.h>
40 #include <string.h>
41
42 #include <avl_tree.h>
43
44 #include "net.h"
45 #include "connection.h"
46 #include "subnet.h"
47 #include "route.h"
48 #include "protocol.h"
49 #include "device.h"
50
51 #include "system.h"
52
53 int routing_mode = RMODE_ROUTER;
54 int priorityinheritance = 0;
55 int macexpire = 600;
56 subnet_t mymac;
57
58 void learn_mac(mac_t *address)
59 {
60   subnet_t *subnet;
61   avl_node_t *node;
62   connection_t *c;
63 cp
64   subnet = lookup_subnet_mac(address);
65
66   /* If we don't know this MAC address yet, store it */
67   
68   if(!subnet || subnet->owner!=myself)
69     {
70       if(debug_lvl >= DEBUG_TRAFFIC)
71         syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
72                address->x[0], address->x[1], address->x[2], address->x[3],  address->x[4], address->x[5]);
73                
74       subnet = new_subnet();
75       subnet->type = SUBNET_MAC;
76       memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
77       subnet_add(myself, subnet);
78
79       /* And tell all other tinc daemons it's our MAC */
80       
81       for(node = connection_tree->head; node; node = node->next)
82         {
83           c = (connection_t *)node->data;
84           if(c->status.active)
85             send_add_subnet(c, subnet);
86         }
87     }
88
89   subnet->net.mac.lastseen = now;
90 }
91
92 void age_mac(void)
93 {
94   subnet_t *s;
95   connection_t *c;
96   avl_node_t *node, *next, *node2;
97 cp
98   for(node = myself->subnet_tree->head; node; node = next)
99     {
100       s = (subnet_t *)node->data;
101       if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
102         {
103           for(node2 = connection_tree->head; node2; node2 = node2->next)
104             {
105               c = (connection_t *)node2->data;
106               if(c->status.active)
107                 send_del_subnet(c, s);
108             }
109           subnet_del(myself, s);
110         }
111     }
112 cp
113 }
114
115 node_t *route_mac(vpn_packet_t *packet)
116 {
117   subnet_t *subnet;
118 cp
119   /* Learn source address */
120
121   learn_mac((mac_t *)(&packet->data[6]));
122   
123   /* Lookup destination address */
124     
125   subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
126
127   if(subnet)
128     return subnet->owner;
129   else
130     return NULL;
131 }
132
133 node_t *route_ipv4(vpn_packet_t *packet)
134 {
135   subnet_t *subnet;
136 cp
137   if(priorityinheritance)
138     packet->priority = packet->data[15];
139
140   subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
141 cp
142   if(!subnet)
143     {
144       if(debug_lvl >= DEBUG_TRAFFIC)
145         {
146           syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
147                  packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
148         }
149
150       return NULL;
151     }
152 cp
153   return subnet->owner;  
154 }
155
156 node_t *route_ipv6(vpn_packet_t *packet)
157 {
158   subnet_t *subnet;
159 cp
160   subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
161 cp
162   if(!subnet)
163     {
164       if(debug_lvl >= DEBUG_TRAFFIC)
165         {
166           syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
167             ntohs(*(short unsigned int *)&packet->data[38]),
168             ntohs(*(short unsigned int *)&packet->data[40]),
169             ntohs(*(short unsigned int *)&packet->data[42]),
170             ntohs(*(short unsigned int *)&packet->data[44]),
171             ntohs(*(short unsigned int *)&packet->data[46]),
172             ntohs(*(short unsigned int *)&packet->data[48]),
173             ntohs(*(short unsigned int *)&packet->data[50]),
174             ntohs(*(short unsigned int *)&packet->data[52]));
175         }
176
177       return NULL;
178     }
179 cp
180   return subnet->owner;  
181 }
182
183 void route_arp(vpn_packet_t *packet)
184 {
185   struct ether_arp *arp;
186   subnet_t *subnet;
187   unsigned char ipbuf[4];
188 cp
189   /* First, snatch the source address from the ARP packet */
190
191   memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
192
193   /* This routine generates replies to ARP requests.
194      You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
195      Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
196    */
197
198   arp = (struct ether_arp *)(packet->data + 14);
199
200   /* Check if this is a valid ARP request */
201
202   if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
203      ntohs(arp->arp_pro) != ETHERTYPE_IP ||
204      (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
205      (int) (arp->arp_pln) != 4 ||
206      ntohs(arp->arp_op) != ARPOP_REQUEST )
207     {
208       if(debug_lvl > DEBUG_TRAFFIC)
209         {
210           syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
211         } 
212       return;
213     }
214
215   /* Check if the IP address exists on the VPN */
216
217   subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
218
219   if(!subnet)
220     {
221       if(debug_lvl >= DEBUG_TRAFFIC)
222         {
223           syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
224                  arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
225         }
226
227       return;
228     }
229
230   /* Check if it is for our own subnet */
231   
232   if(subnet->owner == myself)
233     return;     /* silently ignore */
234
235   memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* copy destination address */
236   packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF;                           /* mangle source address so it looks like it's not from us */
237
238   memcpy(ipbuf, arp->arp_tpa, 4);                                       /* save protocol addr */
239   memcpy(arp->arp_tpa, arp->arp_spa, 4);                                /* swap destination and source protocol address */
240   memcpy(arp->arp_spa, ipbuf, 4);                                       /* ... */
241
242   memcpy(arp->arp_tha, arp->arp_sha, 10);                               /* set target hard/proto addr */
243   memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* add fake source hard addr */
244   arp->arp_op = htons(ARPOP_REPLY);
245   
246   write_packet(packet);
247 cp
248 }
249
250 void route_outgoing(vpn_packet_t *packet)
251 {
252   unsigned short int type;
253   node_t *n;
254 cp
255   /* FIXME: multicast? */
256
257   switch(routing_mode)
258     {
259       case RMODE_ROUTER:
260         type = ntohs(*((unsigned short*)(&packet->data[12])));
261         switch(type)
262           {
263             case 0x0800:
264               n = route_ipv4(packet);
265               break;
266             case 0x86DD:
267               n = route_ipv6(packet);
268               break;
269             case 0x0806:
270               route_arp(packet);
271               return;
272             default:
273               if(debug_lvl >= DEBUG_TRAFFIC)
274                 {
275                   syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
276                 }
277               return;
278            }
279          if(n)
280            send_packet(n, packet);
281          break;
282         
283       case RMODE_SWITCH:
284         n = route_mac(packet);
285         if(n)
286           send_packet(n, packet);
287         else
288           broadcast_packet(myself, packet);
289         break;
290         
291       case RMODE_HUB:
292         broadcast_packet(myself, packet);
293         break;
294     }
295 }
296
297 void route_incoming(node_t *source, vpn_packet_t *packet)
298 {
299   switch(routing_mode)
300     {
301       case RMODE_ROUTER:
302         {
303           node_t *n;
304
305           n = route_ipv4(packet);
306
307           if(n)
308             {
309               if(n == myself)
310                 {
311                   memcpy(packet->data, mymac.net.mac.address.x, 6);
312                   write_packet(packet);
313                 }
314               else
315                 send_packet(n, packet);
316             }
317           }
318         break;
319       case RMODE_SWITCH:
320         {
321           subnet_t *subnet;
322
323           subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
324
325           if(subnet)
326             {
327               if(subnet->owner == myself)
328                 write_packet(packet);
329               else
330                 send_packet(subnet->owner, packet);
331             }
332           else
333             {
334               broadcast_packet(source, packet);
335               write_packet(packet);
336             }
337           }
338         break;
339       case RMODE_HUB:
340         broadcast_packet(source, packet);                       /* Spread it on */
341         write_packet(packet);
342         break;
343     }
344 }