diff --git a/Network/DNS.hs b/Network/DNS.hs
--- a/Network/DNS.hs
+++ b/Network/DNS.hs
@@ -20,6 +20,10 @@
   --   you may need to use the 'lookup', 'lookupAuth', or 'lookupRaw'
   --   functions.
 
+  , module Network.DNS.Utils
+  -- | The "Network.DNS.Utils" module contains utility functions used
+  --   for processing DNS data.
+
   , module Network.DNS.Types
   -- | All of the types that the other modules use.
 
@@ -34,6 +38,7 @@
 
 import Network.DNS.Lookup
 import Network.DNS.Resolver
+import Network.DNS.Utils
 import Network.DNS.Types
 import Network.DNS.Decode
 import Network.DNS.Encode
diff --git a/Network/DNS/Lookup.hs b/Network/DNS/Lookup.hs
--- a/Network/DNS/Lookup.hs
+++ b/Network/DNS/Lookup.hs
@@ -112,11 +112,11 @@
 --
 --   Examples:
 --
---   >>> let hostname = Data.ByteString.Char8.pack "www.mew.org"
+--   >>> let hostname = Data.ByteString.Char8.pack "www.wide.ad.jp"
 --   >>>
 --   >>> rs <- makeResolvSeed defaultResolvConf
 --   >>> withResolver rs $ \resolver -> lookupAAAA resolver hostname
---   Right [2001:240:11e:c00:00:00:00:101]
+--   Right [2001:200:dff:fff1:216:3eff:fe4b:651c]
 --
 lookupAAAA :: Resolver -> Domain -> IO (Either DNSError [IPv6])
 lookupAAAA rlv dom = do
@@ -177,12 +177,12 @@
 --   Examples:
 --
 --   >>> import Data.List (sort)
---   >>> let hostname = Data.ByteString.Char8.pack "iij.ad.jp"
+--   >>> let hostname = Data.ByteString.Char8.pack "wide.ad.jp"
 --   >>>
 --   >>> rs <- makeResolvSeed defaultResolvConf
 --   >>> ips <- withResolver rs $ \resolver -> lookupAviaMX resolver hostname
 --   >>> fmap sort ips
---   Right [202.232.30.70,202.232.30.144]
+--   Right [133.138.10.34,203.178.136.49]
 --
 --   Since there is more than one result, it is necessary to sort the
 --   list in order to check for equality.
diff --git a/Network/DNS/Resolver.hs b/Network/DNS/Resolver.hs
--- a/Network/DNS/Resolver.hs
+++ b/Network/DNS/Resolver.hs
@@ -28,7 +28,7 @@
 import Network.DNS.Encode
 import Network.DNS.Internal
 import Network.Socket (HostName, Socket, SocketType(Datagram), sClose, socket, connect)
-import Network.Socket (AddrInfoFlag(..), AddrInfo(..), defaultHints, getAddrInfo)
+import Network.Socket (AddrInfoFlag(..), AddrInfo(..), SockAddr(..), PortNumber(..), defaultHints, getAddrInfo)
 import Prelude hiding (lookup)
 import System.Random (getStdRandom, randomR)
 import System.Timeout (timeout)
@@ -55,6 +55,7 @@
 --
 data FileOrNumericHost = RCFilePath FilePath -- ^ A path for \"resolv.conf\"
                        | RCHostName HostName -- ^ A numeric IP address
+                       | RCHostPort HostName PortNumber -- ^ A numeric IP address and port number
 
 -- | Type for resolver configuration. The easiest way to construct a
 --   @ResolvConf@ object is to modify the 'defaultResolvConf'.
@@ -129,14 +130,15 @@
                                  <*> pure (resolvBufsize conf)
   where
     addr = case resolvInfo conf of
-        RCHostName numhost -> makeAddrInfo numhost
-        RCFilePath file -> toAddr <$> readFile file >>= makeAddrInfo
+        RCHostName numhost -> makeAddrInfo numhost Nothing
+        RCHostPort numhost mport -> makeAddrInfo numhost $ Just mport
+        RCFilePath file -> toAddr <$> readFile file >>= \i -> makeAddrInfo i Nothing
     toAddr cs = let l:_ = filter ("nameserver" `isPrefixOf`) $ lines cs
                 in extract l
     extract = reverse . dropWhile isSpace . reverse . dropWhile isSpace . drop 11
 
-makeAddrInfo :: HostName -> IO AddrInfo
-makeAddrInfo addr = do
+makeAddrInfo :: HostName -> Maybe PortNumber -> IO AddrInfo
+makeAddrInfo addr mport = do
     proto <- getProtocolNumber "udp"
     let hints = defaultHints {
             addrFlags = [AI_ADDRCONFIG, AI_NUMERICHOST, AI_PASSIVE]
@@ -144,7 +146,11 @@
           , addrProtocol = proto
           }
     a:_ <- getAddrInfo (Just hints) (Just addr) (Just "domain")
-    return a
+    let connectPort = case addrAddress a of
+                        SockAddrInet pn ha -> SockAddrInet (maybe pn id mport) ha
+                        SockAddrInet6 pn fi ha sid -> SockAddrInet6 (maybe pn id mport) fi ha sid
+                        unix -> unix 
+    return $ a { addrAddress = connectPort }
 
 ----------------------------------------------------------------
 
diff --git a/Network/DNS/StateBinary.hs b/Network/DNS/StateBinary.hs
--- a/Network/DNS/StateBinary.hs
+++ b/Network/DNS/StateBinary.hs
@@ -7,7 +7,7 @@
 import Control.Monad.State (State, StateT)
 import qualified Control.Monad.State as ST
 import Control.Monad.Trans.Resource (ResourceT)
