Make sure everything links.
[tinc] / src / route.c
1 /*
2     route.c -- routing
3     Copyright (C) 2000,2001 Ivo Timmermans <itimmermans@bigfoot.com>,
4                   2000,2001 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.20 2001/10/27 13:13:35 guus Exp $
21 */
22
23 #include "config.h"
24
25 #ifdef HAVE_FREEBSD
26  #include <sys/param.h>
27 #endif
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #ifdef HAVE_SOLARIS
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 subnet_t mymac;
55
56 void learn_mac(mac_t *address)
57 {
58   subnet_t *subnet;
59   avl_node_t *node;
60   connection_t *c;
61 cp
62   subnet = lookup_subnet_mac(address);
63
64   /* If we don't know this MAC address yet, store it */
65   
66   if(!subnet || subnet->owner!=myself)
67     {
68       if(debug_lvl >= DEBUG_TRAFFIC)
69         syslog(LOG_INFO, _("Learned new MAC address %hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
70                address->x[0], address->x[1], address->x[2], address->x[3],  address->x[4], address->x[5]);
71                
72       subnet = new_subnet();
73       subnet->type = SUBNET_MAC;
74       memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
75       subnet_add(myself, subnet);
76
77       /* And tell all other tinc daemons it's our MAC */
78       
79       for(node = connection_tree->head; node; node = node->next)
80         {
81           c = (connection_t *)node->data;
82           if(c->status.active)
83             send_add_subnet(c, subnet);
84         }
85     }
86 }
87
88 node_t *route_mac(vpn_packet_t *packet)
89 {
90   subnet_t *subnet;
91 cp
92   /* Learn source address */
93
94   learn_mac((mac_t *)(&packet->data[6]));
95   
96   /* Lookup destination address */
97     
98   subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
99
100   if(subnet)
101     return subnet->owner;
102   else
103     return NULL;
104 }
105
106 node_t *route_ipv4(vpn_packet_t *packet)
107 {
108   ipv4_t dest;
109   subnet_t *subnet;
110 cp
111 #ifdef HAVE_SOLARIS
112   /* The other form gives bus errors on a SparcStation 20. */
113   dest = ((packet->data[30] * 0x100 + packet->data[31]) * 0x100 + packet->data[32]) * 0x100 + packet->data[33];
114 #else
115   dest = ntohl(*((unsigned long*)(&packet->data[30])));
116 #endif
117 cp  
118   subnet = lookup_subnet_ipv4(&dest);
119 cp
120   if(!subnet)
121     {
122       if(debug_lvl >= DEBUG_TRAFFIC)
123         {
124           syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
125                  packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
126         }
127
128       return NULL;
129     }
130 cp
131   return subnet->owner;  
132 }
133
134 node_t *route_ipv6(vpn_packet_t *packet)
135 {
136   ipv6_t dest;
137   subnet_t *subnet;
138 cp
139   memcpy(&dest, &packet->data[30], sizeof(ipv6_t));
140
141   subnet = lookup_subnet_ipv6(&dest);
142 cp
143   if(!subnet)
144     {
145       if(debug_lvl >= DEBUG_TRAFFIC)
146         {
147           syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address"));
148         }
149
150       return NULL;
151     }
152 cp
153   return subnet->owner;  
154 }
155
156 void route_arp(vpn_packet_t *packet)
157 {
158   struct ether_arp *arp;
159   subnet_t *subnet;
160   unsigned char ipbuf[4];
161   ipv4_t dest;
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   dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
192   subnet = lookup_subnet_ipv4(&dest);
193
194   if(!subnet)
195     {
196       if(debug_lvl >= DEBUG_TRAFFIC)
197         {
198           syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
199                  arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
200         }
201
202       return;
203     }
204
205   /* Check if it is for our own subnet */
206   
207   if(subnet->owner == myself)
208     return;     /* silently ignore */
209
210   memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* copy destination address */
211   packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF;                           /* mangle source address so it looks like it's not from us */
212
213   memcpy(ipbuf, arp->arp_tpa, 4);                                       /* save protocol addr */
214   memcpy(arp->arp_tpa, arp->arp_spa, 4);                                /* swap destination and source protocol address */
215   memcpy(arp->arp_spa, ipbuf, 4);                                       /* ... */
216
217   memcpy(arp->arp_tha, arp->arp_sha, 10);                               /* set target hard/proto addr */
218   memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN);  /* add fake source hard addr */
219   arp->arp_op = htons(ARPOP_REPLY);
220   
221   write_packet(packet);
222 cp
223 }
224
225 void route_outgoing(vpn_packet_t *packet)
226 {
227   unsigned short int type;
228   node_t *n;
229 cp
230   /* FIXME: multicast? */
231
232   switch(routing_mode)
233     {
234       case RMODE_ROUTER:
235         type = ntohs(*((unsigned short*)(&packet->data[12])));
236         switch(type)
237           {
238             case 0x0800:
239               n = route_ipv4(packet);
240               break;
241             case 0x86DD:
242               n = route_ipv6(packet);
243               break;
244             case 0x0806:
245               route_arp(packet);
246               return;
247             default:
248               if(debug_lvl >= DEBUG_TRAFFIC)
249                 {
250                   syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
251                 }
252               return;
253            }
254          if(n)
255            send_packet(n, packet);
256          break;
257         
258       case RMODE_SWITCH:
259         n = route_mac(packet);
260         if(n)
261           send_packet(n, packet);
262         else
263           broadcast_packet(myself, packet);
264         break;
265         
266       case RMODE_HUB:
267         broadcast_packet(myself, packet);
268         break;
269     }
270 }
271
272 void route_incoming(node_t *source, vpn_packet_t *packet)
273 {
274   switch(routing_mode)
275     {
276       case RMODE_ROUTER:
277         memcpy(packet->data, mymac.net.mac.address.x, 6);       /* Override destination address to make the kernel accept it */
278         write_packet(packet);
279         break;
280       case RMODE_SWITCH:
281         {
282           subnet_t *subnet;
283
284           subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
285
286           if(subnet)
287             {
288               if(subnet->owner == myself)
289                 write_packet(packet);
290               else
291                 send_packet(subnet->owner, packet);
292             }
293           else
294             {
295               broadcast_packet(source, packet);
296               write_packet(packet);
297             }
298           }
299         break;
300       case RMODE_HUB:
301         broadcast_packet(source, packet);                       /* Spread it on */
302         write_packet(packet);
303         break;
304     }
305 }