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