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.20 2001/10/27 13:13:35 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"
53 int routing_mode = RMODE_ROUTER;
56 void learn_mac(mac_t *address)
62 subnet = lookup_subnet_mac(address);
64 /* If we don't know this MAC address yet, store it */
66 if(!subnet || subnet->owner!=myself)
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]);
72 subnet = new_subnet();
73 subnet->type = SUBNET_MAC;
74 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
75 subnet_add(myself, subnet);
77 /* And tell all other tinc daemons it's our MAC */
79 for(node = connection_tree->head; node; node = node->next)
81 c = (connection_t *)node->data;
83 send_add_subnet(c, subnet);
88 node_t *route_mac(vpn_packet_t *packet)
92 /* Learn source address */
94 learn_mac((mac_t *)(&packet->data[6]));
96 /* Lookup destination address */
98 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
101 return subnet->owner;
106 node_t *route_ipv4(vpn_packet_t *packet)
112 /* The other form gives bus errors on a SparcStation 20. */
113 dest = ((packet->data[30] * 0x100 + packet->data[31]) * 0x100 + packet->data[32]) * 0x100 + packet->data[33];
115 dest = ntohl(*((unsigned long*)(&packet->data[30])));
118 subnet = lookup_subnet_ipv4(&dest);
122 if(debug_lvl >= DEBUG_TRAFFIC)
124 syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
125 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
131 return subnet->owner;
134 node_t *route_ipv6(vpn_packet_t *packet)
139 memcpy(&dest, &packet->data[30], sizeof(ipv6_t));
141 subnet = lookup_subnet_ipv6(&dest);
145 if(debug_lvl >= DEBUG_TRAFFIC)
147 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address"));
153 return subnet->owner;
156 void route_arp(vpn_packet_t *packet)
158 struct ether_arp *arp;
160 unsigned char ipbuf[4];
163 /* First, snatch the source address from the ARP packet */
165 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
167 /* This routine generates replies to ARP requests.
168 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
169 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
172 arp = (struct ether_arp *)(packet->data + 14);
174 /* Check if this is a valid ARP request */
176 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
177 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
178 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
179 (int) (arp->arp_pln) != 4 ||
180 ntohs(arp->arp_op) != ARPOP_REQUEST )
182 if(debug_lvl > DEBUG_TRAFFIC)
184 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
189 /* Check if the IP address exists on the VPN */
191 dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
192 subnet = lookup_subnet_ipv4(&dest);
196 if(debug_lvl >= DEBUG_TRAFFIC)
198 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
199 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
205 /* Check if it is for our own subnet */
207 if(subnet->owner == myself)
208 return; /* silently ignore */
210 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
211 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
213 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
214 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
215 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
217 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
218 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
219 arp->arp_op = htons(ARPOP_REPLY);
221 write_packet(packet);
225 void route_outgoing(vpn_packet_t *packet)
227 unsigned short int type;
230 /* FIXME: multicast? */
235 type = ntohs(*((unsigned short*)(&packet->data[12])));
239 n = route_ipv4(packet);
242 n = route_ipv6(packet);
248 if(debug_lvl >= DEBUG_TRAFFIC)
250 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
255 send_packet(n, packet);
259 n = route_mac(packet);
261 send_packet(n, packet);
263 broadcast_packet(myself, packet);
267 broadcast_packet(myself, packet);
272 void route_incoming(node_t *source, vpn_packet_t *packet)
277 memcpy(packet->data, mymac.net.mac.address.x, 6); /* Override destination address to make the kernel accept it */
278 write_packet(packet);
284 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
288 if(subnet->owner == myself)
289 write_packet(packet);
291 send_packet(subnet->owner, packet);
295 broadcast_packet(source, packet);
296 write_packet(packet);
301 broadcast_packet(source, packet); /* Spread it on */
302 write_packet(packet);