packages feed

network-info (empty) → 0.1

raw patch · 7 files changed

+435/−0 lines, 7 filesdep +basedep +network-infosetup-changed

Dependencies added: base, network-info

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2010, Jacob Stanley++All rights reserved.++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.++    * Neither the name of Jacob Stanley nor the names of other+      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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cbits/network-linux.c view
@@ -0,0 +1,79 @@+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <wchar.h>++#include <ifaddrs.h>+#include <netdb.h>+#include <netpacket/packet.h>++#include "network.h"+#include "common.h"+++void maccopy(unsigned char *dst, struct sockaddr *addr)+{+    /* TODO check that sll_halen is equal to 6 (MAC_SIZE) */+    memcpy(dst, ((struct sockaddr_ll *)addr)->sll_addr, MAC_SIZE);+}++struct network_interface *add_interface(struct network_interface *ns, const wchar_t *name, int max_ns)+{+    int i;+    for (i = 0; i < max_ns; i++) {+        if (wcsempty(ns[i].name)) {+            wszcopy(ns[i].name, name, NAME_SIZE);+            return &ns[i];+        } else if (wcscmp(ns[i].name, name) == 0) {+            return &ns[i];+        }+    }+    return NULL;+}++int count_interfaces(struct network_interface *ns, int max_ns)+{+    int i;+    for (i = 0; i < max_ns; i++) {+        if (wcsempty(ns[i].name)) {+            break;+        }+    }+    return i;+}++int c_get_network_interfaces(struct network_interface *ns, int max_ns)+{+    struct network_interface *n;+    struct ifaddrs *ifaddr, *ifa;+    struct sockaddr *addr;+    wchar_t name[NAME_SIZE];+    int family, error;+   +    error = getifaddrs(&ifaddr);+    if (error != 0) {+        perror("getifaddrs");+        return 0;+    }++    memset(ns, 0, sizeof(struct network_interface) * max_ns);++    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {+        mbswszcopy(name, ifa->ifa_name, NAME_SIZE);+        addr = ifa->ifa_addr;+        family = addr->sa_family;++        n = add_interface(ns, name, max_ns);++        if (family == AF_INET) {+            ipv4copy(&n->ip_address, addr);+        } else if (family == AF_INET6) {+            ipv6copy(&n->ip6_address, addr);+        } else if (family == AF_PACKET) {+            maccopy(n->mac_address, addr);+        }+    }++    freeifaddrs(ifaddr);+    return count_interfaces(ns, max_ns);+}
+ cbits/network-windows.c view
@@ -0,0 +1,67 @@+#define _WIN32_WINNT 0x0501++#include <stdio.h>++#include <winsock2.h>+#include <ws2tcpip.h>+#include <iptypes.h>+#include <iphlpapi.h>++#include "network.h"+#include "common.h"+++int get_adapters_addresses(IP_ADAPTER_ADDRESSES *adapters, ULONG *size)+{+    return GetAdaptersAddresses(AF_UNSPEC, 0, 0, adapters, size);+}++int c_get_network_interfaces(struct network_interface *ns, int max_ns)+{+    struct sockaddr *addr;+    IP_ADAPTER_ADDRESSES *adapters, *adapter;+    IP_ADAPTER_UNICAST_ADDRESS *unicast;+    ULONG buffer_size;+    DWORD error;+    int family, i;++    /* make an initial call to get the necessary+     * size into the buffer_size variable */+    error = get_adapters_addresses(NULL, &buffer_size);++    if (error != ERROR_BUFFER_OVERFLOW) {+        /* if we didn't get ERROR_BUFFER_OVERFLOW+         * then buffer_size was not set */+        return 0;+    }++    adapters = malloc(buffer_size);+    error = get_adapters_addresses(adapters, &buffer_size);+    i = 0;++    if (error == NO_ERROR) {+        adapter = adapters;++        while (i < max_ns && adapter) {+            wszcopy(ns[i].name, adapter->FriendlyName, NAME_SIZE);+            memcpy(ns[i].mac_address, adapter->PhysicalAddress, MAC_SIZE);++            for (unicast = adapter->FirstUnicastAddress; unicast; unicast = unicast->Next) {+                addr = unicast->Address.lpSockaddr;+                family = addr->sa_family;++                if (family == AF_INET) {+                    ipv4copy(&ns[i].ip_address, addr);+                } else if (family == AF_INET6) {+                    ipv6copy(&ns[i].ip6_address, addr);+                }+            }++            i++;+            adapter = adapter->Next;+        }+    }++    free(adapters);+    return i;+}
+ network-info.cabal view
@@ -0,0 +1,56 @@+Name:                network-info+version:             0.1+synopsis:            Access the local computer's basic network configuration+description:         This library provides simple read-only access to the local computer's+                     networking configuration. It is currently capable of getting a list of+                     all the network interfaces and their respective IPv4, IPv6 and MAC+                     addresses.+                     .+                     The executable 'test-network-info' will only be built if the flag 'test'+                     has been set.+homepage:            http://github.com/jystic/network-info+license:             BSD3+license-file:        LICENSE+author:              Jacob Stanley+maintainer:          jacob@stanley.io+category:            Network+build-type:          Simple+cabal-version:       >=1.8.0.4++source-repository head+  type:     git+  location: git://github.com/jystic/network-info.git++Flag test+  description: Build test program+  default:     False++Library+  hs-source-dirs: src+  include-dirs: cbits+  cc-options: -Wall -Werror++  exposed-modules: Network.Info+  +  build-depends:+    base == 4.*++  if os(linux)+    c-sources: cbits/network-linux.c+  else+    if os(windows)+      c-sources: cbits/network-windows.c+      extra-libraries: iphlpapi+    else+      buildable: False++Executable test-network-info+  hs-source-dirs: test+  main-is: Main.hs++  if flag(test)+    build-depends:+      base == 4.*,+      network-info+  else+    buildable: False
+ src/Network/Info.hsc view
@@ -0,0 +1,188 @@+{-# LANGUAGE ForeignFunctionInterface #-}++module Network.Info (+    getNetworkInterfaces,+    NetworkInterface (..),+    IPv4 (..),+    IPv6 (..),+    MAC (..),+) where++import Data.Bits ((.&.), shiftR, shiftL)+import Data.List (intersperse)+import Data.Word+import Foreign.C.String+import Foreign.C.Types+import Foreign.Marshal.Array+import Foreign.Ptr+import Foreign.Storable+import Numeric (showHex)+import Text.Printf+++----------------------------------------------------------------------+-- FFI+----------------------------------------------------------------------++#include "network.h"++foreign import ccall unsafe "c_get_network_interfaces"+        c_get_network_interfaces :: Ptr NetworkInterface -> CInt -> IO CInt++#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)+++----------------------------------------------------------------------+-- Network interfaces+----------------------------------------------------------------------++-- | Describes the basic configuration of a network interface. /This/+--   /definition is currently limited to just one address per family./+data NetworkInterface = NetworkInterface+    { name :: String -- ^ Interface name (e.g. \"eth0\", \"lo\", \"Local Area Connection\")+    , ipv4 :: IPv4   -- ^ IPv4 address+    , ipv6 :: IPv6   -- ^ IPv6 address+    , mac  :: MAC    -- ^ MAC address+    } deriving (Show)++instance Storable NetworkInterface where+    alignment _ = #alignment struct network_interface+    sizeOf _    = #size struct network_interface+    peek ptr    = do+        name <- peekCWString $ (#ptr struct network_interface, name) ptr+        ipv4 <- (#peek struct network_interface, ip_address) ptr+        ipv6 <- (#peek struct network_interface, ip6_address) ptr+        mac  <- (#peek struct network_interface, mac_address) ptr+        return $ NetworkInterface name ipv4 ipv6 mac+++-- | Gets the address information for each of the network interfaces on+--   the local computer.+getNetworkInterfaces :: IO [NetworkInterface]+getNetworkInterfaces =+    allocaArray 64 $ \ptr -> do+    count <- c_get_network_interfaces ptr 64+    peekArray (fromIntegral count) ptr+++----------------------------------------------------------------------+-- IPv4 addresses+----------------------------------------------------------------------++-- | Represents an IPv4 address (e.g. @172.23.21.1@, @127.0.0.1@)+data IPv4 = IPv4+    {-# UNPACK #-} !Word32+    deriving (Eq, Ord, Bounded)++instance Show IPv4 where+    show = showIPv4++instance Storable IPv4 where+    alignment _ = 1+    sizeOf _    = 4+    peek p      = do+        ip <- peek (castPtr p)+        return (IPv4 ip)+    poke p (IPv4 ip) =+        poke (castPtr p) ip+++----------------------------------------------------------------------+-- IPv6 addresses+----------------------------------------------------------------------++-- | Represents an IPv6 address (e.g. @2001:db8:85a3::8a2e:370:7334@, @::1@)+data IPv6 = IPv6+    {-# UNPACK #-} !Word32+    {-# UNPACK #-} !Word32+    {-# UNPACK #-} !Word32+    {-# UNPACK #-} !Word32+    deriving (Eq, Ord, Bounded)++-- | Not yet capable of collapsing groups of zeros, will still+--   generate valid addresses however.+instance Show IPv6 where+    show = showIPv6++instance Storable IPv6 where+    alignment _ = 1+    sizeOf _    = 16+    peek p      = do+        let ptr = castPtr p+        a <- peekElemOff ptr 0+        b <- peekElemOff ptr 1+        c <- peekElemOff ptr 2+        d <- peekElemOff ptr 3+        return $ IPv6 a b c d+    poke p (IPv6 a b c d) = do+        let ptr = castPtr p+        pokeElemOff ptr 0 a+        pokeElemOff ptr 1 b+        pokeElemOff ptr 2 c+        pokeElemOff ptr 3 d+++----------------------------------------------------------------------+-- MAC addresses+----------------------------------------------------------------------++-- | Represents a MAC address (e.g. @01:23:45:67:89:ab@)+data MAC = MAC+    {-# UNPACK #-} !Word8+    {-# UNPACK #-} !Word8+    {-# UNPACK #-} !Word8+    {-# UNPACK #-} !Word8+    {-# UNPACK #-} !Word8+    {-# UNPACK #-} !Word8+    deriving (Eq, Ord, Bounded)++instance Show MAC where+    show (MAC a b c d e f) = printf "%02x:%02x:%02x:%02x:%02x:%02x" a b c d e f++instance Storable MAC where+    alignment _ = 1+    sizeOf _    = 6+    peek p      = do+        a <- peek $ castPtr p+        b <- peekByteOff p 1+        c <- peekByteOff p 2+        d <- peekByteOff p 3+        e <- peekByteOff p 4+        f <- peekByteOff p 5+        return $ MAC a b c d e f+    poke p (MAC a b c d e f) = do+        poke (castPtr p) a+        pokeByteOff p 1 b+        pokeByteOff p 2 c+        pokeByteOff p 3 d+        pokeByteOff p 4 e+        pokeByteOff p 5 f+++----------------------------------------------------------------------+-- Helper functions+----------------------------------------------------------------------++showIPv4 :: IPv4 -> String+showIPv4 (IPv4 ip) = concat . intersperse "." $ showOctets+  where+    showOctets = map show $ word8s ip++-- TODO: drop out consecutive zeros+showIPv6 :: IPv6 -> String+showIPv6 (IPv6 a b c d) = (concat . intersperse ":") groups+  where+    groups = map (flip showHex "")  $ concatMap (group . word8s) [a,b,c,d]++word8s :: Word32 -> [Word8]+word8s x = [ fromIntegral $ x+           , fromIntegral $ x `shiftR` 8+           , fromIntegral $ x `shiftR` 16+           , fromIntegral $ x `shiftR` 24 ]++group :: [Word8] -> [Word16]+group = map2 $ \x y -> (fromIntegral x) `shiftL` 8 + (fromIntegral y)++map2 :: (a -> a -> b) -> [a] -> [b]+map2 _ [] = []+map2 f (x:y:zs) = f x y : map2 f zs
+ test/Main.hs view
@@ -0,0 +1,13 @@+module Main (main) where
+
+import Network.Info
+
+main = do
+    ns <- getNetworkInterfaces
+    mapM (putStrLn . showInterface) ns
+
+showInterface :: NetworkInterface -> String
+showInterface n = name n ++ "\n"
+               ++ "IPv4 Address: " ++ show (ipv4 n) ++ "\n"
+               ++ "IPv6 Address: " ++ show (ipv6 n) ++ "\n"
+               ++ "MAC Address:  " ++ show (mac n) ++ "\n"