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 +30/−0
- Setup.hs +2/−0
- cbits/network-linux.c +79/−0
- cbits/network-windows.c +67/−0
- network-info.cabal +56/−0
- src/Network/Info.hsc +188/−0
- test/Main.hs +13/−0
+ 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"