diff --git a/network-ip.cabal b/network-ip.cabal
--- a/network-ip.cabal
+++ b/network-ip.cabal
@@ -1,5 +1,5 @@
 Name: network-ip
-Version: 0.1
+Version: 0.2
 Category: Network
 Stability: experimental
 Synopsis: Internet Protocol data structures
@@ -26,7 +26,7 @@
   Default-Language: Haskell2010
   Build-Depends:
     base         >= 4.3 && < 5,
-    data-default >= 0.2,
+    data-default-class,
     data-endian  >= 0.0.1,
     data-dword   >= 0.2,
     tagged       >= 0.2,
@@ -45,10 +45,9 @@
   Default-Language: Haskell2010
   Type: exitcode-stdio-1.0
   Build-Depends:
-    base                       >= 4 && < 5,
-    test-framework             >= 0.6,
-    test-framework-quickcheck2 >= 0.2,
-    QuickCheck                 >= 2.4,
+    base             >= 4 && < 5,
+    tasty            >= 0.4,
+    tasty-quickcheck >= 0.3,
     data-dword,
     text-printer,
     data-textual,
diff --git a/src/Network/IP/Addr.hs b/src/Network/IP/Addr.hs
--- a/src/Network/IP/Addr.hs
+++ b/src/Network/IP/Addr.hs
@@ -24,6 +24,10 @@
   , ip4FromOctets
   , ip4FromOctetList
   , anyIP4
+  , loopbackIP4
+  , broadcastIP4
+  , Range4(..)
+  , ip4Range
     -- ** IPv6 address
   , IP6(..)
   , anIP6
@@ -32,6 +36,9 @@
   , ip6FromWords
   , ip6FromWordList
   , anyIP6
+  , loopbackIP6
+  , Range6(..)
+  , ip6Range
     -- ** IP address
   , IP(..)
   , anIP
@@ -45,6 +52,8 @@
   , aNet4Addr
   , aNet6Addr
   , aNetAddrIP
+  , net4Addr
+  , net6Addr
   , printNetAddr
   , net4Parser
   , net6Parser
@@ -71,7 +80,7 @@
 import Data.DoubleWord (BinaryWord(..), DoubleWord(..), Word128)
 import Data.Ix (Ix)
 import Data.Endian
-import Data.Default
+import Data.Default.Class
 import Data.Hashable
 import Data.Binary (Binary)
 import qualified Data.Binary as B
