network-info-0.2.0.10/0000755000000000000000000000000013255656150012550 5ustar0000000000000000network-info-0.2.0.10/README.mkd0000644000000000000000000000073113255656150014203 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.10/Setup.hs0000644000000000000000000000005613255656150014205 0ustar0000000000000000import Distribution.Simple main = defaultMain network-info-0.2.0.10/LICENSE0000644000000000000000000000276413255656150013566 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.10/CHANGELOG.md0000644000000000000000000000024613255656150014363 0ustar0000000000000000## 0.2.0.10 (2018-03-??) * Fixed a link error that manifested when the C compiler uses C99 by default ([#17](https://github.com/jystic/network-info/issues/17)). network-info-0.2.0.10/network-info.cabal0000644000000000000000000000314113255656150016155 0ustar0000000000000000name: network-info version: 0.2.0.10 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 tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1 extra-source-files: cbits/common.h, cbits/common.inc, cbits/network.h, test/src/Main.hs, test/network-info-test.cabal, test/run-tests.bat, test/run-tests.sh, README.mkd, CHANGELOG.md source-repository head type: git location: git://github.com/jystic/network-info.git Library hs-source-dirs: src include-dirs: cbits cc-options: -Wall -std=c99 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.10/cbits/0000755000000000000000000000000013255656150013654 5ustar0000000000000000network-info-0.2.0.10/cbits/network-windows.c0000644000000000000000000000336613255656150017211 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; } #include "common.inc" network-info-0.2.0.10/cbits/common.h0000644000000000000000000000115313255656150015315 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.10/cbits/network.h0000644000000000000000000000046013255656150015516 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.10/cbits/common.inc0000644000000000000000000000061013255656150015634 0ustar0000000000000000/* See https://github.com/jystic/network-info/issues/17 */ extern inline void ipv4copy(ipv4 *dst, struct sockaddr *addr); extern inline void ipv6copy(ipv6 *dst, struct sockaddr *addr); extern inline int wcsempty(const wchar_t *str); extern inline void wszcopy(wchar_t *dst, const wchar_t *src, size_t dst_size); extern inline void mbswszcopy(wchar_t *dst, const char *src, size_t dst_size); network-info-0.2.0.10/cbits/network-unix.c0000644000000000000000000001025713255656150016477 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); } #include "common.inc" network-info-0.2.0.10/test/0000755000000000000000000000000013255656150013527 5ustar0000000000000000network-info-0.2.0.10/test/run-tests.bat0000644000000000000000000000014313255656150016161 0ustar0000000000000000@echo off cabal configure && cabal build && .\dist\build\network-info-test\network-info-test.exe network-info-0.2.0.10/test/run-tests.sh0000755000000000000000000000021413255656150016027 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.10/test/network-info-test.cabal0000644000000000000000000000103313255656150020107 0ustar0000000000000000name: network-info-test version: 0.1 build-type: Simple cabal-version: >= 1.6 tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1 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.10/test/src/0000755000000000000000000000000013255656150014316 5ustar0000000000000000network-info-0.2.0.10/test/src/Main.hs0000644000000000000000000000061513255656150015540 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" network-info-0.2.0.10/src/0000755000000000000000000000000013255656150013337 5ustar0000000000000000network-info-0.2.0.10/src/Network/0000755000000000000000000000000013255656150014770 5ustar0000000000000000network-info-0.2.0.10/src/Network/Info.hsc0000644000000000000000000001265713255656150016375 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