3 Copyright (C) 2000-2002 Ivo Timmermans <ivo@o2w.nl>,
4 2000-2002 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.53 2003/07/06 17:49:49 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 #ifdef HAVE_NETINET_IN_SYSTM_H
37 #include <netinet/in_systm.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_icmp.h>
41 #ifdef HAVE_NETINET_IP6_H
42 #include <netinet/ip6.h>
43 #include <netinet/icmp6.h>
45 #include <netinet/if_ether.h>
50 #ifdef HAVE_INTTYPES_H
57 #include "connection.h"
65 /* Missing definitions */
67 #ifndef ETHER_ADDR_LEN
68 #define ETHER_ADDR_LEN 6
71 #ifndef ICMP_DEST_UNREACH
72 #define ICMP_DEST_UNREACH 3
75 #ifndef ICMP_NET_UNKNOWN
76 #define ICMP_NET_UNKNOWN 6
79 #ifndef ICMP_NET_UNREACH
80 #define ICMP_NET_UNREACH 0
83 int routing_mode = RMODE_ROUTER;
84 int priorityinheritance = 0;
86 int overwrite_mac = 0;
87 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
91 uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
94 uint32_t checksum = prevsum ^ 0xFFFF;
102 checksum += *(unsigned char *)p;
104 while(checksum >> 16)
105 checksum = (checksum & 0xFFFF) + (checksum >> 16);
110 int ratelimit(void) {
111 static time_t lasttime = 0;
120 void learn_mac(mac_t *address)
128 subnet = lookup_subnet_mac(address);
130 /* If we don't know this MAC address yet, store it */
132 if(!subnet || subnet->owner != myself) {
133 if(debug_lvl >= DEBUG_TRAFFIC)
134 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
135 address->x[0], address->x[1], address->x[2], address->x[3],
136 address->x[4], address->x[5]);
138 subnet = new_subnet();
139 subnet->type = SUBNET_MAC;
140 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
141 subnet_add(myself, subnet);
143 /* And tell all other tinc daemons it's our MAC */
145 for(node = connection_tree->head; node; node = node->next) {
146 c = (connection_t *) node->data;
148 send_add_subnet(c, subnet);
152 subnet->net.mac.lastseen = now;
159 avl_node_t *node, *next, *node2;
163 for(node = myself->subnet_tree->head; node; node = next) {
165 s = (subnet_t *) node->data;
166 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
167 if(debug_lvl >= DEBUG_TRAFFIC)
168 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
169 s->net.mac.address.x[0], s->net.mac.address.x[1],
170 s->net.mac.address.x[2], s->net.mac.address.x[3],
171 s->net.mac.address.x[4], s->net.mac.address.x[5]);
173 for(node2 = connection_tree->head; node2; node2 = node2->next) {
174 c = (connection_t *) node2->data;
176 send_del_subnet(c, s);
179 subnet_del(myself, s);
184 node_t *route_mac(vpn_packet_t *packet)
190 /* Learn source address */
192 learn_mac((mac_t *)(&packet->data[6]));
194 /* Lookup destination address */
196 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
199 return subnet->owner;
206 void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
211 struct in_addr ip_src;
212 struct in_addr ip_dst;
220 hdr = (struct ip *)(packet->data + 14);
221 icmp = (struct icmp *)(packet->data + 14 + 20);
223 /* Remember original source and destination */
225 memcpy(&ip_src, &hdr->ip_src, 4);
226 memcpy(&ip_dst, &hdr->ip_dst, 4);
227 oldlen = packet->len - 14;
229 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
230 oldlen = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
232 /* Copy first part of original contents to ICMP message */
234 memmove(&icmp->icmp_ip, hdr, oldlen);
236 /* Fill in IPv4 header */
239 hdr->ip_hl = sizeof(*hdr) / 4;
241 hdr->ip_len = htons(20 + 8 + oldlen);
245 hdr->ip_p = IPPROTO_ICMP;
247 memcpy(&hdr->ip_src, &ip_dst, 4);
248 memcpy(&hdr->ip_dst, &ip_src, 4);
250 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
252 /* Fill in ICMP header */
254 icmp->icmp_type = ICMP_DEST_UNREACH;
255 icmp->icmp_code = code;
256 icmp->icmp_cksum = 0;
258 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
260 packet->len = 14 + 20 + 8 + oldlen;
262 write_packet(packet);
265 node_t *route_ipv4(vpn_packet_t *packet)
271 if(priorityinheritance)
272 packet->priority = packet->data[15];
274 subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
277 if(debug_lvl >= DEBUG_TRAFFIC) {
278 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
279 packet->data[30], packet->data[31], packet->data[32],
283 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
287 if(!subnet->owner->status.reachable)
288 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
290 return subnet->owner;
293 #ifdef HAVE_NETINET_IP6_H
297 void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
300 struct icmp6_hdr *icmp;
304 struct in6_addr ip6_src; /* source address */
305 struct in6_addr ip6_dst; /* destination address */
315 hdr = (struct ip6_hdr *)(packet->data + 14);
316 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
318 /* Remember original source and destination */
320 memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
321 memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
322 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
324 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
325 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
327 /* Copy first part of original contents to ICMP message */
329 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
331 /* Fill in IPv6 header */
333 hdr->ip6_flow = htonl(0x60000000UL);
334 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
335 hdr->ip6_nxt = IPPROTO_ICMPV6;
337 memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
338 memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
340 /* Fill in ICMP header */
342 icmp->icmp6_type = ICMP6_DST_UNREACH;
343 icmp->icmp6_code = code;
344 icmp->icmp6_cksum = 0;
346 /* Create pseudo header */
348 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
349 pseudo.next = htonl(IPPROTO_ICMPV6);
351 /* Generate checksum */
353 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
354 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
356 icmp->icmp6_cksum = checksum;
358 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
360 write_packet(packet);
365 node_t *route_ipv6(vpn_packet_t *packet)
371 subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
374 if(debug_lvl >= DEBUG_TRAFFIC) {
375 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
376 ntohs(*(uint16_t *) & packet->data[38]),
377 ntohs(*(uint16_t *) & packet->data[40]),
378 ntohs(*(uint16_t *) & packet->data[42]),
379 ntohs(*(uint16_t *) & packet->data[44]),
380 ntohs(*(uint16_t *) & packet->data[46]),
381 ntohs(*(uint16_t *) & packet->data[48]),
382 ntohs(*(uint16_t *) & packet->data[50]),
383 ntohs(*(uint16_t *) & packet->data[52]));
385 #ifdef HAVE_NETINET_IP6_H
386 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
392 #ifdef HAVE_NETINET_IP6_H
393 if(!subnet->owner->status.reachable)
394 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
397 return subnet->owner;
400 #ifdef HAVE_NETINET_IP6_H
404 void route_neighborsol(vpn_packet_t *packet)
407 struct nd_neighbor_solicit *ns;
408 struct nd_opt_hdr *opt;
413 struct in6_addr ip6_src; /* source address */
414 struct in6_addr ip6_dst; /* destination address */
421 hdr = (struct ip6_hdr *)(packet->data + 14);
422 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
423 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
425 /* First, snatch the source address from the neighbor solicitation packet */
428 memcpy(mymac.x, packet->data + 6, 6);
430 /* Check if this is a valid neighbor solicitation request */
432 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
433 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
434 if(debug_lvl > DEBUG_TRAFFIC) {
435 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
440 /* Create pseudo header */
442 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
443 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
444 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
445 pseudo.next = htonl(IPPROTO_ICMPV6);
447 /* Generate checksum */
449 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
450 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
453 if(debug_lvl >= DEBUG_TRAFFIC)
454 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
458 /* Check if the IPv6 address exists on the VPN */
460 subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
463 if(debug_lvl >= DEBUG_TRAFFIC) {
464 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
465 ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
466 ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
467 ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
468 ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
469 ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
470 ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
471 ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
472 ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
478 /* Check if it is for our own subnet */
480 if(subnet->owner == myself)
481 return; /* silently ignore */
483 /* Create neighbor advertation reply */
485 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
486 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
488 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
489 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
491 memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
493 ns->nd_ns_hdr.icmp6_cksum = 0;
494 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
495 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
496 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
497 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
498 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
499 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
501 /* Create pseudo header */
503 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
504 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
505 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
506 pseudo.next = htonl(IPPROTO_ICMPV6);
508 /* Generate checksum */
510 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
511 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
513 ns->nd_ns_hdr.icmp6_cksum = checksum;
515 write_packet(packet);
522 void route_arp(vpn_packet_t *packet)
524 struct ether_arp *arp;
530 /* First, snatch the source address from the ARP packet */
533 memcpy(mymac.x, packet->data + 6, 6);
535 /* This routine generates replies to ARP requests.
536 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
537 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
540 arp = (struct ether_arp *)(packet->data + 14);
542 /* Check if this is a valid ARP request */
544 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
545 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
546 if(debug_lvl > DEBUG_TRAFFIC) {
547 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
552 /* Check if the IPv4 address exists on the VPN */
554 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
557 if(debug_lvl >= DEBUG_TRAFFIC) {
558 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
559 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
566 /* Check if it is for our own subnet */
568 if(subnet->owner == myself)
569 return; /* silently ignore */
571 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
572 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
574 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
575 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
576 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
578 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
579 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
580 arp->arp_op = htons(ARPOP_REPLY);
582 write_packet(packet);
585 void route_outgoing(vpn_packet_t *packet)
592 /* FIXME: multicast? */
594 switch (routing_mode) {
596 type = ntohs(*((uint16_t *)(&packet->data[12])));
599 n = route_ipv4(packet);
603 #ifdef HAVE_NETINET_IP6_H
604 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
605 route_neighborsol(packet);
609 n = route_ipv6(packet);
617 if(debug_lvl >= DEBUG_TRAFFIC)
618 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
622 send_packet(n, packet);
626 n = route_mac(packet);
628 send_packet(n, packet);
630 broadcast_packet(myself, packet);
634 broadcast_packet(myself, packet);
639 void route_incoming(node_t *source, vpn_packet_t *packet)
641 switch (routing_mode) {
647 type = ntohs(*((uint16_t *)(&packet->data[12])));
650 n = route_ipv4(packet);
654 n = route_ipv6(packet);
665 memcpy(packet->data, mymac.x, 6);
666 write_packet(packet);
668 send_packet(n, packet);
677 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
680 if(subnet->owner == myself)
681 write_packet(packet);
683 send_packet(subnet->owner, packet);
685 broadcast_packet(source, packet);
686 write_packet(packet);
692 broadcast_packet(source, packet); /* Spread it on */
693 write_packet(packet);