3 Copyright (C) 2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000-2002 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.26 2002/03/01 14:09:31 guus Exp $
25 #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD)
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;
54 int priorityinheritance = 0;
58 void learn_mac(mac_t *address)
64 subnet = lookup_subnet_mac(address);
66 /* If we don't know this MAC address yet, store it */
68 if(!subnet || subnet->owner!=myself)
70 if(debug_lvl >= DEBUG_TRAFFIC)
71 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
72 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
74 subnet = new_subnet();
75 subnet->type = SUBNET_MAC;
76 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
77 subnet_add(myself, subnet);
79 /* And tell all other tinc daemons it's our MAC */
81 for(node = connection_tree->head; node; node = node->next)
83 c = (connection_t *)node->data;
85 send_add_subnet(c, subnet);
89 subnet->net.mac.lastseen = now;
96 avl_node_t *node, *next, *node2;
98 for(node = myself->subnet_tree->head; node; node = next)
100 s = (subnet_t *)node->data;
101 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
103 for(node2 = connection_tree->head; node2; node2 = node2->next)
105 c = (connection_t *)node2->data;
107 send_del_subnet(c, s);
109 subnet_del(myself, s);
115 node_t *route_mac(vpn_packet_t *packet)
119 /* Learn source address */
121 learn_mac((mac_t *)(&packet->data[6]));
123 /* Lookup destination address */
125 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
128 return subnet->owner;
133 node_t *route_ipv4(vpn_packet_t *packet)
137 if(priorityinheritance)
138 packet->priority = packet->data[15];
140 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
144 if(debug_lvl >= DEBUG_TRAFFIC)
146 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
147 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
153 return subnet->owner;
156 node_t *route_ipv6(vpn_packet_t *packet)
160 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
164 if(debug_lvl >= DEBUG_TRAFFIC)
166 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
167 ntohs(*(short unsigned int *)&packet->data[38]),
168 ntohs(*(short unsigned int *)&packet->data[40]),
169 ntohs(*(short unsigned int *)&packet->data[42]),
170 ntohs(*(short unsigned int *)&packet->data[44]),
171 ntohs(*(short unsigned int *)&packet->data[46]),
172 ntohs(*(short unsigned int *)&packet->data[48]),
173 ntohs(*(short unsigned int *)&packet->data[50]),
174 ntohs(*(short unsigned int *)&packet->data[52]));
180 return subnet->owner;
183 void route_arp(vpn_packet_t *packet)
185 struct ether_arp *arp;
187 unsigned char ipbuf[4];
189 /* First, snatch the source address from the ARP packet */
191 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
193 /* This routine generates replies to ARP requests.
194 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
195 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
198 arp = (struct ether_arp *)(packet->data + 14);
200 /* Check if this is a valid ARP request */
202 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
203 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
204 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
205 (int) (arp->arp_pln) != 4 ||
206 ntohs(arp->arp_op) != ARPOP_REQUEST )
208 if(debug_lvl > DEBUG_TRAFFIC)
210 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
215 /* Check if the IP address exists on the VPN */
217 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
221 if(debug_lvl >= DEBUG_TRAFFIC)
223 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
224 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
230 /* Check if it is for our own subnet */
232 if(subnet->owner == myself)
233 return; /* silently ignore */
235 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
236 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
238 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
239 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
240 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
242 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
243 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
244 arp->arp_op = htons(ARPOP_REPLY);
246 write_packet(packet);
250 void route_outgoing(vpn_packet_t *packet)
252 unsigned short int type;
255 /* FIXME: multicast? */
260 type = ntohs(*((unsigned short*)(&packet->data[12])));
264 n = route_ipv4(packet);
267 n = route_ipv6(packet);
273 if(debug_lvl >= DEBUG_TRAFFIC)
275 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
280 send_packet(n, packet);
284 n = route_mac(packet);
286 send_packet(n, packet);
288 broadcast_packet(myself, packet);
292 broadcast_packet(myself, packet);
297 void route_incoming(node_t *source, vpn_packet_t *packet)
305 n = route_ipv4(packet);
311 memcpy(packet->data, mymac.net.mac.address.x, 6);
312 write_packet(packet);
315 send_packet(n, packet);
323 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
327 if(subnet->owner == myself)
328 write_packet(packet);
330 send_packet(subnet->owner, packet);
334 broadcast_packet(source, packet);
335 write_packet(packet);
340 broadcast_packet(source, packet); /* Spread it on */
341 write_packet(packet);