3 Copyright (C) 2000,2001 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000,2001 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.17 2001/07/20 20:25:10 guus Exp $
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
31 #include <netinet/if.h>
32 #define ETHER_ADDR_LEN 6
34 #include <net/ethernet.h>
36 #include <netinet/if_ether.h>
45 #include "connection.h"
52 int routing_mode = RMODE_ROUTER;
55 void learn_mac(mac_t *address)
61 subnet = lookup_subnet_mac(address);
63 /* If we don't know this MAC address yet, store it */
65 if(!subnet || subnet->owner!=myself)
67 if(debug_lvl >= DEBUG_TRAFFIC)
68 syslog(LOG_INFO, _("Learned new MAC address %hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
69 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
71 subnet = new_subnet();
72 subnet->type = SUBNET_MAC;
73 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
74 subnet_add(myself, subnet);
76 /* And tell all other tinc daemons it's our MAC */
78 for(node = connection_tree->head; node; node = node->next)
80 p = (connection_t *)node->data;
82 send_add_subnet(p, subnet);
87 connection_t *route_mac(vpn_packet_t *packet)
91 /* Learn source address */
93 learn_mac((mac_t *)(&packet->data[6]));
95 /* Lookup destination address */
97 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
100 return subnet->owner;
105 connection_t *route_ipv4(vpn_packet_t *packet)
110 dest = ntohl(*((unsigned long*)(&packet->data[30])));
112 subnet = lookup_subnet_ipv4(&dest);
116 if(debug_lvl >= DEBUG_TRAFFIC)
118 syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
119 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
125 return subnet->owner;
128 connection_t *route_ipv6(vpn_packet_t *packet)
131 if(debug_lvl > DEBUG_NOTHING)
133 syslog(LOG_WARNING, _("Cannot route packet: IPv6 routing not yet implemented"));
139 void route_arp(vpn_packet_t *packet)
141 struct ether_arp *arp;
143 unsigned char ipbuf[4];
146 /* First, snatch the source address from the ARP packet */
148 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
150 /* This routine generates replies to ARP requests.
151 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
152 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
155 arp = (struct ether_arp *)(packet->data + 14);
157 /* Check if this is a valid ARP request */
159 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
160 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
161 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
162 (int) (arp->arp_pln) != 4 ||
163 ntohs(arp->arp_op) != ARPOP_REQUEST )
165 if(debug_lvl > DEBUG_TRAFFIC)
167 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
172 /* Check if the IP address exists on the VPN */
174 dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
175 subnet = lookup_subnet_ipv4(&dest);
179 if(debug_lvl >= DEBUG_TRAFFIC)
181 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
182 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
188 /* Check if it is for our own subnet */
190 if(subnet->owner == myself)
191 return; /* silently ignore */
193 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
194 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
196 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
197 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
198 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
200 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
201 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
202 arp->arp_op = htons(ARPOP_REPLY);
204 accept_packet(packet);
208 void route_outgoing(vpn_packet_t *packet)
210 unsigned short int type;
213 /* FIXME: multicast? */
218 type = ntohs(*((unsigned short*)(&packet->data[12])));
222 cl = route_ipv4(packet);
225 cl = route_ipv6(packet);
231 if(debug_lvl >= DEBUG_TRAFFIC)
233 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
238 send_packet(cl, packet);
242 cl = route_mac(packet);
244 send_packet(cl, packet);
246 broadcast_packet(myself, packet);
250 broadcast_packet(myself, packet);
255 void route_incoming(connection_t *source, vpn_packet_t *packet)
260 memcpy(packet->data, mymac.net.mac.address.x, 6); /* Override destination address to make the kernel accept it */
261 accept_packet(packet);
267 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
271 if(subnet->owner == myself)
272 accept_packet(packet);
274 send_packet(subnet->owner, packet);
278 broadcast_packet(source, packet);
279 accept_packet(packet);
284 broadcast_packet(source,packet); /* Spread it on */
285 accept_packet(packet);