📄 vpn.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2008 Christian Grothoff (and other contributing authors) GNUnet 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, or (at your option) any later version. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file applications/vpn/vpn.c * @author Michael John Wensley * @author Christian Grothoff (code cleanup, breaking things) * @brief tunnel RFC 4193 in GNUnet * * * http://gnunet.wensley.org.uk/ * * Yes this will thoroughly break most of the coding guidelines :-/ at least the first release. * * We use IPv6 addresses because they provide a larger space, and are * not as likely to be in use by other applications such as NAT. * * We also follow the guidance in RFC4193 and use only the 40 bits * specified for the randomly generated publickey. This allows nodes * to connect subnets to the network. * * It also allows interoperation with other users of this space such * as anonymous internets. We use GNUnet to benefit from its key * infrastructure, though other users may well rip fdxx:: bits * directly from public keys, using the private key to GNUNET_RSA_sign * route announcements. * * CHANGELOG: * 20060110 Change ifconfig/route to ioctl's * 20060111 P2P packet includes length of the header. * 20060802 Logging for multiple clients * * TODO: * - consider using linked list for routing tables instead of arrays * - find a better solution for /var/lib/gnunet/gnunet.vpn, * at least do not hardwire the path * - can we split off TUN code into * individual files without keeping globals? * - use PeerIdentities instead of PublicKeys where * possible */#include "vpn.h"#include "cs.h"#include "p2p.h"#include "helper.h"/** * Identity service, to reset the core. */GNUNET_Identity_ServiceAPI *identity;GNUNET_Session_ServiceAPI *session;GNUNET_CoreAPIForPlugins *coreAPI;struct GNUNET_Mutex *lock;/* from bluetooth agent */tunnel_info *store1;int entries1;route_info *route_store;int route_entries;route_info *realised_store;int realised_entries;static int interval = 60;static struct GNUNET_ThreadHandle *tunThreadInfo;static struct GNUNET_GE_Context *ectx;static int capacity1; /** * Pipe to communicate with select thread * Used to tell it there is something to do... */static int signalingPipe[2];/** is thread to stop? */static int running;static int admin_fd;static int route_capacity;static int realised_capacity;/** * clear out the prototype routes table * called at start or when we know a peer changes its route table. */voidinit_router (){ int reqcapacity; route_info *reqstore; reqcapacity = sizeof (route_info); if (reqcapacity > route_capacity) { reqstore = GNUNET_realloc (route_store, reqcapacity); if (reqstore == NULL) return; /* not enough ram, cannot init! */ route_store = reqstore; route_capacity = reqcapacity; } route_entries = 1; route_store->hops = 0; /* us! */ route_store->tunnel = -1; /* n/a! */ route_store->owner = *(identity->getPublicPrivateKey ()); /* us! */}/** * clear out the actual route at startup only */static voidinit_realised (){ int reqcapacity; route_info *reqstore; reqcapacity = sizeof (route_info); if (reqcapacity > realised_capacity) { reqstore = GNUNET_realloc (realised_store, reqcapacity); if (reqstore == NULL) return; /* not enough ram, cannot init! */ realised_store = reqstore; realised_capacity = reqcapacity; } realised_entries = 1; realised_store->hops = 0; /* us! */ realised_store->tunnel = -1; /* n/a! */ realised_store->owner = *(identity->getPublicPrivateKey ()); /* us! */}/* adds a route to prototype route table, unless it has same GNUNET_RSA_PublicKey and tunnel as another entry */voidadd_route (GNUNET_RSA_PublicKey * them, int hops, int tunnel){ int i; route_info *rstore; int rcapacity; for (i = 0; i < route_entries; i++) { if (isEqualP (them, &(route_store + i)->owner)) { if ((route_store + i)->hops == 0) { /* we don't store alternative routes to ourselves, * as we already know how to route to ourself */ GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_BULK | GNUNET_GE_ADMIN, _("Not storing route to myself from peer %d\n"), tunnel); return; } if ((route_store + i)->tunnel == tunnel) { /* also, we only keep one route to a node per peer, * but store the lowest hop count that the peer is advertising for that node. */ (route_store + i)->hops = mini ((route_store + i)->hops, hops); GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_BULK | GNUNET_GE_ADMIN, _ ("Duplicate route to node from peer %d, choosing minimum hops"), tunnel); return; } } } route_entries++; rcapacity = route_entries * sizeof (route_info); if (rcapacity > route_capacity) { rstore = GNUNET_realloc (route_store, rcapacity); if (rstore == NULL) { route_entries--; return; /* not enough ram, we will have to drop this route. */ } route_capacity = rcapacity; route_store = rstore; } /* * we really should keep the route table in ascending hop count order... */ if (route_entries > 0) { i = route_entries - 1; /* i = insert location */ while ((i > 0) && ((route_store + (i - 1))->hops > hops)) { (route_store + i)->hops = (route_store + (i - 1))->hops; (route_store + i)->tunnel = (route_store + (i - 1))->hops; (route_store + i)->owner = (route_store + (i - 1))->owner; i--; } GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_BULK | GNUNET_GE_ADMIN, _ ("Inserting route from peer %d in route table at location %d\n"), tunnel, i); (route_store + i)->hops = hops; (route_store + i)->tunnel = tunnel; (route_store + i)->owner = *them; }}/** check that ethertype matches ip version for incoming packets from linux specific code */static intvalid_incoming (int len, struct tun_pi *tp, struct ip6_hdr *fp){ char info[100]; if (len > (65535 - sizeof (struct tun_pi))) { GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER, _("RFC4193 Frame length %d is too big for GNUnet!\n"), len); return GNUNET_NO; } if (len < sizeof (struct tun_pi)) { GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER, _("RFC4193 Frame length %d too small\n"), len); return GNUNET_NO; } if ((ntohs (tp->proto) == ETH_P_IP) && (((struct iphdr *) fp)->version == 4)) { return GNUNET_YES; } else if ((ntohs (tp->proto) == ETH_P_IPV6) && (((struct iphdr *) fp)->version == 6)) { ipinfo (info, fp); GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_BULK | GNUNET_GE_ADMIN, "-> GNUnet(%d) : %s\n", len - sizeof (struct tun_pi), info); return GNUNET_YES; } GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER, _("RFC4193 Ethertype %x and IP version %x do not match!\n"), ntohs (tp->proto), ((struct iphdr *) fp)->version); return GNUNET_NO;}static voidsetup_tunnel (int n, const GNUNET_PeerIdentity * them){ struct ifreq ifr; struct in6_ifreq ifr6; struct in6_rtmsg rt; int i, used, fd, id = 0; GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_DEVELOPER | GNUNET_GE_REQUEST, _("RFC4193 Going to try and make a tunnel in slot %d\n"), n); fd = open ("/dev/net/tun", O_RDWR); if (fd < 0) { GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER, _("Cannot open tunnel device because of %s"), strerror (fd)); GNUNET_GE_DIE_STRERROR (ectx, GNUNET_GE_FATAL | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "open"); } memset (&ifr, 0, sizeof (ifr)); /* IFF_TUN = IP Packets * IFF_TAP = Ethernet packets * * IFF_NO_PI = Do not provide packet information */ /* we know its going to be ipv6 cause the version tells us. * except that linux *assumes* it will be sent IPv4 frames * unless we configure IFF_PI.... hmmmm.... :-/ * lets see the tun linux module source * * this needs PI as type = htons(0x86DD) * ifr.ifr_flags = IFF_TUN | IFF_NO_PI; * We do need PI otherwise TUNTAP assumes it is receiving IPv4... */ ifr.ifr_flags = IFF_TUN; /* try various names until we find a free one */ do { used = 0; for (i = 0; i < entries1; i++) { if ((store1 + i)->id == id) { GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_DEVELOPER | GNUNET_GE_REQUEST, _ ("RFC4193 Create skips gnu%d as we are already using it\n"), id); id++; used = 1; } } if (used == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -