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