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