network-info-0.2.0.9/0000755000000000000000000000000013211645266012476 5ustar0000000000000000network-info-0.2.0.9/LICENSE0000644000000000000000000000276413211645266013514 0ustar0000000000000000Copyright (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. network-info-0.2.0.9/network-info.cabal0000644000000000000000000000277213211645266016114 0ustar0000000000000000name: network-info version: 0.2.0.9 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. . network-info has been tested and is known to work on Ubuntu 10.10, FreeBSD 9.0, Mac OS X 10.6.4 and Windows XP/7. It probably works on other flavours of Linux, OS X, FreeBSD and Windows as well. homepage: http://github.com/jystic/network-info license: BSD3 license-file: LICENSE author: Jacob Stanley maintainer: Jacob Stanley category: Network build-type: Simple cabal-version: >= 1.6 extra-source-files: cbits/common.h, cbits/network.h, test/src/Main.hs, test/network-info-test.cabal, test/run-tests.bat, test/run-tests.sh, README.mkd source-repository head type: git location: git://github.com/jystic/network-info.git Library hs-source-dirs: src include-dirs: cbits cc-options: -Wall exposed-modules: Network.Info build-depends: base == 4.* if os(windows) c-sources: cbits/network-windows.c extra-libraries: iphlpapi else c-sources: cbits/network-unix.c if os(solaris) extra-libraries: socket, nsl network-info-0.2.0.9/README.mkd0000644000000000000000000000073113211645266014131 0ustar0000000000000000network-info ============= 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. Compatibility -------------- network-info has been tested and is known to work on Ubuntu 10.10, Mac OS X 10.6.4, FreeBSD 9.0 and Windows XP/7. It probably works on other flavours of Linux, OS X, FreeBSD and Windows as well. network-info-0.2.0.9/Setup.hs0000644000000000000000000000005613211645266014133 0ustar0000000000000000import Distribution.Simple main = defaultMain network-info-0.2.0.9/cbits/0000755000000000000000000000000013211645266013602 5ustar0000000000000000network-info-0.2.0.9/cbits/common.h0000644000000000000000000000115313211645266015243 0ustar0000000000000000inline void ipv4copy(ipv4 *dst, struct sockaddr *addr) { *dst = ((struct sockaddr_in *)addr)->sin_addr.s_addr; } inline void ipv6copy(ipv6 *dst, struct sockaddr *addr) { memcpy(dst, ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, sizeof(ipv6)); } inline int wcsempty(const wchar_t *str) { return wcslen(str) == 0; } inline void wszcopy(wchar_t *dst, const wchar_t *src, size_t dst_size) { wcsncpy(dst, src, dst_size - 1); dst[dst_size - 1] = '\0'; } inline void mbswszcopy(wchar_t *dst, const char *src, size_t dst_size) { mbstowcs(dst, src, dst_size - 1); dst[dst_size - 1] = '\0'; } network-info-0.2.0.9/cbits/network-unix.c0000644000000000000000000001023013211645266016414 0ustar0000000000000000#include #include #include #include #include #include #include #ifdef __linux__ # include #else # include # include # ifndef __GNU__ # include # ifndef __sun # define AF_PACKET AF_LINK # endif # endif # if defined(__sun) || defined(__GNU__) # include # include # endif # ifdef __sun # include # include # endif #endif #ifdef __FreeBSD__ # include #endif #ifdef __DragonFly__ # include #endif #include "network.h" #include "common.h" #if defined(__sun) || (!defined(AF_PACKET) && defined(SIOCGARP)) int maccopy_arp(unsigned char *dst, struct sockaddr *addr) { // SOURCE DERIVED FROM: http://www.pauliesworld.org/project/getmac.c int sock; if ((sock=socket(AF_INET,SOCK_DGRAM,0)) > -1) { struct arpreq arpreq; memset(&arpreq, 0, sizeof (struct arpreq)); arpreq.arp_pa = *addr; if (ioctl(sock,SIOCGARP,(char*)&arpreq) == 0) { close (sock); memcpy(dst, (unsigned char *)arpreq.arp_ha.sa_data, MAC_SIZE); return 0; } else { close (sock); return 1; } } else { return 1; } } #endif #ifdef AF_PACKET void maccopy(unsigned char *dst, struct sockaddr *addr) { #ifdef __linux__ /* TODO check that sll_halen is equal to 6 (MAC_SIZE) */ memcpy(dst, ((struct sockaddr_ll *)addr)->sll_addr, MAC_SIZE); #else /* TODO check that sdl_alen is equal to 6 (MAC_SIZE) */ struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; memcpy(dst, sdl->sdl_data + sdl->sdl_nlen, MAC_SIZE); #endif } #endif 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) { /* TODO printing the error to stderr is not a very nice thing for * TODO a library to do, but i've never seen this happen and its * TODO probably better than failing silently. */ perror("getifaddrs"); return 0; } memset(ns, 0, sizeof(struct network_interface) * max_ns); for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { /* check we actually have an address in this item */ addr = ifa->ifa_addr; if (addr == NULL) continue; /* convert the interface name to wide characters */ mbswszcopy(name, ifa->ifa_name, NAME_SIZE); /* lookup or add a new interface with the given name */ n = add_interface(ns, name, max_ns); /* extract the address from this item */ family = addr->sa_family; if (family == AF_INET) { ipv4copy(&n->ip_address, addr); #if defined(__sun) || (!defined(AF_PACKET) && defined(SIOCGARP)) if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) { maccopy_arp(n->mac_address, addr); } #endif } else if (family == AF_INET6) { ipv6copy(&n->ip6_address, addr); #if defined(__sun) || (!defined(AF_PACKET) && defined(SIOCGARP)) if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) { maccopy_arp(n->mac_address, addr); } #endif #ifdef AF_PACKET } else if (family == AF_PACKET) { maccopy(n->mac_address, addr); #endif } } freeifaddrs(ifaddr); return count_interfaces(ns, max_ns); } network-info-0.2.0.9/cbits/network-windows.c0000644000000000000000000000333713211645266017135 0ustar0000000000000000#define _WIN32_WINNT 0x0501 #include #include #include #include #include #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-0.2.0.9/cbits/network.h0000644000000000000000000000046013211645266015444 0ustar0000000000000000#define NAME_SIZE (128+4) #define MAC_SIZE 6 typedef long ipv4; typedef long ipv6[4]; struct network_interface { wchar_t name[NAME_SIZE]; ipv4 ip_address; ipv6 ip6_address; unsigned char mac_address[MAC_SIZE]; }; int c_get_network_interfaces(struct network_interface *ns, int max_ns); network-info-0.2.0.9/src/0000755000000000000000000000000013211645266013265 5ustar0000000000000000network-info-0.2.0.9/src/Network/0000755000000000000000000000000013211645266014716 5ustar0000000000000000network-info-0.2.0.9/src/Network/Info.hsc0000644000000000000000000001265713211645266016323 0ustar0000000000000000{-# 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 ---------------------------------------------------------------------- -- 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 _ = #const offsetof(struct {char x__; struct network_interface (y__); }, y__) 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 network-info-0.2.0.9/test/0000755000000000000000000000000013211645266013455 5ustar0000000000000000network-info-0.2.0.9/test/network-info-test.cabal0000644000000000000000000000074213211645266020043 0ustar0000000000000000name: network-info-test version: 0.1 build-type: Simple cabal-version: >= 1.6 Executable network-info-test hs-source-dirs: ../src src include-dirs: ../cbits cc-options: -Wall -Werror main-is: Main.hs other-modules: Network.Info build-depends: base == 4.* if os(windows) c-sources: ../cbits/network-windows.c extra-libraries: iphlpapi else c-sources: ../cbits/network-unix.c if os(solaris) extra-libraries: socket, nsl network-info-0.2.0.9/test/run-tests.bat0000644000000000000000000000014313211645266016107 0ustar0000000000000000@echo off cabal configure && cabal build && .\dist\build\network-info-test\network-info-test.exe network-info-0.2.0.9/test/run-tests.sh0000755000000000000000000000021413211645266015755 0ustar0000000000000000#!/bin/bash TESTDIR="$(dirname -- "${0}")" cd $TESTDIR cabal configure && cabal build && ./dist/build/network-info-test/network-info-test network-info-0.2.0.9/test/src/0000755000000000000000000000000013211645266014244 5ustar0000000000000000network-info-0.2.0.9/test/src/Main.hs0000644000000000000000000000061513211645266015466 0ustar0000000000000000module 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"