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.40 2002/06/08 12:57:10 guus Exp $
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
33 #ifdef HAVE_NET_ETHERNET_H
34 #include <net/ethernet.h>
36 #include <netinet/ip6.h>
37 #include <netinet/icmp6.h>
38 #include <netinet/if_ether.h>
50 #include "connection.h"
58 #ifndef ETHER_ADDR_LEN
59 #define ETHER_ADDR_LEN 6
62 int routing_mode = RMODE_ROUTER;
63 int priorityinheritance = 0;
67 void learn_mac(mac_t *address)
73 subnet = lookup_subnet_mac(address);
75 /* If we don't know this MAC address yet, store it */
77 if(!subnet || subnet->owner!=myself)
79 if(debug_lvl >= DEBUG_TRAFFIC)
80 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
81 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
83 subnet = new_subnet();
84 subnet->type = SUBNET_MAC;
85 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
86 subnet_add(myself, subnet);
88 /* And tell all other tinc daemons it's our MAC */
90 for(node = connection_tree->head; node; node = node->next)
92 c = (connection_t *)node->data;
94 send_add_subnet(c, subnet);
98 subnet->net.mac.lastseen = now;
105 avl_node_t *node, *next, *node2;
107 for(node = myself->subnet_tree->head; node; node = next)
110 s = (subnet_t *)node->data;
111 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
113 if(debug_lvl >= DEBUG_TRAFFIC)
114 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
115 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]);
116 for(node2 = connection_tree->head; node2; node2 = node2->next)
118 c = (connection_t *)node2->data;
120 send_del_subnet(c, s);
122 subnet_del(myself, s);
128 node_t *route_mac(vpn_packet_t *packet)
132 /* Learn source address */
134 learn_mac((mac_t *)(&packet->data[6]));
136 /* Lookup destination address */
138 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
141 return subnet->owner;
146 node_t *route_ipv4(vpn_packet_t *packet)
150 if(priorityinheritance)
151 packet->priority = packet->data[15];
153 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
157 if(debug_lvl >= DEBUG_TRAFFIC)
159 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
160 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
166 return subnet->owner;
169 node_t *route_ipv6(vpn_packet_t *packet)
173 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
177 if(debug_lvl >= DEBUG_TRAFFIC)
179 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
180 ntohs(*(uint16_t *)&packet->data[38]),
181 ntohs(*(uint16_t *)&packet->data[40]),
182 ntohs(*(uint16_t *)&packet->data[42]),
183 ntohs(*(uint16_t *)&packet->data[44]),
184 ntohs(*(uint16_t *)&packet->data[46]),
185 ntohs(*(uint16_t *)&packet->data[48]),
186 ntohs(*(uint16_t *)&packet->data[50]),
187 ntohs(*(uint16_t *)&packet->data[52]));
193 return subnet->owner;
196 uint16_t inet_checksum(uint16_t *data, int len, uint16_t prevsum)
198 uint32_t checksum = prevsum ^ 0xFFFF;
201 checksum += ntohs(*data++);
203 while(checksum >> 16)
204 checksum = (checksum & 0xFFFF) + (checksum >> 16);
206 return checksum ^ 0xFFFF;
209 void route_neighborsol(vpn_packet_t *packet)
212 struct nd_neighbor_solicit *ns;
213 struct nd_opt_hdr *opt;
218 struct in6_addr ip6_src; /* source address */
219 struct in6_addr ip6_dst; /* destination address */
225 hdr = (struct ip6_hdr *)(packet->data + 14);
226 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
227 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
229 /* First, snatch the source address from the neighbor solicitation packet */
231 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
233 /* Check if this is a valid neighbor solicitation request */
235 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
236 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
238 if(debug_lvl > DEBUG_TRAFFIC)
240 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
245 /* Create pseudo header */
247 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
248 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
249 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
250 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
251 pseudo.junk[3] = IPPROTO_ICMPV6;
253 /* Generate checksum */
255 checksum = inet_checksum((uint16_t *)&pseudo, sizeof(pseudo)/2, ~0);
256 checksum = inet_checksum((uint16_t *)ns, sizeof(*ns)/2 + 4, checksum);
260 if(debug_lvl >= DEBUG_TRAFFIC)
261 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
265 /* Check if the IPv6 address exists on the VPN */
267 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
271 if(debug_lvl >= DEBUG_TRAFFIC)
273 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
274 ntohs(((uint16_t *)&ns->nd_ns_target)[0]), ntohs(((uint16_t *)&ns->nd_ns_target)[1]), ntohs(((uint16_t *)&ns->nd_ns_target)[2]), ntohs(((uint16_t *)&ns->nd_ns_target)[3]),
275 ntohs(((uint16_t *)&ns->nd_ns_target)[4]), ntohs(((uint16_t *)&ns->nd_ns_target)[5]), ntohs(((uint16_t *)&ns->nd_ns_target)[6]), ntohs(((uint16_t *)&ns->nd_ns_target)[7]));
281 /* Check if it is for our own subnet */
283 if(subnet->owner == myself)
284 return; /* silently ignore */
286 /* Create neighbor advertation reply */
288 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
289 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
291 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
292 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
294 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
296 ns->nd_ns_hdr.icmp6_cksum = 0;
297 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
298 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
299 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] = ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] = ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
300 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
302 /* Create pseudo header */
304 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
305 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
306 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
307 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
308 pseudo.junk[3] = IPPROTO_ICMPV6;
310 /* Generate checksum */
312 checksum = inet_checksum((uint16_t *)&pseudo, sizeof(pseudo)/2, ~0);
313 checksum = inet_checksum((uint16_t *)ns, sizeof(*ns)/2 + 4, checksum);
315 ns->nd_ns_hdr.icmp6_cksum = htons(checksum);
317 write_packet(packet);
321 void route_arp(vpn_packet_t *packet)
323 struct ether_arp *arp;
327 /* First, snatch the source address from the ARP packet */
329 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
331 /* This routine generates replies to ARP requests.
332 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
333 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
336 arp = (struct ether_arp *)(packet->data + 14);
338 /* Check if this is a valid ARP request */
340 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
341 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
342 arp->arp_hln != ETHER_ADDR_LEN ||
344 ntohs(arp->arp_op) != ARPOP_REQUEST )
346 if(debug_lvl > DEBUG_TRAFFIC)
348 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
353 /* Check if the IPv4 address exists on the VPN */
355 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
359 if(debug_lvl >= DEBUG_TRAFFIC)
361 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
362 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
368 /* Check if it is for our own subnet */
370 if(subnet->owner == myself)
371 return; /* silently ignore */
373 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
374 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
376 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
377 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
378 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
380 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
381 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
382 arp->arp_op = htons(ARPOP_REPLY);
384 write_packet(packet);
388 void route_outgoing(vpn_packet_t *packet)
393 /* FIXME: multicast? */
398 type = ntohs(*((uint16_t *)(&packet->data[12])));
402 n = route_ipv4(packet);
405 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT)
407 route_neighborsol(packet);
410 n = route_ipv6(packet);
416 if(debug_lvl >= DEBUG_TRAFFIC)
418 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
423 send_packet(n, packet);
427 n = route_mac(packet);
429 send_packet(n, packet);
431 broadcast_packet(myself, packet);
435 broadcast_packet(myself, packet);
440 void route_incoming(node_t *source, vpn_packet_t *packet)
449 type = ntohs(*((uint16_t *)(&packet->data[12])));
453 n = route_ipv4(packet);
456 n = route_ipv6(packet);
467 memcpy(packet->data, mymac.net.mac.address.x, 6);
468 write_packet(packet);
471 send_packet(n, packet);
479 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
483 if(subnet->owner == myself)
484 write_packet(packet);
486 send_packet(subnet->owner, packet);
490 broadcast_packet(source, packet);
491 write_packet(packet);
496 broadcast_packet(source, packet); /* Spread it on */
497 write_packet(packet);