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.49 2003/03/29 22:11:22 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 #include <netinet/ip6.h>
42 #include <netinet/icmp6.h>
43 #include <netinet/if_ether.h>
48 #ifdef HAVE_INTTYPES_H
55 #include "connection.h"
63 #ifndef ETHER_ADDR_LEN
64 #define ETHER_ADDR_LEN 6
67 int routing_mode = RMODE_ROUTER;
68 int priorityinheritance = 0;
74 uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
77 uint32_t checksum = prevsum ^ 0xFFFF;
85 checksum += *(unsigned char *)p;
88 checksum = (checksum & 0xFFFF) + (checksum >> 16);
94 static time_t lasttime = 0;
103 void learn_mac(mac_t *address)
111 subnet = lookup_subnet_mac(address);
113 /* If we don't know this MAC address yet, store it */
115 if(!subnet || subnet->owner != myself) {
116 if(debug_lvl >= DEBUG_TRAFFIC)
117 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
118 address->x[0], address->x[1], address->x[2], address->x[3],
119 address->x[4], address->x[5]);
121 subnet = new_subnet();
122 subnet->type = SUBNET_MAC;
123 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
124 subnet_add(myself, subnet);
126 /* And tell all other tinc daemons it's our MAC */
128 for(node = connection_tree->head; node; node = node->next) {
129 c = (connection_t *) node->data;
131 send_add_subnet(c, subnet);
135 subnet->net.mac.lastseen = now;
142 avl_node_t *node, *next, *node2;
146 for(node = myself->subnet_tree->head; node; node = next) {
148 s = (subnet_t *) node->data;
149 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
150 if(debug_lvl >= DEBUG_TRAFFIC)
151 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
152 s->net.mac.address.x[0], s->net.mac.address.x[1],
153 s->net.mac.address.x[2], s->net.mac.address.x[3],
154 s->net.mac.address.x[4], s->net.mac.address.x[5]);
156 for(node2 = connection_tree->head; node2; node2 = node2->next) {
157 c = (connection_t *) node2->data;
159 send_del_subnet(c, s);
162 subnet_del(myself, s);
167 node_t *route_mac(vpn_packet_t *packet)
173 /* Learn source address */
175 learn_mac((mac_t *)(&packet->data[6]));
177 /* Lookup destination address */
179 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
182 return subnet->owner;
189 void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
194 struct in_addr ip_src;
195 struct in_addr ip_dst;
203 hdr = (struct ip *)(packet->data + 14);
204 icmp = (struct icmp *)(packet->data + 14 + 20);
206 /* Remember original source and destination */
208 memcpy(&ip_src, &hdr->ip_src, 4);
209 memcpy(&ip_dst, &hdr->ip_dst, 4);
210 oldlen = packet->len - 14;
212 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(struct icmphdr))
213 oldlen = IP_MSS - sizeof(*hdr) - sizeof(struct icmphdr);
215 /* Copy first part of original contents to ICMP message */
217 memmove(&icmp->icmp_ip, hdr, oldlen);
219 /* Fill in IPv4 header */
222 hdr->ip_hl = sizeof(*hdr) / 4;
224 hdr->ip_len = htons(20 + 8 + oldlen);
228 hdr->ip_p = IPPROTO_ICMP;
230 memcpy(&hdr->ip_src, &ip_dst, 4);
231 memcpy(&hdr->ip_dst, &ip_src, 4);
233 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
235 /* Fill in ICMP header */
237 icmp->icmp_type = ICMP_DEST_UNREACH;
238 icmp->icmp_code = code;
239 icmp->icmp_cksum = 0;
241 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
243 packet->len = 14 + 20 + 8 + oldlen;
245 write_packet(packet);
248 node_t *route_ipv4(vpn_packet_t *packet)
254 if(priorityinheritance)
255 packet->priority = packet->data[15];
257 subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
260 if(debug_lvl >= DEBUG_TRAFFIC) {
261 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
262 packet->data[30], packet->data[31], packet->data[32],
266 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
270 if(!subnet->owner->status.reachable)
271 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
273 return subnet->owner;
278 void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
281 struct icmp6_hdr *icmp;
285 struct in6_addr ip6_src; /* source address */
286 struct in6_addr ip6_dst; /* destination address */
296 hdr = (struct ip6_hdr *)(packet->data + 14);
297 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
299 /* Remember original source and destination */
301 memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
302 memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
303 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
305 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
306 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
308 /* Copy first part of original contents to ICMP message */
310 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
312 /* Fill in IPv6 header */
314 hdr->ip6_flow = htonl(0x60000000UL);
315 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
316 hdr->ip6_nxt = IPPROTO_ICMPV6;
318 memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
319 memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
321 /* Fill in ICMP header */
323 icmp->icmp6_type = ICMP6_DST_UNREACH;
324 icmp->icmp6_code = code;
325 icmp->icmp6_cksum = 0;
327 /* Create pseudo header */
329 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
330 pseudo.next = htonl(IPPROTO_ICMPV6);
332 /* Generate checksum */
334 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
335 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
337 icmp->icmp6_cksum = checksum;
339 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
341 write_packet(packet);
344 node_t *route_ipv6(vpn_packet_t *packet)
350 subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
353 if(debug_lvl >= DEBUG_TRAFFIC) {
354 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
355 ntohs(*(uint16_t *) & packet->data[38]),
356 ntohs(*(uint16_t *) & packet->data[40]),
357 ntohs(*(uint16_t *) & packet->data[42]),
358 ntohs(*(uint16_t *) & packet->data[44]),
359 ntohs(*(uint16_t *) & packet->data[46]),
360 ntohs(*(uint16_t *) & packet->data[48]),
361 ntohs(*(uint16_t *) & packet->data[50]),
362 ntohs(*(uint16_t *) & packet->data[52]));
364 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
369 if(!subnet->owner->status.reachable)
370 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
372 return subnet->owner;
377 void route_neighborsol(vpn_packet_t *packet)
380 struct nd_neighbor_solicit *ns;
381 struct nd_opt_hdr *opt;
386 struct in6_addr ip6_src; /* source address */
387 struct in6_addr ip6_dst; /* destination address */
394 hdr = (struct ip6_hdr *)(packet->data + 14);
395 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
396 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
398 /* First, snatch the source address from the neighbor solicitation packet */
400 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
402 /* Check if this is a valid neighbor solicitation request */
404 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
405 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
406 if(debug_lvl > DEBUG_TRAFFIC) {
407 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
412 /* Create pseudo header */
414 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
415 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
416 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
417 pseudo.next = htonl(IPPROTO_ICMPV6);
419 /* Generate checksum */
421 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
422 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
425 if(debug_lvl >= DEBUG_TRAFFIC)
426 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
430 /* Check if the IPv6 address exists on the VPN */
432 subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
435 if(debug_lvl >= DEBUG_TRAFFIC) {
436 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
437 ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
438 ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
439 ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
440 ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
441 ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
442 ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
443 ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
444 ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
450 /* Check if it is for our own subnet */
452 if(subnet->owner == myself)
453 return; /* silently ignore */
455 /* Create neighbor advertation reply */
457 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
458 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
460 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
461 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
463 memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
465 ns->nd_ns_hdr.icmp6_cksum = 0;
466 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
467 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
468 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
469 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
470 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
471 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
473 /* Create pseudo header */
475 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
476 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
477 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
478 pseudo.next = htonl(IPPROTO_ICMPV6);
480 /* Generate checksum */
482 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
483 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
485 ns->nd_ns_hdr.icmp6_cksum = checksum;
487 write_packet(packet);
492 void route_arp(vpn_packet_t *packet)
494 struct ether_arp *arp;
500 /* First, snatch the source address from the ARP packet */
502 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
504 /* This routine generates replies to ARP requests.
505 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
506 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
509 arp = (struct ether_arp *)(packet->data + 14);
511 /* Check if this is a valid ARP request */
513 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
514 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
515 if(debug_lvl > DEBUG_TRAFFIC) {
516 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
521 /* Check if the IPv4 address exists on the VPN */
523 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
526 if(debug_lvl >= DEBUG_TRAFFIC) {
527 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
528 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
535 /* Check if it is for our own subnet */
537 if(subnet->owner == myself)
538 return; /* silently ignore */
540 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
541 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
543 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
544 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
545 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
547 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
548 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
549 arp->arp_op = htons(ARPOP_REPLY);
551 write_packet(packet);
554 void route_outgoing(vpn_packet_t *packet)
561 /* FIXME: multicast? */
563 switch (routing_mode) {
565 type = ntohs(*((uint16_t *)(&packet->data[12])));
568 n = route_ipv4(packet);
572 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
573 route_neighborsol(packet);
576 n = route_ipv6(packet);
584 if(debug_lvl >= DEBUG_TRAFFIC)
585 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
589 send_packet(n, packet);
593 n = route_mac(packet);
595 send_packet(n, packet);
597 broadcast_packet(myself, packet);
601 broadcast_packet(myself, packet);
606 void route_incoming(node_t *source, vpn_packet_t *packet)
608 switch (routing_mode) {
614 type = ntohs(*((uint16_t *)(&packet->data[12])));
617 n = route_ipv4(packet);
621 n = route_ipv6(packet);
631 memcpy(packet->data, mymac.net.mac.address.x, 6);
632 write_packet(packet);
634 send_packet(n, packet);
643 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
646 if(subnet->owner == myself)
647 write_packet(packet);
649 send_packet(subnet->owner, packet);
651 broadcast_packet(source, packet);
652 write_packet(packet);
658 broadcast_packet(source, packet); /* Spread it on */
659 write_packet(packet);