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