3 Copyright (C) 2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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.32 2002/03/12 14:25:04 guus Exp $
25 #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD)
32 #define ETHER_ADDR_LEN 6
34 #include <net/ethernet.h>
37 #include <netinet/ip6.h>
38 #include <netinet/icmp6.h>
40 #include <netinet/if_ether.h>
49 #include "connection.h"
57 int routing_mode = RMODE_ROUTER;
58 int priorityinheritance = 0;
62 void learn_mac(mac_t *address)
68 subnet = lookup_subnet_mac(address);
70 /* If we don't know this MAC address yet, store it */
72 if(!subnet || subnet->owner!=myself)
74 if(debug_lvl >= DEBUG_TRAFFIC)
75 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
76 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
78 subnet = new_subnet();
79 subnet->type = SUBNET_MAC;
80 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
81 subnet_add(myself, subnet);
83 /* And tell all other tinc daemons it's our MAC */
85 for(node = connection_tree->head; node; node = node->next)
87 c = (connection_t *)node->data;
89 send_add_subnet(c, subnet);
93 subnet->net.mac.lastseen = now;
100 avl_node_t *node, *next, *node2;
102 for(node = myself->subnet_tree->head; node; node = next)
105 s = (subnet_t *)node->data;
106 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
108 if(debug_lvl >= DEBUG_TRAFFIC)
109 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
110 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]);
111 for(node2 = connection_tree->head; node2; node2 = node2->next)
113 c = (connection_t *)node2->data;
115 send_del_subnet(c, s);
117 subnet_del(myself, s);
123 node_t *route_mac(vpn_packet_t *packet)
127 /* Learn source address */
129 learn_mac((mac_t *)(&packet->data[6]));
131 /* Lookup destination address */
133 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
136 return subnet->owner;
141 node_t *route_ipv4(vpn_packet_t *packet)
145 if(priorityinheritance)
146 packet->priority = packet->data[15];
148 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
152 if(debug_lvl >= DEBUG_TRAFFIC)
154 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
155 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
161 return subnet->owner;
164 node_t *route_ipv6(vpn_packet_t *packet)
168 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
172 if(debug_lvl >= DEBUG_TRAFFIC)
174 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
175 ntohs(*(short unsigned int *)&packet->data[38]),
176 ntohs(*(short unsigned int *)&packet->data[40]),
177 ntohs(*(short unsigned int *)&packet->data[42]),
178 ntohs(*(short unsigned int *)&packet->data[44]),
179 ntohs(*(short unsigned int *)&packet->data[46]),
180 ntohs(*(short unsigned int *)&packet->data[48]),
181 ntohs(*(short unsigned int *)&packet->data[50]),
182 ntohs(*(short unsigned int *)&packet->data[52]));
188 return subnet->owner;
192 unsigned short int ipv6_cksum(short int *data, int len, unsigned short int cksum)
196 cksum += ntohs(*data++);
201 void route_neighborsol(vpn_packet_t *packet)
204 struct nd_neighbor_solicit *ns;
205 struct nd_opt_hdr *opt;
210 struct in6_addr ip6_src; /* source address */
211 struct in6_addr ip6_dst; /* destination address */
217 hdr = (struct ip6_hdr *)(packet->data + 14);
218 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(struct ip6_hdr));
219 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(struct ip6_hdr) + sizeof(struct nd_neighbor_solicit));
221 /* First, snatch the source address from the neighbor solicitation packet */
223 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
225 /* Check if this is a valid neighbor solicitation request */
227 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
228 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
230 if(debug_lvl > DEBUG_TRAFFIC)
232 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
237 /* Check if the IPv6 address exists on the VPN */
239 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
243 if(debug_lvl >= DEBUG_TRAFFIC)
245 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
246 ntohs(ns->nd_ns_target.s6_addr16[0]), ntohs(ns->nd_ns_target.s6_addr16[1]), ntohs(ns->nd_ns_target.s6_addr16[2]), ntohs(ns->nd_ns_target.s6_addr16[3]),
247 ntohs(ns->nd_ns_target.s6_addr16[4]), ntohs(ns->nd_ns_target.s6_addr16[5]), ntohs(ns->nd_ns_target.s6_addr16[6]), ntohs(ns->nd_ns_target.s6_addr16[7]));
253 /* Check if it is for our own subnet */
255 if(subnet->owner == myself)
256 return; /* silently ignore */
259 syslog(LOG_DEBUG, "Neighbor solicitation request with checksum %hx", ntohs(ns->nd_ns_hdr.icmp6_cksum));
261 /* Create pseudo header */
263 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
264 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
265 pseudo.length = htonl(sizeof(*ns));
266 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
267 pseudo.junk[3] = IPPROTO_ICMPV6;
269 /* Generate checksum */
271 ns->nd_ns_hdr.icmp6_cksum = 0;
273 cksum = ipv6_cksum((short int *)&pseudo, sizeof(pseudo)/2, 0);
275 syslog(LOG_DEBUG, "Our checksum %hx", cksum);
277 cksum = ipv6_cksum((short int *)ns, sizeof(*ns)/2, cksum);
279 syslog(LOG_DEBUG, "Our checksum %hx", cksum);
281 cksum = ipv6_cksum((short int *)opt, sizeof(*opt)/2, cksum);
283 syslog(LOG_DEBUG, "Our checksum %hx", cksum);
285 /* Create neighbor advertation reply */
287 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
288 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
290 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
291 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
293 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
295 ns->nd_ns_hdr.icmp6_cksum = 0;
296 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
297 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
299 /* Create pseudo header */
301 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
302 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
303 pseudo.length = htonl(sizeof(struct icmp6_hdr));
304 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
305 pseudo.junk[3] = IPPROTO_ICMPV6;
307 /* Generate checksum */
309 cksum = ipv6_cksum((short int *)&pseudo, sizeof(pseudo)/2, 0);
310 cksum = ipv6_cksum((short int *)ns, sizeof(*ns)/2, cksum);
312 ns->nd_ns_hdr.icmp6_cksum = htons(cksum);
314 write_packet(packet);
319 void route_arp(vpn_packet_t *packet)
321 struct ether_arp *arp;
323 unsigned char ipbuf[4];
325 /* First, snatch the source address from the ARP packet */
327 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
329 /* This routine generates replies to ARP requests.
330 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
331 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
334 arp = (struct ether_arp *)(packet->data + 14);
336 /* Check if this is a valid ARP request */
338 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
339 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
340 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
341 (int) (arp->arp_pln) != 4 ||
342 ntohs(arp->arp_op) != ARPOP_REQUEST )
344 if(debug_lvl > DEBUG_TRAFFIC)
346 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
351 /* Check if the IPv4 address exists on the VPN */
353 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
357 if(debug_lvl >= DEBUG_TRAFFIC)
359 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
360 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
366 /* Check if it is for our own subnet */
368 if(subnet->owner == myself)
369 return; /* silently ignore */
371 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
372 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
374 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
375 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
376 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
378 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
379 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
380 arp->arp_op = htons(ARPOP_REPLY);
382 write_packet(packet);
386 void route_outgoing(vpn_packet_t *packet)
388 unsigned short int type;
391 /* FIXME: multicast? */
396 type = ntohs(*((unsigned short*)(&packet->data[12])));
400 n = route_ipv4(packet);
403 n = route_ipv6(packet);
405 if(!n && packet->data[0] == 0x33 && packet->data[1] == 0x33 && packet->data[2] == 0xff)
407 route_neighborsol(packet);
416 if(debug_lvl >= DEBUG_TRAFFIC)
418 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
423 send_packet(n, packet);
427 n = route_mac(packet);
429 send_packet(n, packet);
431 broadcast_packet(myself, packet);
435 broadcast_packet(myself, packet);
440 void route_incoming(node_t *source, vpn_packet_t *packet)
447 unsigned short int type;
449 type = ntohs(*((unsigned short*)(&packet->data[12])));
453 n = route_ipv4(packet);
456 n = route_ipv6(packet);
467 memcpy(packet->data, mymac.net.mac.address.x, 6);
468 write_packet(packet);
471 send_packet(n, packet);
479 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
483 if(subnet->owner == myself)
484 write_packet(packet);
486 send_packet(subnet->owner, packet);
490 broadcast_packet(source, packet);
491 write_packet(packet);
496 broadcast_packet(source, packet); /* Spread it on */
497 write_packet(packet);