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