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