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.43 2002/06/21 10:11:33 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/ip6.h>
40 #include <netinet/icmp6.h>
41 #include <netinet/if_ether.h>
46 #ifdef HAVE_INTTYPES_H
53 #include "connection.h"
61 #ifndef ETHER_ADDR_LEN
62 #define ETHER_ADDR_LEN 6
65 int routing_mode = RMODE_ROUTER;
66 int priorityinheritance = 0;
70 void learn_mac(mac_t *address)
76 subnet = lookup_subnet_mac(address);
78 /* If we don't know this MAC address yet, store it */
80 if(!subnet || subnet->owner!=myself)
82 if(debug_lvl >= DEBUG_TRAFFIC)
83 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
84 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
86 subnet = new_subnet();
87 subnet->type = SUBNET_MAC;
88 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
89 subnet_add(myself, subnet);
91 /* And tell all other tinc daemons it's our MAC */
93 for(node = connection_tree->head; node; node = node->next)
95 c = (connection_t *)node->data;
97 send_add_subnet(c, subnet);
101 subnet->net.mac.lastseen = now;
108 avl_node_t *node, *next, *node2;
110 for(node = myself->subnet_tree->head; node; node = next)
113 s = (subnet_t *)node->data;
114 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
116 if(debug_lvl >= DEBUG_TRAFFIC)
117 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
118 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]);
119 for(node2 = connection_tree->head; node2; node2 = node2->next)
121 c = (connection_t *)node2->data;
123 send_del_subnet(c, s);
125 subnet_del(myself, s);
131 node_t *route_mac(vpn_packet_t *packet)
135 /* Learn source address */
137 learn_mac((mac_t *)(&packet->data[6]));
139 /* Lookup destination address */
141 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
144 return subnet->owner;
149 node_t *route_ipv4(vpn_packet_t *packet)
153 if(priorityinheritance)
154 packet->priority = packet->data[15];
156 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
160 if(debug_lvl >= DEBUG_TRAFFIC)
162 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
163 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
169 return subnet->owner;
172 node_t *route_ipv6(vpn_packet_t *packet)
176 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
180 if(debug_lvl >= DEBUG_TRAFFIC)
182 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
183 ntohs(*(uint16_t *)&packet->data[38]),
184 ntohs(*(uint16_t *)&packet->data[40]),
185 ntohs(*(uint16_t *)&packet->data[42]),
186 ntohs(*(uint16_t *)&packet->data[44]),
187 ntohs(*(uint16_t *)&packet->data[46]),
188 ntohs(*(uint16_t *)&packet->data[48]),
189 ntohs(*(uint16_t *)&packet->data[50]),
190 ntohs(*(uint16_t *)&packet->data[52]));
196 return subnet->owner;
199 uint16_t inet_checksum(uint16_t *data, int len, uint16_t prevsum)
201 uint32_t checksum = prevsum ^ 0xFFFF;
204 checksum += ntohs(*data++);
206 while(checksum >> 16)
207 checksum = (checksum & 0xFFFF) + (checksum >> 16);
209 return checksum ^ 0xFFFF;
212 void route_neighborsol(vpn_packet_t *packet)
215 struct nd_neighbor_solicit *ns;
216 struct nd_opt_hdr *opt;
221 struct in6_addr ip6_src; /* source address */
222 struct in6_addr ip6_dst; /* destination address */
228 hdr = (struct ip6_hdr *)(packet->data + 14);
229 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
230 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
232 /* First, snatch the source address from the neighbor solicitation packet */
234 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
236 /* Check if this is a valid neighbor solicitation request */
238 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
239 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
241 if(debug_lvl > DEBUG_TRAFFIC)
243 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
248 /* Create pseudo header */
250 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
251 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
252 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
253 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
254 pseudo.junk[3] = IPPROTO_ICMPV6;
256 /* Generate checksum */
258 checksum = inet_checksum((uint16_t *)&pseudo, sizeof(pseudo)/2, ~0);
259 checksum = inet_checksum((uint16_t *)ns, sizeof(*ns)/2 + 4, checksum);
263 if(debug_lvl >= DEBUG_TRAFFIC)
264 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
268 /* Check if the IPv6 address exists on the VPN */
270 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
274 if(debug_lvl >= DEBUG_TRAFFIC)
276 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
277 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]),
278 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]));
284 /* Check if it is for our own subnet */
286 if(subnet->owner == myself)
287 return; /* silently ignore */
289 /* Create neighbor advertation reply */
291 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
292 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
294 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
295 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
297 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
299 ns->nd_ns_hdr.icmp6_cksum = 0;
300 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
301 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
302 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;
303 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
305 /* Create pseudo header */
307 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
308 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
309 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
310 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
311 pseudo.junk[3] = IPPROTO_ICMPV6;
313 /* Generate checksum */
315 checksum = inet_checksum((uint16_t *)&pseudo, sizeof(pseudo)/2, ~0);
316 checksum = inet_checksum((uint16_t *)ns, sizeof(*ns)/2 + 4, checksum);
318 ns->nd_ns_hdr.icmp6_cksum = htons(checksum);
320 write_packet(packet);
324 void route_arp(vpn_packet_t *packet)
326 struct ether_arp *arp;
330 /* First, snatch the source address from the ARP packet */
332 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
334 /* This routine generates replies to ARP requests.
335 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
336 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
339 arp = (struct ether_arp *)(packet->data + 14);
341 /* Check if this is a valid ARP request */
343 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
344 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
345 arp->arp_hln != ETHER_ADDR_LEN ||
347 ntohs(arp->arp_op) != ARPOP_REQUEST )
349 if(debug_lvl > DEBUG_TRAFFIC)
351 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
356 /* Check if the IPv4 address exists on the VPN */
358 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
362 if(debug_lvl >= DEBUG_TRAFFIC)
364 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
365 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
371 /* Check if it is for our own subnet */
373 if(subnet->owner == myself)
374 return; /* silently ignore */
376 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
377 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
379 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
380 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
381 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
383 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
384 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
385 arp->arp_op = htons(ARPOP_REPLY);
387 write_packet(packet);
391 void route_outgoing(vpn_packet_t *packet)
396 /* FIXME: multicast? */
401 type = ntohs(*((uint16_t *)(&packet->data[12])));
405 n = route_ipv4(packet);
408 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT)
410 route_neighborsol(packet);
413 n = route_ipv6(packet);
419 if(debug_lvl >= DEBUG_TRAFFIC)
421 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
426 send_packet(n, packet);
430 n = route_mac(packet);
432 send_packet(n, packet);
434 broadcast_packet(myself, packet);
438 broadcast_packet(myself, packet);
443 void route_incoming(node_t *source, vpn_packet_t *packet)
452 type = ntohs(*((uint16_t *)(&packet->data[12])));
456 n = route_ipv4(packet);
459 n = route_ipv6(packet);
470 memcpy(packet->data, mymac.net.mac.address.x, 6);
471 write_packet(packet);
474 send_packet(n, packet);
482 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
486 if(subnet->owner == myself)
487 write_packet(packet);
489 send_packet(subnet->owner, packet);
493 broadcast_packet(source, packet);
494 write_packet(packet);
499 broadcast_packet(source, packet); /* Spread it on */
500 write_packet(packet);