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.51 2003/06/11 19:40:43 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;
70 int overwrite_mac = 0;
71 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
75 uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
78 uint32_t checksum = prevsum ^ 0xFFFF;
86 checksum += *(unsigned char *)p;
89 checksum = (checksum & 0xFFFF) + (checksum >> 16);
95 static time_t lasttime = 0;
104 void learn_mac(mac_t *address)
112 subnet = lookup_subnet_mac(address);
114 /* If we don't know this MAC address yet, store it */
116 if(!subnet || subnet->owner != myself) {
117 if(debug_lvl >= DEBUG_TRAFFIC)
118 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
119 address->x[0], address->x[1], address->x[2], address->x[3],
120 address->x[4], address->x[5]);
122 subnet = new_subnet();
123 subnet->type = SUBNET_MAC;
124 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
125 subnet_add(myself, subnet);
127 /* And tell all other tinc daemons it's our MAC */
129 for(node = connection_tree->head; node; node = node->next) {
130 c = (connection_t *) node->data;
132 send_add_subnet(c, subnet);
136 subnet->net.mac.lastseen = now;
143 avl_node_t *node, *next, *node2;
147 for(node = myself->subnet_tree->head; node; node = next) {
149 s = (subnet_t *) node->data;
150 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
151 if(debug_lvl >= DEBUG_TRAFFIC)
152 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
153 s->net.mac.address.x[0], s->net.mac.address.x[1],
154 s->net.mac.address.x[2], s->net.mac.address.x[3],
155 s->net.mac.address.x[4], s->net.mac.address.x[5]);
157 for(node2 = connection_tree->head; node2; node2 = node2->next) {
158 c = (connection_t *) node2->data;
160 send_del_subnet(c, s);
163 subnet_del(myself, s);
168 node_t *route_mac(vpn_packet_t *packet)
174 /* Learn source address */
176 learn_mac((mac_t *)(&packet->data[6]));
178 /* Lookup destination address */
180 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
183 return subnet->owner;
190 void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
195 struct in_addr ip_src;
196 struct in_addr ip_dst;
204 hdr = (struct ip *)(packet->data + 14);
205 icmp = (struct icmp *)(packet->data + 14 + 20);
207 /* Remember original source and destination */
209 memcpy(&ip_src, &hdr->ip_src, 4);
210 memcpy(&ip_dst, &hdr->ip_dst, 4);
211 oldlen = packet->len - 14;
213 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(struct icmphdr))
214 oldlen = IP_MSS - sizeof(*hdr) - sizeof(struct icmphdr);
216 /* Copy first part of original contents to ICMP message */
218 memmove(&icmp->icmp_ip, hdr, oldlen);
220 /* Fill in IPv4 header */
223 hdr->ip_hl = sizeof(*hdr) / 4;
225 hdr->ip_len = htons(20 + 8 + oldlen);
229 hdr->ip_p = IPPROTO_ICMP;
231 memcpy(&hdr->ip_src, &ip_dst, 4);
232 memcpy(&hdr->ip_dst, &ip_src, 4);
234 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
236 /* Fill in ICMP header */
238 icmp->icmp_type = ICMP_DEST_UNREACH;
239 icmp->icmp_code = code;
240 icmp->icmp_cksum = 0;
242 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
244 packet->len = 14 + 20 + 8 + oldlen;
246 write_packet(packet);
249 node_t *route_ipv4(vpn_packet_t *packet)
255 if(priorityinheritance)
256 packet->priority = packet->data[15];
258 subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
261 if(debug_lvl >= DEBUG_TRAFFIC) {
262 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
263 packet->data[30], packet->data[31], packet->data[32],
267 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
271 if(!subnet->owner->status.reachable)
272 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
274 return subnet->owner;
279 void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
282 struct icmp6_hdr *icmp;
286 struct in6_addr ip6_src; /* source address */
287 struct in6_addr ip6_dst; /* destination address */
297 hdr = (struct ip6_hdr *)(packet->data + 14);
298 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
300 /* Remember original source and destination */
302 memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
303 memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
304 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
306 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
307 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
309 /* Copy first part of original contents to ICMP message */
311 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
313 /* Fill in IPv6 header */
315 hdr->ip6_flow = htonl(0x60000000UL);
316 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
317 hdr->ip6_nxt = IPPROTO_ICMPV6;
319 memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
320 memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
322 /* Fill in ICMP header */
324 icmp->icmp6_type = ICMP6_DST_UNREACH;
325 icmp->icmp6_code = code;
326 icmp->icmp6_cksum = 0;
328 /* Create pseudo header */
330 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
331 pseudo.next = htonl(IPPROTO_ICMPV6);
333 /* Generate checksum */
335 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
336 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
338 icmp->icmp6_cksum = checksum;
340 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
342 write_packet(packet);
345 node_t *route_ipv6(vpn_packet_t *packet)
351 subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
354 if(debug_lvl >= DEBUG_TRAFFIC) {
355 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
356 ntohs(*(uint16_t *) & packet->data[38]),
357 ntohs(*(uint16_t *) & packet->data[40]),
358 ntohs(*(uint16_t *) & packet->data[42]),
359 ntohs(*(uint16_t *) & packet->data[44]),
360 ntohs(*(uint16_t *) & packet->data[46]),
361 ntohs(*(uint16_t *) & packet->data[48]),
362 ntohs(*(uint16_t *) & packet->data[50]),
363 ntohs(*(uint16_t *) & packet->data[52]));
365 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
370 if(!subnet->owner->status.reachable)
371 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
373 return subnet->owner;
378 void route_neighborsol(vpn_packet_t *packet)
381 struct nd_neighbor_solicit *ns;
382 struct nd_opt_hdr *opt;
387 struct in6_addr ip6_src; /* source address */
388 struct in6_addr ip6_dst; /* destination address */
395 hdr = (struct ip6_hdr *)(packet->data + 14);
396 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
397 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
399 /* First, snatch the source address from the neighbor solicitation packet */
402 memcpy(mymac.x, packet->data + 6, 6);
404 /* Check if this is a valid neighbor solicitation request */
406 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
407 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
408 if(debug_lvl > DEBUG_TRAFFIC) {
409 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
414 /* Create pseudo header */
416 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
417 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
418 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
419 pseudo.next = htonl(IPPROTO_ICMPV6);
421 /* Generate checksum */
423 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
424 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
427 if(debug_lvl >= DEBUG_TRAFFIC)
428 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
432 /* Check if the IPv6 address exists on the VPN */
434 subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
437 if(debug_lvl >= DEBUG_TRAFFIC) {
438 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
439 ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
440 ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
441 ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
442 ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
443 ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
444 ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
445 ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
446 ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
452 /* Check if it is for our own subnet */
454 if(subnet->owner == myself)
455 return; /* silently ignore */
457 /* Create neighbor advertation reply */
459 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
460 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
462 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
463 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
465 memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
467 ns->nd_ns_hdr.icmp6_cksum = 0;
468 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
469 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
470 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
471 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
472 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
473 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
475 /* Create pseudo header */
477 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
478 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
479 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
480 pseudo.next = htonl(IPPROTO_ICMPV6);
482 /* Generate checksum */
484 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
485 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
487 ns->nd_ns_hdr.icmp6_cksum = checksum;
489 write_packet(packet);
494 void route_arp(vpn_packet_t *packet)
496 struct ether_arp *arp;
502 /* First, snatch the source address from the ARP packet */
505 memcpy(mymac.x, packet->data + 6, 6);
507 /* This routine generates replies to ARP requests.
508 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
509 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
512 arp = (struct ether_arp *)(packet->data + 14);
514 /* Check if this is a valid ARP request */
516 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
517 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
518 if(debug_lvl > DEBUG_TRAFFIC) {
519 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
524 /* Check if the IPv4 address exists on the VPN */
526 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
529 if(debug_lvl >= DEBUG_TRAFFIC) {
530 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
531 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
538 /* Check if it is for our own subnet */
540 if(subnet->owner == myself)
541 return; /* silently ignore */
543 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
544 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
546 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
547 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
548 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
550 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
551 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
552 arp->arp_op = htons(ARPOP_REPLY);
554 write_packet(packet);
557 void route_outgoing(vpn_packet_t *packet)
564 /* FIXME: multicast? */
566 switch (routing_mode) {
568 type = ntohs(*((uint16_t *)(&packet->data[12])));
571 n = route_ipv4(packet);
575 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
576 route_neighborsol(packet);
579 n = route_ipv6(packet);
587 if(debug_lvl >= DEBUG_TRAFFIC)
588 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
592 send_packet(n, packet);
596 n = route_mac(packet);
598 send_packet(n, packet);
600 broadcast_packet(myself, packet);
604 broadcast_packet(myself, packet);
609 void route_incoming(node_t *source, vpn_packet_t *packet)
611 switch (routing_mode) {
617 type = ntohs(*((uint16_t *)(&packet->data[12])));
620 n = route_ipv4(packet);
624 n = route_ipv6(packet);
635 memcpy(packet->data, mymac.x, 6);
636 write_packet(packet);
638 send_packet(n, packet);
647 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
650 if(subnet->owner == myself)
651 write_packet(packet);
653 send_packet(subnet->owner, packet);
655 broadcast_packet(source, packet);
656 write_packet(packet);
662 broadcast_packet(source, packet); /* Spread it on */
663 write_packet(packet);