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