3 Copyright (C) 2000-2003 Ivo Timmermans <ivo@o2w.nl>,
4 2000-2003 Guus Sliepen <guus@sliepen.eu.org>
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.66 2003/10/01 09:14:01 guus Exp $
25 #ifdef HAVE_NET_ETHERNET_H
26 #include <net/ethernet.h>
28 #ifdef HAVE_NET_IF_ARP_H
29 #include <net/if_arp.h>
31 #ifdef HAVE_NETINET_IP_ICMP_H
32 #include <netinet/ip_icmp.h>
34 #ifdef HAVE_NETINET_ICMP6_H
35 #include <netinet/icmp6.h>
37 #ifdef HAVE_NETINET_IF_ETHER_H
38 #include <netinet/if_ether.h>
42 #include "connection.h"
54 rmode_t routing_mode = RMODE_ROUTER;
55 bool priorityinheritance = false;
57 bool overwrite_mac = false;
58 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
62 static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
65 uint32_t checksum = prevsum ^ 0xFFFF;
73 checksum += *(unsigned char *)p;
76 checksum = (checksum & 0xFFFF) + (checksum >> 16);
81 static bool ratelimit(void) {
82 static time_t lasttime = 0;
91 static void learn_mac(mac_t *address)
99 subnet = lookup_subnet_mac(address);
101 /* If we don't know this MAC address yet, store it */
103 if(!subnet || subnet->owner != myself) {
104 ifdebug(TRAFFIC) logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
105 address->x[0], address->x[1], address->x[2], address->x[3],
106 address->x[4], address->x[5]);
108 subnet = new_subnet();
109 subnet->type = SUBNET_MAC;
110 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
111 subnet_add(myself, subnet);
113 /* And tell all other tinc daemons it's our MAC */
115 for(node = connection_tree->head; node; node = node->next) {
118 send_add_subnet(c, subnet);
122 subnet->net.mac.lastseen = now;
129 avl_node_t *node, *next, *node2;
133 for(node = myself->subnet_tree->head; node; node = next) {
136 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
137 ifdebug(TRAFFIC) logger(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
138 s->net.mac.address.x[0], s->net.mac.address.x[1],
139 s->net.mac.address.x[2], s->net.mac.address.x[3],
140 s->net.mac.address.x[4], s->net.mac.address.x[5]);
142 for(node2 = connection_tree->head; node2; node2 = node2->next) {
145 send_del_subnet(c, s);
148 subnet_del(myself, s);
153 static node_t *route_mac(vpn_packet_t *packet)
159 /* Learn source address */
161 learn_mac((mac_t *)(&packet->data[6]));
163 /* Lookup destination address */
165 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
168 return subnet->owner;
175 static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
180 struct in_addr ip_src;
181 struct in_addr ip_dst;
189 hdr = (struct ip *)(packet->data + 14);
190 icmp = (struct icmp *)(packet->data + 14 + 20);
192 /* Remember original source and destination */
194 memcpy(&ip_src, &hdr->ip_src, 4);
195 memcpy(&ip_dst, &hdr->ip_dst, 4);
196 oldlen = packet->len - 14;
198 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
199 oldlen = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
201 /* Copy first part of original contents to ICMP message */
203 memmove(&icmp->icmp_ip, hdr, oldlen);
205 /* Fill in IPv4 header */
208 hdr->ip_hl = sizeof(*hdr) / 4;
210 hdr->ip_len = htons(20 + 8 + oldlen);
214 hdr->ip_p = IPPROTO_ICMP;
216 memcpy(&hdr->ip_src, &ip_dst, 4);
217 memcpy(&hdr->ip_dst, &ip_src, 4);
219 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
221 /* Fill in ICMP header */
223 icmp->icmp_type = ICMP_DEST_UNREACH;
224 icmp->icmp_code = code;
225 icmp->icmp_cksum = 0;
227 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
229 packet->len = 14 + 20 + 8 + oldlen;
231 write_packet(packet);
234 static node_t *route_ipv4(vpn_packet_t *packet)
240 if(priorityinheritance)
241 packet->priority = packet->data[15];
243 subnet = lookup_subnet_ipv4((ipv4_t *) &packet->data[30]);
246 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
247 packet->data[30], packet->data[31], packet->data[32],
250 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
254 if(!subnet->owner->status.reachable)
255 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
257 return subnet->owner;
262 static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
265 struct icmp6_hdr *icmp;
269 struct in6_addr ip6_src; /* source address */
270 struct in6_addr ip6_dst; /* destination address */
280 hdr = (struct ip6_hdr *)(packet->data + 14);
281 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
283 /* Remember original source and destination */
285 memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
286 memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
287 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
289 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
290 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
292 /* Copy first part of original contents to ICMP message */
294 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
296 /* Fill in IPv6 header */
298 hdr->ip6_flow = htonl(0x60000000UL);
299 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
300 hdr->ip6_nxt = IPPROTO_ICMPV6;
302 memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
303 memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
305 /* Fill in ICMP header */
307 icmp->icmp6_type = ICMP6_DST_UNREACH;
308 icmp->icmp6_code = code;
309 icmp->icmp6_cksum = 0;
311 /* Create pseudo header */
313 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
314 pseudo.next = htonl(IPPROTO_ICMPV6);
316 /* Generate checksum */
318 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
319 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
321 icmp->icmp6_cksum = checksum;
323 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
325 write_packet(packet);
328 static node_t *route_ipv6(vpn_packet_t *packet)
334 subnet = lookup_subnet_ipv6((ipv6_t *) &packet->data[38]);
337 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
338 ntohs(*(uint16_t *) &packet->data[38]),
339 ntohs(*(uint16_t *) &packet->data[40]),
340 ntohs(*(uint16_t *) &packet->data[42]),
341 ntohs(*(uint16_t *) &packet->data[44]),
342 ntohs(*(uint16_t *) &packet->data[46]),
343 ntohs(*(uint16_t *) &packet->data[48]),
344 ntohs(*(uint16_t *) &packet->data[50]),
345 ntohs(*(uint16_t *) &packet->data[52]));
346 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
351 if(!subnet->owner->status.reachable)
352 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
354 return subnet->owner;
359 static void route_neighborsol(vpn_packet_t *packet)
362 struct nd_neighbor_solicit *ns;
363 struct nd_opt_hdr *opt;
368 struct in6_addr ip6_src; /* source address */
369 struct in6_addr ip6_dst; /* destination address */
376 hdr = (struct ip6_hdr *)(packet->data + 14);
377 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
378 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
380 /* First, snatch the source address from the neighbor solicitation packet */
383 memcpy(mymac.x, packet->data + 6, 6);
385 /* Check if this is a valid neighbor solicitation request */
387 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
388 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
389 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
393 /* Create pseudo header */
395 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
396 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
397 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
398 pseudo.next = htonl(IPPROTO_ICMPV6);
400 /* Generate checksum */
402 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
403 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
406 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
410 /* Check if the IPv6 address exists on the VPN */
412 subnet = lookup_subnet_ipv6((ipv6_t *) &ns->nd_ns_target);
415 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
416 ntohs(((uint16_t *) &ns->nd_ns_target)[0]),
417 ntohs(((uint16_t *) &ns->nd_ns_target)[1]),
418 ntohs(((uint16_t *) &ns->nd_ns_target)[2]),
419 ntohs(((uint16_t *) &ns->nd_ns_target)[3]),
420 ntohs(((uint16_t *) &ns->nd_ns_target)[4]),
421 ntohs(((uint16_t *) &ns->nd_ns_target)[5]),
422 ntohs(((uint16_t *) &ns->nd_ns_target)[6]),
423 ntohs(((uint16_t *) &ns->nd_ns_target)[7]));
428 /* Check if it is for our own subnet */
430 if(subnet->owner == myself)
431 return; /* silently ignore */
433 /* Create neighbor advertation reply */
435 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
436 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
438 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
439 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
441 memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
443 ns->nd_ns_hdr.icmp6_cksum = 0;
444 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
445 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
446 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
447 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
448 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
449 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
451 /* Create pseudo header */
453 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
454 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
455 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
456 pseudo.next = htonl(IPPROTO_ICMPV6);
458 /* Generate checksum */
460 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
461 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
463 ns->nd_ns_hdr.icmp6_cksum = checksum;
465 write_packet(packet);
470 static void route_arp(vpn_packet_t *packet)
472 struct ether_arp *arp;
478 /* First, snatch the source address from the ARP packet */
481 memcpy(mymac.x, packet->data + 6, 6);
483 /* This routine generates replies to ARP requests.
484 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
485 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
488 arp = (struct ether_arp *)(packet->data + 14);
490 /* Check if this is a valid ARP request */
492 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
493 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
494 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
498 /* Check if the IPv4 address exists on the VPN */
500 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
503 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
504 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
509 /* Check if it is for our own subnet */
511 if(subnet->owner == myself)
512 return; /* silently ignore */
514 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
515 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
517 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
518 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
519 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
521 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
522 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
523 arp->arp_op = htons(ARPOP_REPLY);
525 write_packet(packet);
528 void route_outgoing(vpn_packet_t *packet)
535 if(packet->len < 14) {
536 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
540 /* FIXME: multicast? */
542 switch (routing_mode) {
544 type = ntohs(*((uint16_t *)(&packet->data[12])));
547 if(packet->len < 34) {
548 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
552 n = route_ipv4(packet);
556 if(packet->len < 54) {
557 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
561 if(packet->data[20] == IPPROTO_ICMPV6 && packet->len >= 62 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
562 route_neighborsol(packet);
565 n = route_ipv6(packet);
569 if(packet->len < 42) {
570 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
578 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
582 send_packet(n, packet);
586 n = route_mac(packet);
588 send_packet(n, packet);
590 broadcast_packet(myself, packet);
594 broadcast_packet(myself, packet);
599 void route_incoming(node_t *source, vpn_packet_t *packet)
601 if(packet->len < 14) {
602 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got too short packet from %s (%s)"),
603 source->name, source->hostname);
607 switch (routing_mode) {
613 type = ntohs(*((uint16_t *)(&packet->data[12])));
616 if(packet->len < 34) {
617 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
621 n = route_ipv4(packet);
625 if(packet->len < 54) {
626 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Read too short packet"));
630 n = route_ipv6(packet);
641 memcpy(packet->data, mymac.x, 6);
642 write_packet(packet);
644 send_packet(n, packet);
653 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
656 if(subnet->owner == myself)
657 write_packet(packet);
659 send_packet(subnet->owner, packet);
661 broadcast_packet(source, packet);
662 write_packet(packet);
668 broadcast_packet(source, packet); /* Spread it on */
669 write_packet(packet);