packages feed

Scurry (empty) → 0.0.1

raw patch · 8 files changed

+1140/−0 lines, 8 filesdep +basedep +binarydep +bytestringsetup-changed

Dependencies added: base, binary, bytestring, containers, network, network-bytestring, parsec, random, stm, time, unix

Files

+ LICENSE view
@@ -0,0 +1,27 @@+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++Redistributions of source code must retain the above copyright+notice, this list of conditions and the following disclaimer.++Redistributions in binary form must reproduce the above copyright+notice, this list of conditions and the following disclaimer in the+documentation and/or other materials provided with the distribution.++The name of John Van Enk; nor the names of his contributors+may be used to endorse or promote products derived from this software+without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Scurry.cabal view
@@ -0,0 +1,72 @@+Name:          Scurry+Version:       0.0.1+Category:      Network+Description:   A distributed VPN system written in Haskell.+License:       BSD3+License-File:  LICENSE+Author:        John Van Enk+Maintainer:    vanenkj@gmail.com+Copyright:     John Van Enk, 2009++Synopsis:      A cross platform P2P VPN application built using Haskell.+Stability:     Experimental++Description:   P2P VPN implementation currently without any encryption.+               Supports Windows and Unix variants. Features include:+               .+               * Simple NAT Traversal using UDP (similar to STUN, not the same).+               .+               * Automatic address assignment to new peers+               .+               * Emulates a LAN between machines+               .+               Note: Scurry currently has no encryption layer or authentication+               mechanism at all. Also, the packet switching is currently+               implemented using Data.List.lookup as opposed to something+               more appropriate. This really isn't much of a problem until+               you hit hundreds or thousands of peers.+               .+               Requires a TAP-Win32 driver to run in Windows. Requires the tun+               module to be loaded to run in Linux (expects \/dev\/net\/tun).++Homepage:      http://code.google.com/p/scurry/++Cabal-Version: >= 1.2.0+Build-Type:    Simple++extra-source-files: src/C/help.h++executable scurry+    build-depends: base >= 3.0.0.0+    build-depends: binary >= 0.4.3.1+    build-depends: network >= 2.1.0.0+    build-depends: network-bytestring >= 0.1.1.2+    build-depends: bytestring >= 0.9.1.3+    build-depends: stm >= 2.1.1.0+    build-depends: parsec >= 3.0.0+    build-depends: containers+    build-depends: time >= 1.1.2.2+    build-depends: random >= 1.0.0.0++    if os(mingw32)+        c-sources:          src/C/help-win.c+        extra-libraries:    Iphlpapi, ws2_32+        cc-options:         -D MINGW32+        cpp-options:        -DCALLCONV=stdcall++    if os(linux)+        build-depends: unix >= 2.3.0.0+        c-sources:          src/C/help-linux.c+        cc-options:         -D LINUX+        cpp-options:        -DCALLCONV=ccall++    if os(darwin) || os(freebsd)+        build-depends: unix >= 2.3.0.0+        c-sources:          src/C/help-bsd.c+        cc-options:         -D BSD+        cpp-options:        -DCALLCONV=ccall+ +    hs-source-dirs:     src+    ghc-options:        -Wall -threaded+    main-is:            scurry.hs+    
+ Setup.hs view
@@ -0,0 +1,4 @@+module Main where++import Distribution.Simple+main = defaultMain
+ src/C/help-bsd.c view
@@ -0,0 +1,153 @@+#include <sys/ioctl.h>+#include <arpa/inet.h>+#include <errno.h>+#include <fcntl.h>+#include <sys/select.h>+#include <sys/socket.h>+#include <sys/stat.h>+#include <net/if.h>+#include <net/if_dl.h>+#include <net/route.h>+#include <netinet/in.h>+#include <stdarg.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <unistd.h>+#include <ifaddrs.h>++#include "help.h"+#include "tun_ioctls.h"++int get_mac(struct ifreq * ifr, int sock, struct tap_info * ti);++static int set_ip(struct ifreq * ifr, int sock, ip4_addr_t ip, ip4_addr_t mask);+static int set_mtu(struct ifreq * ifr, int sock, unsigned int mtu);++int open_tap(ip4_addr_t local_ip, ip4_addr_t local_mask, struct tap_info * ti)+{+    struct ifreq ifr_tap;+    int r = 0;++    int fd = -1;+    int sock = -1;++    if ((fd = open("/dev/tap0", O_RDWR)) < 0)+        return -1;++    memset(&ifr_tap, 0, sizeof(ifr_tap));++    /* setup tap */+    strncpy(ifr_tap.ifr_name, "tap0", IFNAMSIZ);+    +    /*+    if ((ioctl(fd, TUNSIFHEAD, (void *)&ifr_tap)) < 0)+        return -2;+    */+    +    /* setup ip */+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)+        return -3;++    if (set_ip(&ifr_tap, sock, local_ip, local_mask) < 0)+        return -4;++    if ( ioctl(sock, SIOCGIFFLAGS, &ifr_tap) < 0)+        return -6;++    if ( get_mac(&ifr_tap, sock, ti) < 0)+        return -7;++    ifr_tap.ifr_flags |= IFF_UP;+    ifr_tap.ifr_flags |= IFF_RUNNING;++    if (ioctl(sock, SIOCSIFFLAGS, &ifr_tap) < 0)+        return -8;++    if (set_mtu(&ifr_tap, sock, 1200) < 0)+        return -9;++    ti->desc->desc = fd;++    return fd;+}++static int set_ip(struct ifreq * ifr, int sock, ip4_addr_t ip, ip4_addr_t mask)+{+    /* Setting a single address of an interface is depreciated. Now uses ifaliasreq and it is done in one call */+    struct ifaliasreq ifa;+    struct sockaddr_in *in;+    +    memset(&ifa, 0, sizeof(ifa));+    strcpy(ifa.ifra_name, ifr->ifr_name);+    +    in = (struct sockaddr_in *) &ifa.ifra_addr;+	in->sin_family = AF_INET;+	in->sin_len = sizeof(ifa.ifra_addr);+	in->sin_addr.s_addr = ip;+	+	in = (struct sockaddr_in *) &ifa.ifra_mask;+	in->sin_family = AF_INET;+	in->sin_len = sizeof(ifa.ifra_mask);+	in->sin_addr.s_addr = mask;+    +    if ( ioctl(sock, SIOCSIFADDR, &ifa) < 0) {+        printf("SIOCAIFADDR: %s\n", strerror(errno));+        return -1;+    }++    return 0; +}++static int set_mtu(struct ifreq * ifr, int sock, unsigned int mtu)+{+    /* Set the MTU of the tap interface */+    ifr->ifr_mtu = mtu; +    if (ioctl(sock, SIOCSIFMTU, ifr) < 0)  {+        printf("SIOCSIFMTU: %s\n", strerror(errno));+        return -1;+    }++    return 0;+}++void close_tap(union tap_desc * td)+{+    if (0 <= td->desc) +    {+        close(td->desc);+    }+}++int get_mac(struct ifreq * ifr, int sock, struct tap_info * ti)+{+    struct ifaddrs *ifap;+        +    if (getifaddrs(&ifap) == 0) {+        struct ifaddrs *p;+        for (p = ifap; p; p = p->ifa_next) {+            if (p->ifa_addr->sa_family == AF_LINK && strncmp(((struct sockaddr_dl *) p->ifa_addr)->sdl_data, "tap", 3) == 0) {+            	struct sockaddr_dl *sdp = (struct sockaddr_dl *) p->ifa_addr;+            	memcpy(&(ti->mac), LLADDR(sdp), 6);+            	freeifaddrs(ifap);+                return 0;+            }+        }+        freeifaddrs(ifap);+    }++    printf("Unable to get MAC address.");+    return -1;    +}++int read_tap(union tap_desc * td, char * buf, int len)+{   +    int ret = read(td->desc,buf,len);+    return ret;+}++int write_tap(union tap_desc * td, const char * buf, int len)+{+    int ret = write(td->desc,buf,len);+    return ret;+}
+ src/C/help-linux.c view
@@ -0,0 +1,161 @@+#include <arpa/inet.h>+#include <errno.h>+#include <fcntl.h>+#include <linux/if.h>+#include <linux/if_tun.h>+#include <net/route.h>+#include <netinet/if_ether.h>+#include <netinet/in.h>+#include <netinet/ip.h>+#include <stdarg.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <sys/ioctl.h>+#include <sys/socket.h>+#include <sys/stat.h>+#include <unistd.h>++#include "help.h"++int open_tap(ip4_addr_t local_ip, ip4_addr_t local_mask, struct tap_info * ti);+int get_mac(struct ifreq * ifr, int sock, struct tap_info * ti);+void close_tap(union tap_desc * td);++static int set_ip(struct ifreq * ifr, int sock, ip4_addr_t ip4);+static int set_mask(struct ifreq * ifr, int sock, ip4_addr_t ip4);+static int set_mtu(struct ifreq * ifr, int sock, unsigned int mtu);+++int open_tap(ip4_addr_t local_ip, ip4_addr_t local_mask, struct tap_info * ti)+{+    struct ifreq ifr_tap;+    int r = 0;++    int fd = -1;+    int sock = -1;++    if ((fd = open("/dev/net/tun", O_RDWR)) < 0)+        return -1;++    memset(&ifr_tap, 0, sizeof(ifr_tap));++    /* setup tap */+    ifr_tap.ifr_flags = IFF_TAP | IFF_NO_PI;++    if ((ioctl(fd, TUNSETIFF, (void *)&ifr_tap)) < 0)+        return -2;+    +    /* setup ip */+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)+        return -3;++    if (set_ip(&ifr_tap, sock, local_ip) < 0)+        return -4;++    if (set_mask(&ifr_tap, sock, local_mask) < 0)+        return -5;++    if ( ioctl(sock, SIOCGIFFLAGS, &ifr_tap) < 0)+        return -6;++    if ( get_mac(&ifr_tap,sock,ti) < 0)+        return -7;++    ifr_tap.ifr_flags |= IFF_UP;+    ifr_tap.ifr_flags |= IFF_RUNNING;++    if (ioctl(sock, SIOCSIFFLAGS, &ifr_tap) < 0)+        return -8;++    if (set_mtu(&ifr_tap, sock, 1200) < 0)+        return -9;++    ti->desc->desc = fd;++    return fd;+}++static int set_ip(struct ifreq * ifr, int sock, ip4_addr_t ip4)+{+    struct sockaddr_in addr;++    /* set the IP of this end point of tunnel */+    memset( &addr, 0, sizeof(addr) );+    addr.sin_addr.s_addr = ip4; /*network byte order*/+    addr.sin_family = AF_INET;+    memcpy( &ifr->ifr_addr, &addr, sizeof(struct sockaddr) );++    if ( ioctl(sock, SIOCSIFADDR, ifr) < 0) {+        printf("SIOCSIFADDR: %s\n", strerror(errno));+        return -1;+    }++    return 0; +}++static int set_mask(struct ifreq * ifr, int sock, ip4_addr_t ip4)+{+    struct sockaddr_in addr;++    memset( &addr, 0, sizeof(addr) );+    addr.sin_addr.s_addr = ip4; /*network byte order*/+    addr.sin_family = AF_INET;+    memcpy( &ifr->ifr_addr, &addr, sizeof(struct sockaddr) );+    +    if ( ioctl(sock, SIOCSIFNETMASK, ifr) < 0) {+        printf("SIOCSIFNETMASK: %s\n", strerror(errno));+        return -1;+    }++    return 0;+}++static int set_mtu(struct ifreq * ifr, int sock, unsigned int mtu)+{+    /* Set the MTU of the tap interface */+    ifr->ifr_mtu = mtu; +    if (ioctl(sock, SIOCSIFMTU, ifr) < 0)  {+        printf("SIOCSIFMTU: %s\n", strerror(errno));+        return -1;+    }++    return 0;+}++void close_tap(union tap_desc * td)+{+    if (0 <= td->desc) +    {+        close(td->desc);+    }+}++int get_mac(struct ifreq * ifr, int sock, struct tap_info * ti)+{+    +    if ( ioctl(sock, SIOCGIFHWADDR, ifr) < 0) {+        printf("SIOCGIFHWADDR: %s\n", strerror(errno));+        return -1;+    }+    else+    {+        memcpy(&(ti->mac),&(ifr->ifr_hwaddr.sa_data),6);+    }+++    return 0;+}++/* I HATE WINDOWS IT SUCKS SO HARD AHHH!! */+int read_tap(union tap_desc * td, char * buf, int len)+{+    int ret = read(td->desc,buf,len);+    return ret;+}++int write_tap(union tap_desc * td, const char * buf, int len)+{+    int ret = write(td->desc,buf,len);+    return ret;+}
+ src/C/help-win.c view
@@ -0,0 +1,529 @@+/* NOTE: most of this code is a direct copy of the qemu tap code+*/++#include <stdio.h>+#include <wchar.h>+#define WIN32_LEAN_AND_MEAN+#include <windows.h>+#include <winioctl.h>+#include <ws2tcpip.h>+#include <iphlpapi.h>+#include <io.h>+#include <Fcntl.h>+#include <malloc.h>++//=============+// TAP IOCTLs+//=============++#define TAP_CONTROL_CODE(request,method) \+  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)++#define TAP_IOCTL_GET_MAC               TAP_CONTROL_CODE (1, METHOD_BUFFERED)+#define TAP_IOCTL_GET_VERSION           TAP_CONTROL_CODE (2, METHOD_BUFFERED)+#define TAP_IOCTL_GET_MTU               TAP_CONTROL_CODE (3, METHOD_BUFFERED)+#define TAP_IOCTL_GET_INFO              TAP_CONTROL_CODE (4, METHOD_BUFFERED)+#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)+#define TAP_IOCTL_SET_MEDIA_STATUS      TAP_CONTROL_CODE (6, METHOD_BUFFERED)+#define TAP_IOCTL_CONFIG_DHCP_MASQ      TAP_CONTROL_CODE (7, METHOD_BUFFERED)+#define TAP_IOCTL_GET_LOG_LINE          TAP_CONTROL_CODE (8, METHOD_BUFFERED)+#define TAP_IOCTL_CONFIG_DHCP_SET_OPT   TAP_CONTROL_CODE (9, METHOD_BUFFERED)++//=================+// Registry keys+//=================++#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"++#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"++//======================+// Filesystem prefixes+//======================++#define USERMODEDEVICEDIR "\\\\.\\Global\\"+#define TAPSUFFIX         ".tap"++#define TAP_COMPONENT_ID "tap0801"++//======================+// Compile time configuration+//======================++//#define DEBUG_TAP_WIN32 1++#define TUN_ASYNCHRONOUS_WRITES 1++#define TUN_BUFFER_SIZE 1560+#define TUN_MAX_BUFFER_COUNT 32+ ++#include "help.h"++static OVERLAPPED overlap_read, overlap_write;+++int open_tap(ip4_addr_t local_ip, ip4_addr_t local_mask, struct tap_info * ti);++static const IP_ADAPTER_INFO *+get_adapter (const IP_ADAPTER_INFO *ai, DWORD index)+{+  if (ai && index != (DWORD)~0)+    {+      const IP_ADAPTER_INFO *a;++      /* find index in the linked list */+      for (a = ai; a != NULL; a = a->Next)+	{+	  if (a->Index == index)+	    return a;+	}+    }+  return NULL;+}+++static void+delete_temp_addresses (DWORD index)+{+  ULONG size = 4096;+  DWORD status;+  IP_ADAPTER_INFO *adapters = (IP_ADAPTER_INFO *) malloc(size);+  if ((status = GetAdaptersInfo (adapters, &size)) != NO_ERROR)+	 return;+   +  const IP_ADAPTER_INFO *a = get_adapter(adapters, index);++  if (a)+  {+    const IP_ADDR_STRING *ip = &a->IpAddressList;+    while (ip)+    {+      +      const DWORD context = ip->Context;++      if ((status = DeleteIPAddress ((ULONG) context)) == NO_ERROR)+      {+        //msg (M_INFO, "Successfully deleted previously set dynamic IP/netmask: %s/%s",  ip->IpAddress.String,    ip->IpMask.String);+      }+      else+      {+        const char *empty = "0.0.0.0";+        if (strcmp (ip->IpAddress.String, empty)+         || strcmp (ip->IpMask.String, empty)) {}+          //msg (M_INFO, "NOTE: could not delete previously set dynamic IP/netmask: %s/%s (status=%u)", ip->IpAddress.String, ip->IpMask.String,         (unsigned int)status);+      }+      ip = ip->Next;+    }+  }+  free(adapters);+}++static int is_tap_win32_dev(const char *guid)+{+    HKEY netcard_key;+    LONG status;+    DWORD len;+    int i = 0;++    status = RegOpenKeyEx(+        HKEY_LOCAL_MACHINE,+        (LPCTSTR) ADAPTER_KEY,+        0,+        KEY_READ,+        (PHKEY)&netcard_key);++    if (status != ERROR_SUCCESS) {+        return FALSE;+    }++    for (;;) {+        char enum_name[256];+        char unit_string[256];+        HKEY unit_key;+        char component_id_string[] = "ComponentId";+        char component_id[256];+        char net_cfg_instance_id_string[] = "NetCfgInstanceId";+        char net_cfg_instance_id[256];+        DWORD data_type;++        len = sizeof (enum_name);+        status = RegEnumKeyEx(+            netcard_key,+            i,+            (LPTSTR) enum_name,+            &len,+            NULL,+            NULL,+            NULL,+            NULL);++        if (status == ERROR_NO_MORE_ITEMS)+            break;+        else if (status != ERROR_SUCCESS) {+            return FALSE;+        }++        snprintf (unit_string, sizeof(unit_string), "%s\\%s",+                  ADAPTER_KEY, enum_name);++        status = RegOpenKeyEx(+            HKEY_LOCAL_MACHINE,+            (LPCTSTR) unit_string,+            0,+            KEY_READ,+            &unit_key);++        if (status != ERROR_SUCCESS) {+            return FALSE;+        } else {+            len = sizeof (component_id);+            status = RegQueryValueEx(+                unit_key,+                (LPCTSTR) component_id_string,+                NULL,+                &data_type,+                component_id,+                &len);++            if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {+                len = sizeof (net_cfg_instance_id);+                status = RegQueryValueEx(+                    unit_key,+                    (LPCTSTR) net_cfg_instance_id_string,+                    NULL,+                    &data_type,+                    net_cfg_instance_id,+                    &len);++                if (status == ERROR_SUCCESS && data_type == REG_SZ) {+                    if (!strcmp (component_id, TAP_COMPONENT_ID) &&+                        !strcmp (net_cfg_instance_id, guid)) {+                        RegCloseKey (unit_key);+                        RegCloseKey (netcard_key);+                        return TRUE;+                    }+                }+            }+            RegCloseKey (unit_key);+        }+        ++i;+    }++    RegCloseKey (netcard_key);+    return FALSE;+}++static int get_device_guid(+    char *name,+    int name_size,+    char *actual_name,+    int actual_name_size)+{+    LONG status;+    HKEY control_net_key;+    DWORD len;+    int i = 0;+    int stop = 0;++    status = RegOpenKeyEx(+        HKEY_LOCAL_MACHINE,+        (LPCTSTR) NETWORK_CONNECTIONS_KEY,+        0,+        KEY_READ,+        &control_net_key);++    if (status != ERROR_SUCCESS) {+        return -1;+    }++    while (!stop)+    {+        char enum_name[256];+        char connection_string[256];+        HKEY connection_key;+        char name_data[256];+        DWORD name_type;+        const char name_string[] = "Name";++        len = sizeof (enum_name);+        status = RegEnumKeyEx(+            control_net_key,+            i,+            (LPTSTR) enum_name,+            &len,+            NULL,+            NULL,+            NULL,+            NULL);++        if (status == ERROR_NO_MORE_ITEMS)+            break;+        else if (status != ERROR_SUCCESS) {+            return -1;+        }++        snprintf(connection_string,+             sizeof(connection_string),+             "%s\\%s\\Connection",+             NETWORK_CONNECTIONS_KEY, enum_name);++        status = RegOpenKeyEx(+            HKEY_LOCAL_MACHINE,+            (LPCTSTR) connection_string,+            0,+            KEY_READ,+            &connection_key);++        if (status == ERROR_SUCCESS) {+            len = sizeof (name_data);+            status = RegQueryValueEx(+                connection_key,+                (LPTSTR) name_string,+                NULL,+                &name_type,+                name_data,+                &len);++            if (status != ERROR_SUCCESS || name_type != REG_SZ) {+                    return -1;+            }+            else {+                if (is_tap_win32_dev(enum_name)) {+                    snprintf(name, name_size, "%s", enum_name);+                    if (actual_name) {+                        if (strcmp(actual_name, "") != 0) {+                            if (strcmp(name_data, actual_name) != 0) {+                                RegCloseKey (connection_key);+                                ++i;+                                continue;+                            }+                        }+                        else {+                            snprintf(actual_name, actual_name_size, "%s", name_data);+                        }+                    }+                    stop = 1;+                }+            }++            RegCloseKey (connection_key);+        }+        ++i;+    }++    RegCloseKey (control_net_key);++    if (stop == 0)+        return -1;++    return 0;+}++static DWORD get_interface_index (const char *guid)+{+  ULONG index;+  DWORD status;+  wchar_t wbuf[256];+  snwprintf (wbuf, sizeof (wbuf), L"\\DEVICE\\TCPIP_%S", guid);+  wbuf [sizeof(wbuf) - 1] = 0;+  if ((status = GetAdapterIndex (wbuf, &index)) != NO_ERROR)+    return (DWORD)~0;+  else+    return index;+}++static int tap_win32_set_status(HANDLE handle, int status)+{+    unsigned long len = 0;++    return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,+                &status, sizeof (status),+                &status, sizeof (status), &len, NULL);+}++int open_tap(ip4_addr_t local_ip, ip4_addr_t local_mask, struct tap_info * ti)+{+    // #TODO this function needs some pretty heavy cleanup+    const char *prefered_name = NULL;+      +    DWORD err;+    char device_path[256];+    char device_guid[0x100];+    int rc;+    HANDLE handle;+    DWORD index;+    ULONG ipapi_context;+    ULONG ipapi_instance;+    BOOL bret;+    char name_buffer[0x100] = {0, };+    struct {+        unsigned long major;+        unsigned long minor;+        unsigned long debug;+    } version;+    DWORD len;++    if (prefered_name != NULL)+        snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name);++    rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));+    if (rc)+        return -1;+    index = get_interface_index(device_guid);++    snprintf (device_path, sizeof(device_path), "%s%s%s",+              USERMODEDEVICEDIR,+              device_guid,+              TAPSUFFIX);++    handle = CreateFile (+        (LPCTSTR) device_path,+        GENERIC_READ | GENERIC_WRITE,+        0,+        0,+        OPEN_EXISTING,+        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,+        0 );++    if (handle == INVALID_HANDLE_VALUE) {+        return -2;+    }++    bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,+                           &version, sizeof (version),+                           &version, sizeof (version), &len, NULL);++    if (bret == FALSE) {+        CloseHandle(handle);+        return -3;+    }+    +    if(!DeviceIoControl(handle, TAP_IOCTL_GET_MAC, ti->mac, 6, ti->mac, 6, &len, 0)) {+      return -4;+    }+    +    uint32_t ep[4];+    ep[0] = local_ip;+    ep[1] = local_mask;+    ep[2] = 0xFE00000A;+    ep[3] = 0x00FFFFFF;+    if (!DeviceIoControl (handle, TAP_IOCTL_CONFIG_DHCP_MASQ,+			    ep, sizeof (ep),+			    ep, sizeof (ep), &len, NULL))+      return -5;+    +    if (!tap_win32_set_status(handle, TRUE)) {+      return -6;+    }+    +    FlushIpNetTable(index);+    +    overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);+	  overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);+	  if (!overlap_read.hEvent || !overlap_write.hEvent) {+  		return -7;+  	}+    +    // delete_temp_addresses (index);+    +    // printf("%x\n", local_ip);+    // if ((err = AddIPAddress (local_ip,+                             // local_mask,+                             // index,+                             // &ipapi_context,+                             // &ipapi_instance)) != NO_ERROR)+    // {+      // printf("AddIPAddress failed! (%d)\n", err);++      // LPVOID lpMsgBuf;++      // if (5010 != err) {+        // if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |+                          // FORMAT_MESSAGE_FROM_SYSTEM |+                          // FORMAT_MESSAGE_IGNORE_INSERTS,+                          // NULL, err,+                          // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),+                          // (LPTSTR) & lpMsgBuf, 0, NULL)) {+              // printf("\tError: %s", lpMsgBuf);+              // LocalFree(lpMsgBuf);+        // }+        // return -5;+      // }+    // }+    // if (AddIPAddress (local_ip,+                      // local_mask,+                      // index,+                      // &ipapi_context,+                      // &ipapi_instance) != NO_ERROR)+      // return -7;+    +++    +    ti->desc->desc = handle;+    ti->desc->context = ipapi_context;+    +    return 0;+}+++void close_tap(union tap_desc * td)+{+  //DeleteIPAddress(td->context);+  CloseHandle(td->desc);+}+++/* Read a frame from a tap device. The buffer needs+ * to be at least as large as the MTU of the device. */+int read_tap(union tap_desc * td, char * buf, int len)+{+	DWORD read_size;+	+	ResetEvent(overlap_read.hEvent);+	if (ReadFile(td->desc, buf, len, &read_size, &overlap_read)) {+		return read_size;+	}+	switch (GetLastError()) {+	case ERROR_IO_PENDING:+		WaitForSingleObject(overlap_read.hEvent, INFINITE);+		GetOverlappedResult(td->desc, &overlap_read, &read_size, FALSE);+		return read_size;+		break;+	default:+		break;+	}+	+	return -1;+}++/* Write a frame to a tap device. The frame length+ * must be less than the MTU of the device. */+int write_tap(union tap_desc * td, const char * buf, int len)+{  +  DWORD write_size;+	+	ResetEvent(overlap_write.hEvent);+	if (WriteFile(td->desc,+		buf,+		len,+		&write_size,+		&overlap_write)) {+		return write_size;+	}+	switch (GetLastError()) {+	case ERROR_IO_PENDING:+		WaitForSingleObject(overlap_write.hEvent, INFINITE);+		GetOverlappedResult(td->desc, &overlap_write,+			&write_size, FALSE);+		return write_size;+		break;+	default:+		break;+	}+	+	return -1;+}++
+ src/C/help.h view
@@ -0,0 +1,57 @@+#ifndef __HELP_HASKELL_VPN__+#define __HELP_HASKELL_VPN__ __HELP_HASKELL_VPN__++#include <assert.h>++typedef uint32_t ip4_addr_t;++#define TAP_DESC_SIZE 32++/* A union that serves to be a common storage medium for+ * whatever the OS wants to use as a device descriptor+ * for the TAP device. In Linux, this is just a file + * descriptor. */+union tap_desc {+    char pad[TAP_DESC_SIZE];+#if defined(MINGW32)+    struct+    {+      HANDLE desc;+      unsigned long context;+    };+#elif defined(LINUX)+    int desc;+#elif defined(BSD)+    int desc;+#else+    #error "ERROR: This platform not supported."+#endif+};++/* A struct used to pass information about+ * a tap device around. */+struct tap_info {+    union tap_desc * desc;+    char mac[8]; /* Use 8, instead of 6, to force alignment */+};++/* Open a tap device. The file descriptor and the+ * MAC address are written to the tap_info struct.+ * On failure, a negative value is returned. */+int open_tap(ip4_addr_t local_ip,+             ip4_addr_t local_mask,+             struct tap_info * ti);++/* Close a tap device. */+void close_tap(union tap_desc * td);++/* Read a frame from a tap device. The buffer needs+ * to be at least as large as the MTU of the device. */+int read_tap(union tap_desc * td, char * buf, int len);++/* Write a frame to a tap device. The frame length+ * must be less than the MTU of the device. */+int write_tap(union tap_desc * td, const char * buf, int len);++#endif /* __HELP_HASKELL_VPN__ */+
+ src/scurry.hs view
@@ -0,0 +1,137 @@+module Main where++import System.Console.GetOpt+import System.Environment+import System.IO+import System.Exit++import Network.Socket (withSocketsDo)+import Network.BSD++import Scurry.Peer+import Scurry.Comm+-- import Scurry.Management.Config+-- import Scurry.Management.Tracker+import Scurry.State+import Scurry.Util(inet_addr)+import Scurry.Network+import Scurry.Types.Network+import Data.Word+import Data.Maybe++data ScurryOpts = ScurryOpts {+    vpnAddr  :: Maybe ScurryAddress,+    vpnMask  :: Maybe ScurryMask,+    bindAddr :: ScurryAddress,+    bindPort :: ScurryPort,+    peers    :: [EndPoint]+} deriving (Show)++data ScurryOpt = SOVAddr ScurryAddress+               | SOVMask ScurryMask+               | SOBAddr ScurryAddress+               | SOBPort ScurryPort+    deriving (Show)++defaultPort :: ScurryPort+defaultPort = ScurryPort 24999++readPort :: String -> ScurryPort+readPort [] = error "I need some numbers!"+readPort s = let w = read s :: Word16+             in (ScurryPort . fromIntegral) w++lookupName :: String -> IO EndPoint+lookupName ep = do+    let name = takeWhile (/=':') ep+        port = case drop 1 $ dropWhile (/=':') ep of+                    [] -> defaultPort+                    x  -> readPort x++    HostEntry { hostAddresses = as } <- getHostByName name++    return $ EndPoint (ScurryAddress (as !! 0)) port+          +parseScurryOpts :: [String] -> IO (Either String ScurryOpts)+parseScurryOpts args = let def_opt = ScurryOpts { vpnAddr = Nothing+                                                , vpnMask = Nothing+                                                , bindAddr = ScurryAddress 0+                                                , bindPort = ScurryPort 24999+                                                , peers = [] }+                           va_t = SOVAddr . fromJust . inet_addr+                           vm_t = SOVMask . fromJust . inet_addr+                           ba_t = SOBAddr . fromJust . inet_addr+                           bp_t = SOBPort . readPort+                           options = [ Option "a" ["vpn-addr"]  (ReqArg va_t "VPN_ADDRESS")  "The IP address to use for the VPN."+                                     , Option "m" ["vpn-mask"]  (ReqArg vm_t "VPN_NETMASK")  "The network mask the for the VPN."+                                     , Option "b" ["bind-addr"] (ReqArg ba_t "BIND_ADDRESS") "The network interface on which listen for connections."+                                     , Option "p" ["bind-port"] (ReqArg bp_t "BIND_PORT")    "The port on which to listen for connections." ]+                           (m,o,_) = getOpt RequireOrder options args -- ignore errors for now+                           u = Left (usageInfo "How to use scurry." options)+                           opt' = foldr rplcOpts def_opt m+                       in case args of+                               ["-h"]     -> return u+                               ["--help"] -> return u+                               _          -> do ps <- mapM lookupName o+                                                return $ Right (opt' { peers = ps })++    where rplcOpts (SOVAddr a) sos = sos { vpnAddr  = Just a }+          rplcOpts (SOVMask m) sos = sos { vpnMask  = Just m }+          rplcOpts (SOBAddr a) sos = sos { bindAddr = a }+          rplcOpts (SOBPort p) sos = sos { bindPort = p }++main :: IO ()+main = withSocketsDo $ do +    args <- getArgs++    opts_ <- parseScurryOpts args+    -- let (configPath:trackerPath:_) = args++    opts <- case opts_ of+                 (Left msg) -> putStrLn msg >> exitFailure+                 (Right p)  -> return p++    -- (Just config)  <- load_scurry_config_file configPath+    -- (Just tracker) <- load_tracker_file trackerPath++    -- let (Scurry (VpnConfig tapIp tapMask) (NetworkConfig mySockAddr)) = config+    --     trackerEndPoints = filter (/= mySockAddr) $ map tToS tracker++    let initState = ScurryState {+            scurryPeers = [],+            scurryEndPoint = EndPoint (bindAddr opts) (bindPort opts),+            scurryNetwork = ScurryNetwork {+                scurryMask = vpnMask opts+            },+            scurryMyRecord = PeerRecord {+                peerMAC = Nothing,+                peerEndPoint = EndPoint (ScurryAddress 0) (ScurryPort 0),+                peerVPNAddr = vpnAddr opts,+                peerLocalPort = bindPort opts -- (\(EndPoint _ p) -> p) mySockAddr+            }+        }+        tapNet = (vpnAddr opts, vpnMask opts)++    local <- prepEndPoint (scurryEndPoint initState) -- mySockAddr++    startCom tapNet local initState (peers opts)++    {-+    where+        tToS (ScurryPeer ip port) = EndPoint ip port +    -}+++{-+getAddress :: Socket -> [EndPoint] -> IO (ScurryAddress, ScurryMask)+getAddress sock (t:trackers) = do+    let msg = SAddrRequest+        cmd = sendToAddr sock msg+    +    putStrLn "Requesting address..."+    cmd t++    where+        delayRead = do+            threadDelay (sToMs 1.5)+-}