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.31 2002/03/11 13:56:00 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/ip6.h>
37 #include <netinet/icmp6.h>
38 #include <netinet/if_ether.h>
47 #include "connection.h"
55 int routing_mode = RMODE_ROUTER;
56 int priorityinheritance = 0;
61 #define s6_addr16 __u6_addr.__u6_addr16
64 void learn_mac(mac_t *address)
70 subnet = lookup_subnet_mac(address);
72 /* If we don't know this MAC address yet, store it */
74 if(!subnet || subnet->owner!=myself)
76 if(debug_lvl >= DEBUG_TRAFFIC)
77 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
78 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
80 subnet = new_subnet();
81 subnet->type = SUBNET_MAC;
82 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
83 subnet_add(myself, subnet);
85 /* And tell all other tinc daemons it's our MAC */
87 for(node = connection_tree->head; node; node = node->next)
89 c = (connection_t *)node->data;
91 send_add_subnet(c, subnet);
95 subnet->net.mac.lastseen = now;
102 avl_node_t *node, *next, *node2;
104 for(node = myself->subnet_tree->head; node; node = next)
107 s = (subnet_t *)node->data;
108 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
110 if(debug_lvl >= DEBUG_TRAFFIC)
111 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
112 s->net.mac.address.x[0], s->net.mac.address.x[1], s->net.mac.address.x[2], s->net.mac.address.x[3], s->net.mac.address.x[4], s->net.mac.address.x[5]);
113 for(node2 = connection_tree->head; node2; node2 = node2->next)
115 c = (connection_t *)node2->data;
117 send_del_subnet(c, s);
119 subnet_del(myself, s);
125 node_t *route_mac(vpn_packet_t *packet)
129 /* Learn source address */
131 learn_mac((mac_t *)(&packet->data[6]));
133 /* Lookup destination address */
135 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
138 return subnet->owner;
143 node_t *route_ipv4(vpn_packet_t *packet)
147 if(priorityinheritance)
148 packet->priority = packet->data[15];
150 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
154 if(debug_lvl >= DEBUG_TRAFFIC)
156 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
157 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
163 return subnet->owner;
166 node_t *route_ipv6(vpn_packet_t *packet)
170 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
174 if(debug_lvl >= DEBUG_TRAFFIC)
176 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
177 ntohs(*(short unsigned int *)&packet->data[38]),
178 ntohs(*(short unsigned int *)&packet->data[40]),
179 ntohs(*(short unsigned int *)&packet->data[42]),
180 ntohs(*(short unsigned int *)&packet->data[44]),
181 ntohs(*(short unsigned int *)&packet->data[46]),
182 ntohs(*(short unsigned int *)&packet->data[48]),
183 ntohs(*(short unsigned int *)&packet->data[50]),
184 ntohs(*(short unsigned int *)&packet->data[52]));
190 return subnet->owner;
193 node_t *route_neighborsol(vpn_packet_t *packet)
196 struct nd_neighbor_solicit *ns;
199 hdr = (struct ip6_hdr *)(packet->data + 14);
200 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(struct ip6_hdr));
202 /* First, snatch the source address from the neighbor solicitation packet */
204 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
206 /* Check if this is a valid neighbor solicitation request */
208 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT)
210 if(debug_lvl > DEBUG_TRAFFIC)
212 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
217 /* Check if the IPv6 address exists on the VPN */
219 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
223 if(debug_lvl >= DEBUG_TRAFFIC)
225 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
226 ntohs(ns->nd_ns_target.s6_addr16[0]), ntohs(ns->nd_ns_target.s6_addr16[1]), ntohs(ns->nd_ns_target.s6_addr16[2]), ntohs(ns->nd_ns_target.s6_addr16[3]),
227 ntohs(ns->nd_ns_target.s6_addr16[4]), ntohs(ns->nd_ns_target.s6_addr16[5]), ntohs(ns->nd_ns_target.s6_addr16[6]), ntohs(ns->nd_ns_target.s6_addr16[7]));
233 /* Check if it is for our own subnet */
235 if(subnet->owner == myself)
236 return NULL; /* silently ignore */
238 /* Forward to destination */
240 return subnet->owner;
244 void route_arp(vpn_packet_t *packet)
246 struct ether_arp *arp;
248 unsigned char ipbuf[4];
250 /* First, snatch the source address from the ARP packet */
252 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
254 /* This routine generates replies to ARP requests.
255 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
256 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
259 arp = (struct ether_arp *)(packet->data + 14);
261 /* Check if this is a valid ARP request */
263 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
264 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
265 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
266 (int) (arp->arp_pln) != 4 ||
267 ntohs(arp->arp_op) != ARPOP_REQUEST )
269 if(debug_lvl > DEBUG_TRAFFIC)
271 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
276 /* Check if the IPv4 address exists on the VPN */
278 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
282 if(debug_lvl >= DEBUG_TRAFFIC)
284 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
285 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
291 /* Check if it is for our own subnet */
293 if(subnet->owner == myself)
294 return; /* silently ignore */
296 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
297 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
299 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
300 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
301 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
303 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
304 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
305 arp->arp_op = htons(ARPOP_REPLY);
307 write_packet(packet);
311 void route_outgoing(vpn_packet_t *packet)
313 unsigned short int type;
316 /* FIXME: multicast? */
321 type = ntohs(*((unsigned short*)(&packet->data[12])));
325 n = route_ipv4(packet);
328 n = route_ipv6(packet);
329 if(!n && packet->data[0] == 0x33 && packet->data[1] == 0x33 && packet->data[2] == 0xff)
330 n = route_neighborsol(packet);
336 if(debug_lvl >= DEBUG_TRAFFIC)
338 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
343 send_packet(n, packet);
347 n = route_mac(packet);
349 send_packet(n, packet);
351 broadcast_packet(myself, packet);
355 broadcast_packet(myself, packet);
360 void route_incoming(node_t *source, vpn_packet_t *packet)
367 unsigned short int type;
369 type = ntohs(*((unsigned short*)(&packet->data[12])));
373 n = route_ipv4(packet);
376 n = route_ipv6(packet);
387 memcpy(packet->data, mymac.net.mac.address.x, 6);
388 write_packet(packet);
391 send_packet(n, packet);
399 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
403 if(subnet->owner == myself)
404 write_packet(packet);
406 send_packet(subnet->owner, packet);
410 broadcast_packet(source, packet);
411 write_packet(packet);
416 broadcast_packet(source, packet); /* Spread it on */
417 write_packet(packet);