3 Copyright (C) 2000,2001 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000,2001 Guus Sliepen <guus@sliepen.warande.net>
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.
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.
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.
20 $Id: route.c,v 1.1.2.18 2001/07/21 20:21:25 guus Exp $
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
32 #define ETHER_ADDR_LEN 6
34 #include <net/ethernet.h>
36 #include <netinet/if_ether.h>
45 #include "connection.h"
52 int routing_mode = RMODE_ROUTER;
55 void learn_mac(mac_t *address)
61 subnet = lookup_subnet_mac(address);
63 /* If we don't know this MAC address yet, store it */
65 if(!subnet || subnet->owner!=myself)
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]);
71 subnet = new_subnet();
72 subnet->type = SUBNET_MAC;
73 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
74 subnet_add(myself, subnet);
76 /* And tell all other tinc daemons it's our MAC */
78 for(node = connection_tree->head; node; node = node->next)
80 p = (connection_t *)node->data;
82 send_add_subnet(p, subnet);
87 connection_t *route_mac(vpn_packet_t *packet)
91 /* Learn source address */
93 learn_mac((mac_t *)(&packet->data[6]));
95 /* Lookup destination address */
97 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
100 return subnet->owner;
105 connection_t *route_ipv4(vpn_packet_t *packet)
111 /* The other form gives bus errors on a SparcStation 20. */
112 dest = ((packet->data[30] * 0x100 + packet->data[31]) * 0x100 + packet->data[32]) * 0x100 + packet->data[33];
114 dest = ntohl(*((unsigned long*)(&packet->data[30])));
117 subnet = lookup_subnet_ipv4(&dest);
121 if(debug_lvl >= DEBUG_TRAFFIC)
123 syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
124 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
130 return subnet->owner;
133 connection_t *route_ipv6(vpn_packet_t *packet)
136 if(debug_lvl > DEBUG_NOTHING)
138 syslog(LOG_WARNING, _("Cannot route packet: IPv6 routing not yet implemented"));
144 void route_arp(vpn_packet_t *packet)
146 struct ether_arp *arp;
148 unsigned char ipbuf[4];
151 /* First, snatch the source address from the ARP packet */
153 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
155 /* This routine generates replies to ARP requests.
156 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
157 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
160 arp = (struct ether_arp *)(packet->data + 14);
162 /* Check if this is a valid ARP request */
164 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
165 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
166 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
167 (int) (arp->arp_pln) != 4 ||
168 ntohs(arp->arp_op) != ARPOP_REQUEST )
170 if(debug_lvl > DEBUG_TRAFFIC)
172 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
177 /* Check if the IP address exists on the VPN */
179 dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
180 subnet = lookup_subnet_ipv4(&dest);
184 if(debug_lvl >= DEBUG_TRAFFIC)
186 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
187 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
193 /* Check if it is for our own subnet */
195 if(subnet->owner == myself)
196 return; /* silently ignore */
198 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
199 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
201 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
202 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
203 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
205 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
206 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
207 arp->arp_op = htons(ARPOP_REPLY);
209 accept_packet(packet);
213 void route_outgoing(vpn_packet_t *packet)
215 unsigned short int type;
218 /* FIXME: multicast? */
223 type = ntohs(*((unsigned short*)(&packet->data[12])));
227 cl = route_ipv4(packet);
230 cl = route_ipv6(packet);
236 if(debug_lvl >= DEBUG_TRAFFIC)
238 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
243 send_packet(cl, packet);
247 cl = route_mac(packet);
249 send_packet(cl, packet);
251 broadcast_packet(myself, packet);
255 broadcast_packet(myself, packet);
260 void route_incoming(connection_t *source, vpn_packet_t *packet)
265 memcpy(packet->data, mymac.net.mac.address.x, 6); /* Override destination address to make the kernel accept it */
266 accept_packet(packet);
272 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
276 if(subnet->owner == myself)
277 accept_packet(packet);
279 send_packet(subnet->owner, packet);
283 broadcast_packet(source, packet);
284 accept_packet(packet);
289 broadcast_packet(source,packet); /* Spread it on */
290 accept_packet(packet);