prune_connections() before build_fdset().
[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.29 2002/03/10 14:04:48 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       next = node->next;
101       s = (subnet_t *)node->data;
102       if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
103         {
104           if(debug_lvl >= DEBUG_TRAFFIC)
105             syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
106                    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]);
107           for(node2 = connection_tree->head; node2; node2 = node2->next)
108             {
109               c = (connection_t *)node2->data;
110               if(c->status.active)
111                 send_del_subnet(c, s);
112             }
113           subnet_del(myself, s);
114         }
115     }
116 cp
117 }
118
119 node_t *route_mac(vpn_packet_t *packet)
120 {
121   subnet_t *subnet;
122 cp
123   /* Learn source address */
124
125   learn_mac((mac_t *)(&packet->data[6]));
126   
127   /* Lookup destination address */
128     
129   subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
130
131   if(subnet)
132     return subnet->owner;
133   else
134     return NULL;
135 }
136
137 node_t *route_ipv4(vpn_packet_t *packet)
138 {
139   subnet_t *subnet;
140 cp
141   if(priorityinheritance)
142     packet->priority = packet->data[15];
143
144   subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
145 cp
146   if(!subnet)
147     {
148       if(debug_lvl >= DEBUG_TRAFFIC)
149         {
150           syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
151                  packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
152         }
153
154       return NULL;
155     }
156 cp
157   return subnet->owner;  
158 }
159
160 node_t *route_ipv6(vpn_packet_t *packet)
161 {
162   subnet_t *subnet;
163 cp
164   subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
165 cp
166   if(!subnet)
167     {
168       if(debug_lvl >= DEBUG_TRAFFIC)
169         {
170           syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
171             ntohs(*(short unsigned int *)&packet->data[38]),
172             ntohs(*(short unsigned int *)&packet->data[40]),
173             ntohs(*(short unsigned int *)&packet->data[42]),
174             ntohs(*(short unsigned int *)&packet->data[44]),
175             ntohs(*(short unsigned int *)&packet->data[46]),
176             ntohs(*(short unsigned int *)&packet->data[48]),
177             ntohs(*(short unsigned int *)&packet->data[50]),
178             ntohs(*(short unsigned int *)&packet->data[52]));
179         }
180
181       return NULL;
182     }
183 cp
184   return subnet->owner;  
185 }
186
187 void route_arp(vpn_packet_t *packet)
188 {
189   struct ether_arp *arp;
190   subnet_t *subnet;
191   unsigned char ipbuf[4];
192 cp
193   /* First, snatch the source address from the ARP packet */
194
195   memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
196
197   /* This routine generates replies to ARP requests.
198      You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
199      Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
200    */
201
202   arp = (struct ether_arp *)(packet->data + 14);
203
204   /* Check if this is a valid ARP request */
205
206   if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
207      ntohs(arp->arp_pro) != ETHERTYPE_IP ||
208      (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
209      (int) (arp->arp_pln) != 4 ||
210      ntohs(arp->arp_op) != ARPOP_REQUEST )
211     {
212       if(debug_lvl > DEBUG_TRAFFIC)
213         {
214           syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
215         } 
216       return;
217     }
218
219   /* Check if the IP address exists on the VPN */
220
221   subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
222
223   if(!subnet)
224     {
225       if(debug_lvl >= DEBUG_TRAFFIC)
226         {
227           syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
228                  arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
229         }
230
231       return;
232     }
233
234   /* Check if it is for our own subnet */
235   
236   if(subnet->owner == myself)
237     return;     /* silently ignore */
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(ipbuf, arp->arp_tpa, 4);                                       /* save protocol addr */
243   memcpy(arp->arp_tpa, arp->arp_spa, 4);                                /* swap destination and source protocol address */
244   memcpy(arp->arp_spa, ipbuf, 4);                                       /* ... */
245
246   memcpy(arp->arp_tha, arp->arp_sha, 10);                               /* set target hard/proto addr */
247   memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* add fake source hard addr */
248   arp->arp_op = htons(ARPOP_REPLY);
249   
250   write_packet(packet);
251 cp
252 }
253
254 void route_outgoing(vpn_packet_t *packet)
255 {
256   unsigned short int type;
257   node_t *n = NULL;
258 cp
259   /* FIXME: multicast? */
260
261   switch(routing_mode)
262     {
263       case RMODE_ROUTER:
264         type = ntohs(*((unsigned short*)(&packet->data[12])));
265         switch(type)
266           {
267             case 0x0800:
268               n = route_ipv4(packet);
269               break;
270             case 0x86DD:
271               n = route_ipv6(packet);
272               break;
273             case 0x0806:
274               route_arp(packet);
275               return;
276             default:
277               if(debug_lvl >= DEBUG_TRAFFIC)
278                 {
279                   syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
280                 }
281               return;
282            }
283          if(n)
284            send_packet(n, packet);
285          break;
286         
287       case RMODE_SWITCH:
288         n = route_mac(packet);
289         if(n)
290           send_packet(n, packet);
291         else
292           broadcast_packet(myself, packet);
293         break;
294         
295       case RMODE_HUB:
296         broadcast_packet(myself, packet);
297         break;
298     }
299 }
300
301 void route_incoming(node_t *source, vpn_packet_t *packet)
302 {
303   switch(routing_mode)
304     {
305       case RMODE_ROUTER:
306         {
307           node_t *n = NULL;
308           unsigned short int type;
309
310           type = ntohs(*((unsigned short*)(&packet->data[12])));
311           switch(type)
312             {
313               case 0x0800:
314                 n = route_ipv4(packet);
315                 break;
316               case 0x86DD:
317                 n = route_ipv6(packet);
318                 break;
319               default:
320                 n = myself;
321                 break;
322              }
323
324           if(n)
325             {
326               if(n == myself)
327                 {
328                   memcpy(packet->data, mymac.net.mac.address.x, 6);
329                   write_packet(packet);
330                 }
331               else
332                 send_packet(n, packet);
333             }
334           }
335         break;
336       case RMODE_SWITCH:
337         {
338           subnet_t *subnet;
339
340           subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
341
342           if(subnet)
343             {
344               if(subnet->owner == myself)
345                 write_packet(packet);
346               else
347                 send_packet(subnet->owner, packet);
348             }
349           else
350             {
351               broadcast_packet(source, packet);
352               write_packet(packet);
353             }
354           }
355         break;
356       case RMODE_HUB:
357         broadcast_packet(source, packet);                       /* Spread it on */
358         write_packet(packet);
359         break;
360     }
361 }