123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /*
- route.c -- routing
- Copyright (C) 2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
- 2000-2002 Guus Sliepen <guus@sliepen.warande.net>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: route.c,v 1.1.2.22 2002/02/10 21:57:54 guus Exp $
- */
- #include "config.h"
- #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
- #include <sys/param.h>
- #endif
- #include <sys/socket.h>
- #include <netinet/in.h>
- #if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD)
- #include <net/if.h>
- #define ETHER_ADDR_LEN 6
- #else
- #include <net/ethernet.h>
- #endif
- #include <netinet/if_ether.h>
- #include <utils.h>
- #include <xalloc.h>
- #include <syslog.h>
- #include <string.h>
- #include <avl_tree.h>
- #include "net.h"
- #include "connection.h"
- #include "subnet.h"
- #include "route.h"
- #include "protocol.h"
- #include "device.h"
- #include "system.h"
- int routing_mode = RMODE_ROUTER;
- subnet_t mymac;
- void learn_mac(mac_t *address)
- {
- subnet_t *subnet;
- avl_node_t *node;
- connection_t *c;
- cp
- subnet = lookup_subnet_mac(address);
- /* If we don't know this MAC address yet, store it */
-
- if(!subnet || subnet->owner!=myself)
- {
- if(debug_lvl >= DEBUG_TRAFFIC)
- syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
- address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
-
- subnet = new_subnet();
- subnet->type = SUBNET_MAC;
- memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
- subnet_add(myself, subnet);
- /* And tell all other tinc daemons it's our MAC */
-
- for(node = connection_tree->head; node; node = node->next)
- {
- c = (connection_t *)node->data;
- if(c->status.active)
- send_add_subnet(c, subnet);
- }
- }
- }
- node_t *route_mac(vpn_packet_t *packet)
- {
- subnet_t *subnet;
- cp
- /* Learn source address */
- learn_mac((mac_t *)(&packet->data[6]));
-
- /* Lookup destination address */
-
- subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
- if(subnet)
- return subnet->owner;
- else
- return NULL;
- }
- node_t *route_ipv4(vpn_packet_t *packet)
- {
- ipv4_t dest;
- subnet_t *subnet;
- cp
- #ifdef HAVE_SOLARIS
- /* The other form gives bus errors on a SparcStation 20. */
- dest = ((packet->data[30] * 0x100 + packet->data[31]) * 0x100 + packet->data[32]) * 0x100 + packet->data[33];
- #else
- dest = ntohl(*((unsigned long*)(&packet->data[30])));
- #endif
- cp
- subnet = lookup_subnet_ipv4(&dest);
- cp
- if(!subnet)
- {
- if(debug_lvl >= DEBUG_TRAFFIC)
- {
- syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
- packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
- }
- return NULL;
- }
- cp
- return subnet->owner;
- }
- node_t *route_ipv6(vpn_packet_t *packet)
- {
- subnet_t *subnet;
- cp
- subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
- cp
- if(!subnet)
- {
- if(debug_lvl >= DEBUG_TRAFFIC)
- {
- syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
- ntohs(*(short unsigned int *)&packet->data[38]),
- ntohs(*(short unsigned int *)&packet->data[40]),
- ntohs(*(short unsigned int *)&packet->data[42]),
- ntohs(*(short unsigned int *)&packet->data[44]),
- ntohs(*(short unsigned int *)&packet->data[46]),
- ntohs(*(short unsigned int *)&packet->data[48]),
- ntohs(*(short unsigned int *)&packet->data[50]),
- ntohs(*(short unsigned int *)&packet->data[52]));
- }
- return NULL;
- }
- cp
- return subnet->owner;
- }
- void route_arp(vpn_packet_t *packet)
- {
- struct ether_arp *arp;
- subnet_t *subnet;
- unsigned char ipbuf[4];
- ipv4_t dest;
- cp
- /* First, snatch the source address from the ARP packet */
- memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
- /* This routine generates replies to ARP requests.
- You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
- Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
- */
- arp = (struct ether_arp *)(packet->data + 14);
- /* Check if this is a valid ARP request */
- if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
- ntohs(arp->arp_pro) != ETHERTYPE_IP ||
- (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
- (int) (arp->arp_pln) != 4 ||
- ntohs(arp->arp_op) != ARPOP_REQUEST )
- {
- if(debug_lvl > DEBUG_TRAFFIC)
- {
- syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
- }
- return;
- }
- /* Check if the IP address exists on the VPN */
- dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
- subnet = lookup_subnet_ipv4(&dest);
- if(!subnet)
- {
- if(debug_lvl >= DEBUG_TRAFFIC)
- {
- syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
- arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
- }
- return;
- }
- /* Check if it is for our own subnet */
-
- if(subnet->owner == myself)
- return; /* silently ignore */
- memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
- packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
- memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
- memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
- memcpy(arp->arp_spa, ipbuf, 4); /* ... */
- memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
- memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
- arp->arp_op = htons(ARPOP_REPLY);
-
- write_packet(packet);
- cp
- }
- void route_outgoing(vpn_packet_t *packet)
- {
- unsigned short int type;
- node_t *n;
- cp
- /* FIXME: multicast? */
- switch(routing_mode)
- {
- case RMODE_ROUTER:
- type = ntohs(*((unsigned short*)(&packet->data[12])));
- switch(type)
- {
- case 0x0800:
- n = route_ipv4(packet);
- break;
- case 0x86DD:
- n = route_ipv6(packet);
- break;
- case 0x0806:
- route_arp(packet);
- return;
- default:
- if(debug_lvl >= DEBUG_TRAFFIC)
- {
- syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
- }
- return;
- }
- if(n)
- send_packet(n, packet);
- break;
-
- case RMODE_SWITCH:
- n = route_mac(packet);
- if(n)
- send_packet(n, packet);
- else
- broadcast_packet(myself, packet);
- break;
-
- case RMODE_HUB:
- broadcast_packet(myself, packet);
- break;
- }
- }
- void route_incoming(node_t *source, vpn_packet_t *packet)
- {
- switch(routing_mode)
- {
- case RMODE_ROUTER:
- memcpy(packet->data, mymac.net.mac.address.x, 6); /* Override destination address to make the kernel accept it */
- write_packet(packet);
- break;
- case RMODE_SWITCH:
- {
- subnet_t *subnet;
- subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
- if(subnet)
- {
- if(subnet->owner == myself)
- write_packet(packet);
- else
- send_packet(subnet->owner, packet);
- }
- else
- {
- broadcast_packet(source, packet);
- write_packet(packet);
- }
- }
- break;
- case RMODE_HUB:
- broadcast_packet(source, packet); /* Spread it on */
- write_packet(packet);
- break;
- }
- }
|