@@ -183,6 +192,63 @@
   def = anyIP4
   {-# INLINE def #-}
 
+-- | IPv4 address @127.0.0.1@.
+loopbackIP4 ∷ IP4
+loopbackIP4 = IP4 0x7F000001
+{-# INLINE loopbackIP4 #-}
+
+-- | IPv4 address @255.255.255.255@.
+broadcastIP4 ∷ IP4
+broadcastIP4 = IP4 0xFFFFFFFF
+{-# INLINE broadcastIP4 #-}
+
+-- | IPv4 address range classification (per RFC6890).
+data Range4 = GeneralIP4       -- ^ General IPv4 address.
+            | ThisHostIP4      -- ^ This host on this network.
+            | PrivateUseIP4    -- ^ Private-Use networks.
+            | SharedSpaceIP4   -- ^ Shared address space.
+            | LoopbackIP4      -- ^ Loopback address.
+            | LinkLocalIP4     -- ^ Link local address.
+            | ReservedIP4      -- ^ Reserved address.
+            | DSLiteIP4        -- ^ Dual-Stack Lite.
+            | DocumentationIP4 -- ^ Reserved for documentation.
+            | IP6To4IP4        -- ^ 6to4.
+            | BenchmarkingIP4  -- ^ Benchmark testing.
+            | MulticastIP4     -- ^ Multicast address.
+            | FutureUseIP4     -- ^ Future use.
+            | BroadcastIP4     -- ^ Limited broadcast.
+            deriving (Typeable, Show, Read, Eq, Ord, Enum)
+
+-- | Determine the address range type.
+ip4Range ∷ IP4 → Range4
+ip4Range addr = case w1 of
+    0   → ThisHostIP4
+    10  → PrivateUseIP4
+    100 → if w2 .&. 0xC0 == 0x40 then SharedSpaceIP4 else GeneralIP4
+    127 → LoopbackIP4
+    169 → if w2 == 254 then LinkLocalIP4 else GeneralIP4
+    172 → if w2 .&. 0xF0 == 0x10 then PrivateUseIP4 else GeneralIP4
+    192 → case w2 of
+            0   → case w3 of
+                    0 → if w4 <= 7 then DSLiteIP4 else ReservedIP4
+                    2 → DocumentationIP4
+                    _ → GeneralIP4
+            88  → if w3 == 99 then IP6To4IP4 else GeneralIP4
+            168 → PrivateUseIP4
+            _   → GeneralIP4
+    198 → case w2 of
+            18  → BenchmarkingIP4
+            19  → BenchmarkingIP4
+            51  → if w3 == 100 then DocumentationIP4 else GeneralIP4
+            _   → GeneralIP4
+    203 → if w2 == 0 && w3 == 113 then DocumentationIP4 else GeneralIP4
+    _   | addr == broadcastIP4 → BroadcastIP4
+    _   → case w1 .&. 0xF0 of
+            224 → MulticastIP4
+            240 → FutureUseIP4
+            _   → GeneralIP4
+  where (w1, w2, w3, w4) = ip4ToOctets addr
+
 -- | IPv6 address.
 newtype IP6 = IP6 { unIP6 ∷ Word128 }
   deriving (Typeable, Eq, Ord, Bounded, Enum, Ix, Num, Bits, Hashable)
@@ -360,6 +426,60 @@
   def = anyIP6
   {-# INLINE def #-}
 
+-- | IPv6 address @::1@.
+loopbackIP6 ∷ IP6
+loopbackIP6 = IP6 1
+
+-- | IPv6 address range classification (per RFC6890).
+data Range6 = GeneralIP6       -- ^ General IPv6 address.
+            | AnyIP6           -- ^ Unspecified address.
+            | LoopbackIP6      -- ^ Loopback address.
+            | IP4MappedIP6     -- ^ Mapped IPv4 address.
+            | IP4EmbeddedIP6   -- ^ Embedded IPv4 address.
+            | DiscardIP6       -- ^ Discard address.
+            | ReservedIP6      -- ^ Reserved address.
+            | TeredoIP6        -- ^ Teredo address.
+            | BenchmarkingIP6  -- ^ Benchmark testing.
+            | DocumentationIP6 -- ^ Reserved for documentation.
+            | OrchidIP6        -- ^ ORCHID address.
+            | IP6To4IP6        -- ^ 6to4.
+            | UniqueLocalIP6   -- ^ Unique local address.
+            | LinkLocalIP6     -- ^ Link local address.
+            | MulticastIP6     -- ^ Multicast address.
+            deriving (Typeable, Show, Read, Eq, Ord, Enum)
+
+-- | Determine the address range type.
+ip6Range ∷ IP6 → Range6
+ip6Range (IP6 w) = case hi of
+    0 → case lo of
+          0 → AnyIP6
+          1 → LoopbackIP6
+          _ → GeneralIP6
+    0x000000000000FFFF → if q3 == 0 then IP4MappedIP6 else GeneralIP6
+    0x0064FF9B00000000 → if q3 == 0 then IP4EmbeddedIP6 else GeneralIP6
+    0x0100000000000000 → DiscardIP6
+    _                  → case w1 of
+      0x2001 → case w2 of
+                 0     → TeredoIP6
+                 2     → if w3 == 0 then BenchmarkingIP6 else GeneralIP6
+                 0xDB8 → DocumentationIP6
+                 _     | w2 .&. 0xFFF0 == 0x10 → OrchidIP6
+                       | w2 .&. 0xFE00 == 0    → ReservedIP6 
+                       | otherwise             → GeneralIP6
+      0x2002 → IP6To4IP6
+      _      | w1 .&. 0xFE00 == 0xFC00 → UniqueLocalIP6
+             | w1 .&. 0xFFC0 == 0xFE80 → LinkLocalIP6
+             | w1 >= 0xFF00            → MulticastIP6
+             | otherwise               → GeneralIP6
+  where hi = hiWord w
+        lo = loWord w
+        q1 = hiWord hi
+        q2 = loWord hi
+        q3 = hiWord lo
+        w1 = hiWord q1
+        w2 = loWord q1
+        w3 = hiWord q2
+
 -- IP address.
 data IP = IPv4 {-# UNPACK #-} !IP4
         | IPv6 {-# UNPACK #-} !IP6
@@ -406,6 +526,10 @@
   netAddr   ∷ NetHost n -- ^ Host address
             → Word8     -- ^ Network prefix length
             → n
+  -- | Test if the address is in the network.
+  inNetwork ∷ NetHost n -- ^ Host address
+            → n         -- ^ Network address
+            → Bool
 
 -- | Network address: host address + network mask length.
 data NetAddr a = NetAddr a {-# UNPACK #-} !Word8
@@ -519,6 +643,9 @@
   {-# INLINE netLength #-}
   netAddr a w = NetAddr a (w `min` 32)
   {-# INLINE netAddr #-}
+  inNetwork h (NetAddr a w) = h `shiftR` l == a `shiftR` l
+    where l = 32 - fromIntegral w
+  {-# INLINE inNetwork #-}
 
 instance IsNetAddr Net6Addr where
   type NetHost Net6Addr = IP6
@@ -537,6 +664,9 @@
   {-# INLINE netLength #-}
   netAddr a w = NetAddr a (w `min` 128)
   {-# INLINE netAddr #-}
+  inNetwork h (NetAddr a w) = h `shiftR` l == a `shiftR` l
+    where l = 128 - fromIntegral w
+  {-# INLINE inNetwork #-}
 
 instance IsNetAddr (NetAddr IP) where
   type NetHost (NetAddr IP) = IP
@@ -566,7 +696,20 @@
                 IPv4 _ → 32
                 IPv6 _ → 128
   {-# INLINABLE netAddr #-}
+  inNetwork (IPv4 h) (NetAddr (IPv4 a) w) = h `shiftR` l == a `shiftR` l
+    where l = 32 - fromIntegral w
+  inNetwork (IPv6 h) (NetAddr (IPv6 a) w) = h `shiftR` l == a `shiftR` l
+    where l = 128 - fromIntegral w
+  inNetwork _ _ = False
 
+net4Addr ∷ IP4 → Word8 → Net4Addr
+net4Addr = netAddr
+{-# INLINE net4Addr #-}
+
+net6Addr ∷ IP6 → Word8 → Net6Addr
+net6Addr = netAddr
+{-# INLINE net6Addr #-}
+
 -- | Print network address (CIDR notation).
 printNetAddr ∷ (IsNetAddr n, Printable (NetHost n), Printer p) ⇒ n → p
 printNetAddr n = print (netHost n) <> P.char7 '/' <> print (netLength n)
@@ -644,7 +787,7 @@
 type Inet6Addr = InetAddr IP6
 
 -- | 'InetAddr' proxy value.
-anInetAddr ∷ Proxy (InetAddr IP)
+anInetAddr ∷ Proxy InetAddr
 anInetAddr = Proxy
 
 -- | 'InetAddr' /a/ proxy value.
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE UnicodeSyntax #-}
+{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE TypeSynonymInstances #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 
-import Test.Framework (defaultMain, testGroup)
-import Test.Framework.Providers.QuickCheck2 (testProperty)
-import Test.QuickCheck
+import Test.Tasty (defaultMain, testGroup)
+import Test.Tasty.QuickCheck
 
 import Data.DoubleWord
 import Data.Textual
@@ -52,7 +52,7 @@
   arbitrary = InetAddr <$> arbitrary <*> arbitrary
   shrink n = uncurry InetAddr <$> shrink (inetHost n, inetPort n)
 
-main = defaultMain
+main = defaultMain $ testGroup "Tests"
          [ testGroup "IP4"
              [ testProperty "show -> read" $ \a →
                  read (show a) == (a ∷ IP4)
@@ -80,6 +80,101 @@
                  fromStringAs anIP4 "1.2.3.4.5" == Nothing
              , testProperty "parsing \"1a.2.3.4\" fails" $
                  fromStringAs anIP4 "1a.2.3.4" == Nothing
+             , testProperty "0.1.2.3 is in the 'This host' range" $
+                 ip4Range (ip4FromOctets 0 1 2 3) == ThisHostIP4
+             , testProperty "10.1.2.3 is in the 'Private-Use' range" $
+                 ip4Range (ip4FromOctets 10 1 2 3) == PrivateUseIP4
+             , testProperty "100.64.1.2 is in the 'Shared address space' range" $
+                 ip4Range (ip4FromOctets 100 64 1 2) == SharedSpaceIP4
+             , testProperty "100.97.1.2 is in the 'Shared address space' range" $
+                 ip4Range (ip4FromOctets 100 97 1 2) == SharedSpaceIP4
+             , testProperty "100.128.1.2 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 100 128 1 2) == GeneralIP4
+             , testProperty "127.0.0.1 is in the 'Loopback' range" $
+                 ip4Range loopbackIP4 == LoopbackIP4
+             , testProperty "169.254.0.1 is in the 'Link Local' range" $
+                 ip4Range (ip4FromOctets 169 254 0 1) == LinkLocalIP4
+             , testProperty "172.16.1.2 is in the 'Private-Use' range" $
+                 ip4Range (ip4FromOctets 172 16 1 2) == PrivateUseIP4
+             , testProperty "172.31.1.2 is in the 'Private-Use' range" $
+                 ip4Range (ip4FromOctets 172 31 1 2) == PrivateUseIP4
+             , testProperty "172.48.1.2 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 172 48 1 2) == GeneralIP4
+             , testProperty "192.0.0.7 is in the 'DS-Lite' range" $
+                 ip4Range (ip4FromOctets 192 0 0 7) == DSLiteIP4
+             , testProperty "192.0.0.8 is in the 'Reserved' range" $
+                 ip4Range (ip4FromOctets 192 0 0 8) == ReservedIP4
+             , testProperty "192.0.2.1 is in the 'Documentation' range" $
+                 ip4Range (ip4FromOctets 192 0 2 1) == DocumentationIP4
+             , testProperty "192.88.99.1 is in the '6to4' range" $
+                 ip4Range (ip4FromOctets 192 88 99 1) == IP6To4IP4
+             , testProperty "192.168.1.2 is in the 'Private-Use' range" $
+                 ip4Range (ip4FromOctets 192 168 1 2) == PrivateUseIP4
+             , testProperty "198.18.1.2 is in the 'Benchmarking' range" $
+                 ip4Range (ip4FromOctets 198 18 1 2) == BenchmarkingIP4
+             , testProperty "198.19.1.2 is in the 'Benchmarking' range" $
+                 ip4Range (ip4FromOctets 198 19 1 2) == BenchmarkingIP4
+             , testProperty "198.20.1.2 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 198 20 1 2) == GeneralIP4
+             , testProperty "198.51.100.1 is in the 'Documentation' range" $
+                 ip4Range (ip4FromOctets 198 51 100 1) == DocumentationIP4
+             , testProperty "198.51.101.1 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 198 51 101 1) == GeneralIP4
+             , testProperty "198.52.100.1 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 198 52 100 1) == GeneralIP4
+             , testProperty "203.0.113.1 is in the 'Documentation' range" $
+                 ip4Range (ip4FromOctets 203 0 113 1) == DocumentationIP4
+             , testProperty "203.0.114.1 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 203 0 114 1) == GeneralIP4
+             , testProperty "203.1.113.1 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 203 1 113 1) == GeneralIP4
+             , testProperty "224.1.2.3 is in the 'Multicast' range" $
+                 ip4Range (ip4FromOctets 224 1 2 3) == MulticastIP4
+             , testProperty "239.1.2.3 is in the 'Multicast' range" $
+                 ip4Range (ip4FromOctets 239 1 2 3) == MulticastIP4
+             , testProperty "223.1.2.3 is in the 'General' range" $
+                 ip4Range (ip4FromOctets 223 1 2 3) == GeneralIP4
+             , testProperty "240.1.2.3 is in the 'Future use' range" $
+                 ip4Range (ip4FromOctets 240 1 2 3) == FutureUseIP4
+             , testProperty "255.255.255.254 is in the 'Future use' range" $
+                 ip4Range (ip4FromOctets 255 255 255 254) == FutureUseIP4
+             , testProperty "255.255.255.255 is in the 'Broadcast' range" $
+                 ip4Range broadcastIP4 == BroadcastIP4
+             , testProperty "ip4Range" $ \a →
+                 let r = ip4Range a in
+                   if | inNetwork a (net4Addr anyIP4 8)
+                      → r == ThisHostIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 10 0 0 0) 8) ||
+                        inNetwork a (net4Addr (ip4FromOctets 172 16 0 0) 12) ||
+                        inNetwork a (net4Addr (ip4FromOctets 192 168 0 0) 16)
+                      → r == PrivateUseIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 100 64 0 0) 10)
+                      → r == SharedSpaceIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 127 0 0 0) 8)
+                      → r == LoopbackIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 169 254 0 0) 16)
+                      → r == LinkLocalIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 192 0 0 0) 24)
+                      → if inNetwork a (net4Addr (ip4FromOctets 192 0 0 0) 29)
+                        then r == DSLiteIP4
+                        else r == ReservedIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 192 0 2 0) 24) ||
+                        inNetwork a
+                          (net4Addr (ip4FromOctets 198 51 100 0) 24) ||
+                        inNetwork a (net4Addr (ip4FromOctets 203 0 113 0) 24)
+                      → r == DocumentationIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 192 88 99 0) 24)
+                      → r == IP6To4IP4
+                      | inNetwork a (net4Addr (ip4FromOctets 198 18 0 0) 15)
+                      → r == BenchmarkingIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 224 0 0 0) 4)
+                      → r == MulticastIP4
+                      | inNetwork a (net4Addr (ip4FromOctets 240 0 0 0) 4)
+                      → if a == broadcastIP4
+                        then r == BroadcastIP4
+                        else r == FutureUseIP4
+                      | otherwise
+                      → r == GeneralIP4
              ]
          , testGroup "IP6"
              [ testProperty "show -> read" $ \a →
@@ -133,6 +228,123 @@
                  fromStringAs anIP6 "1:2::3:4:5g" == Nothing
              , testProperty "parsing \"1:2:3:4:5:6:7:8g\" fails" $
                  fromStringAs anIP6 "1:2:3:4:5:6:7:8g" == Nothing
+             , testProperty ":: is in the 'Unspecified' range" $
+                 ip6Range (IP6 0) == AnyIP6
+             , testProperty "::1 is in the 'Loopback' range" $
+                 ip6Range (IP6 1) == LoopbackIP6
+             , testProperty "::ffff:0:0:102:304 is in the 'IPv4 mapped' range" $
+                 ip6Range (ip6FromWords 0 0 0 0xFFFF 0 0 0x102 0x304) ==
+                   IP4MappedIP6
+             , testProperty "64:ff9b::102:304 is in the 'IPv4 embedded' range" $
+                 ip6Range (ip6FromWords 0x64 0xFF9B 0 0 0 0 0x102 0x304) ==
+                   IP4EmbeddedIP6
+             , testProperty "100::1:2:3:4 is in the 'Discard' range" $
+                 ip6Range (ip6FromWords 0x100 0 0 0 1 2 3 4) == DiscardIP6
+             , testProperty "100::1:2:3:4:5 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0x100 0 0 1 2 3 4 5) == GeneralIP6
+             , testProperty "2001::ffff:1:2:3:4:5 is in the 'Teredo' range" $
+                 ip6Range (ip6FromWords 0x2001 0 0xFFFF 1 2 3 4 5) ==
+                   TeredoIP6
+             , testProperty "2001:2::0xFFFF:1:2:3:4 is in the 'Benchmarking' range" $
+                 ip6Range (ip6FromWords 0x2001 2 0 0xFFFF 1 2 3 4) ==
+                   BenchmarkingIP6
+             , testProperty "2001:2:1:2:3:4:5:6 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0x2001 2 1 2 3 4 5 6) == GeneralIP6
+             , testProperty "2001:db8:0xFFFF:1:2:3:4:5 is in the 'Documentation' range" $
+                 ip6Range (ip6FromWords 0x2001 0xDB8 0xFFFF 1 2 3 4 5) ==
+                   DocumentationIP6
+             , testProperty "2001:db9:1:2:3:4:5:6 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0x2001 0xDB9 1 2 3 4 5 6) ==
+                   GeneralIP6
+             , testProperty "2001:10:0xFFFF:1:2:3:4:5 is in the 'Orchid' range" $
+                 ip6Range (ip6FromWords 0x2001 0x10 0xFFFF 1 2 3 4 5) ==
+                   OrchidIP6
+             , testProperty "2001:18:1:2:3:4:5:6 is in the 'Orchid' range" $
+                 ip6Range (ip6FromWords 0x2001 0x18 1 2 3 4 5 6) ==
+                   OrchidIP6
+             , testProperty "2001:100:1:2:3:4:5:6 is in the 'Reserved' range" $
+                 ip6Range (ip6FromWords 0x2001 0x100 1 2 3 4 5 6) ==
+                   ReservedIP6
+             , testProperty "2001:200:1:2:3:4:5:6 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0x2001 0x200 1 2 3 4 5 6) ==
+                   GeneralIP6
+             , testProperty "2002::1:2:3:4:5:6 is in the '6to4' range" $
+                 ip6Range (ip6FromWords 0x2002 0 1 2 3 4 5 6) ==
+                   IP6To4IP6
+             , testProperty "2002:ffff:1:2:3:4:5:6 is in the '6to4' range" $
+                 ip6Range (ip6FromWords 0x2002 0xFFFF 1 2 3 4 5 6) ==
+                   IP6To4IP6
+             , testProperty "fc00::1:2:3:4:5:6 is in the 'Unique Local' range" $
+                 ip6Range (ip6FromWords 0xFC00 0 1 2 3 4 5 6) ==
+                   UniqueLocalIP6
+             , testProperty "fdff::1:2:3:4:5:6 is in the 'Unique Local' range" $
+                 ip6Range (ip6FromWords 0xFDFF 0 1 2 3 4 5 6) ==
+                   UniqueLocalIP6
+             , testProperty "fe00::1:2:3:4:5:6 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0xFE00 0 1 2 3 4 5 6) ==
+                   GeneralIP6
+             , testProperty "fe80::1:2:3:4:5:6 is in the 'Link Local' range" $
+                 ip6Range (ip6FromWords 0xFE80 0 1 2 3 4 5 6) ==
+                   LinkLocalIP6
+             , testProperty "febf::1:2:3:4:5:6 is in the 'Link Local' range" $
+                 ip6Range (ip6FromWords 0xFEBF 0 1 2 3 4 5 6) ==
+                   LinkLocalIP6
+             , testProperty "fec0::1:2:3:4:5:6 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0xFEC0 0 1 2 3 4 5 6) ==
+                   GeneralIP6
+             , testProperty "fe00::1:2:3:4:5:6 is in the 'General' range" $
+                 ip6Range (ip6FromWords 0xFE00 0 1 2 3 4 5 6) ==
+                   GeneralIP6
+             , testProperty "ff00::1:2:3:4:5:6 is in the 'Multicast' range" $
+                 ip6Range (ip6FromWords 0xFF00 0 1 2 3 4 5 6) ==
+                   MulticastIP6
+             , testProperty "ffff::1:2:3:4:5:6 is in the 'Multicast' range" $
+                 ip6Range (ip6FromWords 0xFFFF 0 1 2 3 4 5 6) ==
+                   MulticastIP6
+             , testProperty "ip6Range" $ \a →
+                 let r = ip6Range a in
+                   if | a == anyIP6
+                      → r == AnyIP6
+                      | a == loopbackIP6
+                      → r == LoopbackIP6 
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0 0 0 0xFFFF 0 0 0 0) 96)
+                      → r == IP4MappedIP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0x100 0 0 0 0 0 0 0) 64)
+                      → r == DiscardIP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0x64 0xFF9B 0 0 0 0 0 0) 96)
+                      → r == IP4EmbeddedIP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0x2001 0 0 0 0 0 0 0) 23)
+                      → if inNetwork a
+                             (net6Addr (ip6FromWords 0x2001 0 0 0 0 0 0 0) 32)
+                        then r == TeredoIP6
+                        else
+                          if inNetwork a
+                               (net6Addr
+                                  (ip6FromWords 0x2001 0x10 0 0 0 0 0 0) 28)
+                          then r == OrchidIP6
+                          else r == ReservedIP6
+                      | inNetwork a
+                          (net6Addr
+                             (ip6FromWords 0x2001 0xDB8 0 0 0 0 0 0) 32)
+                      → r == DocumentationIP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0x2002 0 0 0 0 0 0 0) 16)
+                      → r == IP6To4IP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0xFC00 0 0 0 0 0 0 0) 7)
+                      → r == UniqueLocalIP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0xFE80 0 0 0 0 0 0 0) 10)
+                      → r == LinkLocalIP6
+                      | inNetwork a
+                          (net6Addr (ip6FromWords 0xFF00 0 0 0 0 0 0 0) 8)
+                      → r == MulticastIP6
+                      | otherwise
+                      → r == GeneralIP6
              ]
          , testGroup "IP"
              [ testProperty "show -> read" $ \a →