-import qualified Data.Attoparsec as A
+import qualified Data.Attoparsec.ByteString as A
 import qualified Data.Attoparsec.ByteString.Lazy as AL
 import qualified Data.Attoparsec.Types as T
 import Data.ByteString (ByteString)
diff --git a/Network/DNS/Utils.hs b/Network/DNS/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Network/DNS/Utils.hs
@@ -0,0 +1,137 @@
+-- | Miscellaneous utility functions for processing DNS data.
+--
+module Network.DNS.Utils (
+    normalize
+  , normalizeCase
+  , normalizeRoot
+  ) where
+
+import qualified Data.ByteString.Char8 as BS (
+    append
+  , last
+  , map
+  , null
+  , pack )
+import Data.Char ( toLower )
+
+import Network.DNS.Types ( Domain )
+
+
+-- | Perform both 'normalizeCase' and 'normalizeRoot' on the given
+--   'Domain'. When comparing DNS names taken from user input, this is
+--   often necessary to avoid unexpected results.
+--
+--   /Examples/:
+--
+--   >>> let domain1 = BS.pack "ExAmPlE.COM"
+--   >>> let domain2 = BS.pack "example.com."
+--   >>> domain1 == domain2
+--   False
+--   >>> normalize domain1 == normalize domain2
+--   True
+--
+--   The 'normalize' function should be idempotent:
+--
+--   >>> normalize (normalize domain1) == normalize domain1
+--   True
+--
+--   Ensure that we don't crash on the empty 'Domain':
+--
+--   >>> import qualified Data.ByteString.Char8 as BS ( empty )
+--   >>> normalize BS.empty
+--   "."
+--
+normalize :: Domain -> Domain
+normalize = normalizeCase . normalizeRoot
+
+
+-- | Normalize the case of the given DNS name for comparisons.
+--
+--   According to RFC #1035, \"For all parts of the DNS that are part
+--   of the official protocol, all comparisons between character
+--   strings (e.g., labels, domain names, etc.) are done in a
+--   case-insensitive manner.\" This function chooses to lowercase
+--   its argument, but that should be treated as an implementation
+--   detail if at all possible.
+--
+--   /Examples/:
+--
+--   >>> let domain1 = BS.pack "ExAmPlE.COM"
+--   >>> let domain2 = BS.pack "exAMPle.com"
+--   >>> domain1 == domain2
+--   False
+--   >>> normalizeCase domain1 == normalizeCase domain2
+--   True
+--
+--   The 'normalizeCase' function should be idempotent:
+--
+--   >>> normalizeCase (normalizeCase domain2) == normalizeCase domain2
+--   True
+--
+--   Ensure that we don't crash on the empty 'Domain':
+--
+--   >>> import qualified Data.ByteString.Char8 as BS ( empty )
+--   >>> normalizeCase BS.empty
+--   ""
+--
+normalizeCase :: Domain -> Domain
+normalizeCase = BS.map toLower
+
+
+-- | Normalize the given name by appending a trailing dot (the DNS
+--   root) if one does not already exist.
+--
+--   Warning: this does not produce an equivalent DNS name! However,
+--   users are often unaware of the effect that the absence of the
+--   root will have. In user interface design, it may therefore be
+--   wise to act as if the user supplied the trailing dot during
+--   comparisons.
+--
+--   Per RFC #1034,
+--
+--   \"Since a complete domain name ends with the root label, this leads
+--   to a printed form which ends in a dot. We use this property to
+--   distinguish between:
+--
+--   * a character string which represents a complete domain name
+--     (often called \'absolute\'). For example, \'poneria.ISI.EDU.\'
+--
+--   * a character string that represents the starting labels of a
+--     domain name which is incomplete, and should be completed by
+--     local software using knowledge of the local domain (often
+--     called \'relative\'). For example, \'poneria\' used in the
+--     ISI.EDU domain.
+--
+--   Relative names are either taken relative to a well known origin,
+--   or to a list of domains used as a search list. Relative names
+--   appear mostly at the user interface, where their interpretation
+--   varies from implementation to implementation, and in master
+--   files, where they are relative to a single origin domain name.\"
+--
+--   /Examples/:
+--
+--   >>> let domain1 = BS.pack "example.com"
+--   >>> let domain2 = BS.pack "example.com."
+--   >>> domain1 == domain2
+--   False
+--   >>> normalizeRoot domain1 == normalizeRoot domain2
+--   True
+--
+--   The 'normalizeRoot' function should be idempotent:
+--
+--   >>> normalizeRoot (normalizeRoot domain1) == normalizeRoot domain1
+--   True
+--
+--   Ensure that we don't crash on the empty 'Domain':
+--
+--   >>> import qualified Data.ByteString.Char8 as BS ( empty )
+--   >>> normalizeRoot BS.empty
+--   "."
+--
+normalizeRoot :: Domain -> Domain
+normalizeRoot d
+  | BS.null d = trailing_dot
+  | BS.last d == '.' = d
+  | otherwise = d `BS.append` trailing_dot
+    where
+      trailing_dot = BS.pack "."
diff --git a/dns.cabal b/dns.cabal
--- a/dns.cabal
+++ b/dns.cabal
@@ -1,5 +1,5 @@
 Name:                   dns
-Version:                1.3.0
+Version:                1.4.0
 Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
 Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
 License:                BSD3
@@ -18,6 +18,7 @@
   Exposed-Modules:      Network.DNS
                         Network.DNS.Lookup
                         Network.DNS.Resolver
+                        Network.DNS.Utils
                         Network.DNS.Types
                         Network.DNS.Encode
                         Network.DNS.Decode
