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