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