5
5
-- Copyright : (c) Michel Boucey 2011-2013
6
6
-- License : BSD-Style
7
7
-- Maintainer : michel.boucey@gmail.com
8
- -- Stability : provisional
9
8
--
10
9
-- Dealing with IPv6 address text representations, canonization and manipulations.
11
10
--
12
11
13
12
-- -----------------------------------------------------------------------------
14
13
15
14
module Text.IPv6Addr.Internal
16
- ( colon
17
- , doubleColon
18
- , fullSixteenBit
19
- , sixteenBit
20
- , ipv4Addr
21
- , expandTokens
15
+ ( expandTokens
22
16
, macAddr
23
17
, maybeIPv6AddrTokens
24
18
, ipv4AddrToIPv6AddrTokens
@@ -62,7 +56,7 @@ ipv6TokenToText (SixteenBit s) = s
62
56
ipv6TokenToText Colon = T. pack " :"
63
57
ipv6TokenToText DoubleColon = T. pack " ::"
64
58
-- "A single 16-bit 0000 field MUST be represented as 0" (RFC 5952, 4.1)
65
- ipv6TokenToText AllZeros = tok0
59
+ ipv6TokenToText AllZeros = tok0 --
66
60
ipv6TokenToText (IPv4Addr a) = a
67
61
68
62
-- | Returns 'True' if a list of 'IPv6AddrToken' constitutes a valid IPv6 Address.
@@ -79,28 +73,28 @@ isIPv6Addr tks =
79
73
firstValidToken tks &&
80
74
(case countIPv4Addr tks of
81
75
0 -> case lasttk of
82
- SixteenBit _ -> lenconst
83
- DoubleColon -> lenconst
84
- AllZeros -> lenconst
85
- _ -> False
76
+ SixteenBit _ -> lenconst
77
+ DoubleColon -> lenconst
78
+ AllZeros -> lenconst
79
+ _ -> False
86
80
1 -> case lasttk of
87
- IPv4Addr _ -> (lentks == 13 && cdctks == 0 ) || (lentks < 12 && cdctks == 1 )
88
- _ -> False
81
+ IPv4Addr _ -> (lentks == 13 && cdctks == 0 ) || (lentks < 12 && cdctks == 1 )
82
+ _ -> False
89
83
otherwise -> False ))
90
84
where diffNext [] = False
91
85
diffNext [_] = True
92
86
diffNext (t: ts) = do
93
87
let h = head ts
94
88
case t of
95
- SixteenBit _ -> case h of
96
- SixteenBit _ -> False
97
- AllZeros -> False
98
- _ -> diffNext ts
99
- AllZeros -> case h of
100
- SixteenBit _ -> False
101
- AllZeros -> False
102
- _ -> diffNext ts
103
- _ -> diffNext ts
89
+ SixteenBit _ -> case h of
90
+ SixteenBit _ -> False
91
+ AllZeros -> False
92
+ _ -> diffNext ts
93
+ AllZeros -> case h of
94
+ SixteenBit _ -> False
95
+ AllZeros -> False
96
+ _ -> diffNext ts
97
+ _ -> diffNext ts
104
98
firstValidToken l =
105
99
case head l of
106
100
SixteenBit _ -> True
@@ -111,41 +105,44 @@ isIPv6Addr tks =
111
105
tok1 = T. pack " 1"
112
106
113
107
countIPv4Addr = foldr oneMoreIPv4Addr 0
114
- where
115
- oneMoreIPv4Addr t c = case t of
116
- IPv4Addr _ -> c + 1
117
- otherwise -> c
108
+ where
109
+ oneMoreIPv4Addr t c = case t of
110
+ IPv4Addr _ -> c + 1
111
+ otherwise -> c
118
112
119
113
-- | This is the main function which returns 'Just' the list of a tokenized IPv6
120
114
-- address text representation validated against RFC 4291 and canonized
121
115
-- in conformation with RFC 5952, or 'Nothing'.
122
116
maybeTokIPv6Addr :: T. Text -> Maybe [IPv6AddrToken ]
123
117
maybeTokIPv6Addr t =
124
118
case maybeIPv6AddrTokens t of
125
- Just ltks -> if isIPv6Addr ltks
119
+ Just ltks -> if isIPv6Addr ltks
126
120
then Just $ (ipv4AddrReplacement . toDoubleColon . fromDoubleColon) ltks
127
121
else Nothing
128
- Nothing -> Nothing
129
- where ipv4AddrReplacement ltks =
130
- if ipv4AddrRewrite ltks
131
- then init ltks ++ ipv4AddrToIPv6AddrTokens (last ltks) else ltks
122
+ Nothing -> Nothing
123
+ where
124
+ ipv4AddrReplacement ltks =
125
+ if ipv4AddrRewrite ltks
126
+ then init ltks ++ ipv4AddrToIPv6AddrTokens (last ltks)
127
+ else ltks
132
128
133
129
-- | Returns 'Just' the list of tokenized pure IPv6 address, always rewriting an
134
130
-- embedded IPv4 address if present.
135
131
maybeTokPureIPv6Addr :: T. Text -> Maybe [IPv6AddrToken ]
136
- maybeTokPureIPv6Addr t =
137
- do ltks <- maybeIPv6AddrTokens t
138
- if isIPv6Addr ltks
139
- then Just $ (toDoubleColon . ipv4AddrReplacement . fromDoubleColon) ltks
140
- else Nothing
141
- where ipv4AddrReplacement ltks' = init ltks' ++ ipv4AddrToIPv6AddrTokens (last ltks')
132
+ maybeTokPureIPv6Addr t = do
133
+ ltks <- maybeIPv6AddrTokens t
134
+ if isIPv6Addr ltks
135
+ then Just $ (toDoubleColon . ipv4AddrReplacement . fromDoubleColon) ltks
136
+ else Nothing
137
+ where
138
+ ipv4AddrReplacement ltks' = init ltks' ++ ipv4AddrToIPv6AddrTokens (last ltks')
142
139
143
140
-- | Tokenize a 'Text' into 'Just' a list of 'IPv6AddrToken', or 'Nothing'.
144
141
maybeIPv6AddrTokens :: T. Text -> Maybe [IPv6AddrToken ]
145
142
maybeIPv6AddrTokens s =
146
143
case readText s of
147
- Done r l -> if r== T. empty then Just l else Nothing
148
- Fail {} -> Nothing
144
+ Done r l -> if r== T. empty then Just l else Nothing
145
+ Fail {} -> Nothing
149
146
where
150
147
readText s = feed (parse (many1 $ ipv4Addr <|> sixteenBit <|> doubleColon <|> colon) s) T. empty
151
148
@@ -194,9 +191,10 @@ ipv4AddrToIPv6AddrTokens t =
194
191
[ SixteenBit ((!!) m 0 `T.append` addZero ((!!) m 1 ))
195
192
, Colon
196
193
, SixteenBit ((!!) m 2 `T.append` addZero ((!!) m 3 ))]
197
- _ -> [t]
198
- where toHex a = map (\ x -> T. pack $ showHex (read (T. unpack x):: Int ) " " ) $ T. split (== ' .' ) a
199
- addZero d = if T. length d == 1 then tok0 `T.append` d else d
194
+ _ -> [t]
195
+ where
196
+ toHex a = map (\ x -> T. pack $ showHex (read (T. unpack x):: Int ) " " ) $ T. split (== ' .' ) a
197
+ addZero d = if T. length d == 1 then tok0 `T.append` d else d
200
198
201
199
expandTokens :: [IPv6AddrToken ] -> [IPv6AddrToken ]
202
200
expandTokens = map expandToken
@@ -206,19 +204,20 @@ expandTokens = map expandToken
206
204
207
205
fromDoubleColon :: [IPv6AddrToken ] -> [IPv6AddrToken ]
208
206
fromDoubleColon tks =
209
- if DoubleColon `notElem` tks then tks
210
- else do
211
- let s = splitAt (fromJust $ elemIndex DoubleColon tks) tks
212
- let fsts = fst s
213
- let snds = if not (null (snd s)) then tail (snd s) else []
214
- let fste = if null fsts then [] else fsts ++ [Colon ]
215
- let snde = if null snds then [] else Colon : snds
216
- fste ++ allZerosTokensReplacement(quantityOfAllZerosTokenToReplace tks) ++ snde
217
- where quantityOfAllZerosTokenToReplace x =
218
- ntks tks - foldl (\ c x -> if (x /= DoubleColon ) && (x /= Colon ) then c+ 1 else c) 0 x
219
- where
220
- ntks tks = if countIPv4Addr tks == 1 then 7 else 8
221
- allZerosTokensReplacement x = intersperse Colon (replicate x AllZeros )
207
+ if DoubleColon `notElem` tks
208
+ then tks
209
+ else do let s = splitAt (fromJust $ elemIndex DoubleColon tks) tks
210
+ let fsts = fst s
211
+ let snds = if not (null (snd s)) then tail (snd s) else []
212
+ let fste = if null fsts then [] else fsts ++ [Colon ]
213
+ let snde = if null snds then [] else Colon : snds
214
+ fste ++ allZerosTokensReplacement(quantityOfAllZerosTokenToReplace tks) ++ snde
215
+ where
216
+ allZerosTokensReplacement x = intersperse Colon (replicate x AllZeros )
217
+ quantityOfAllZerosTokenToReplace x =
218
+ ntks tks - foldl (\ c x -> if (x /= DoubleColon ) && (x /= Colon ) then c+ 1 else c) 0 x
219
+ where
220
+ ntks tks = if countIPv4Addr tks == 1 then 7 else 8
222
221
223
222
toDoubleColon :: [IPv6AddrToken ] -> [IPv6AddrToken ]
224
223
toDoubleColon tks =
@@ -235,14 +234,14 @@ toDoubleColon tks =
235
234
zerosRunToReplace t =
236
235
let l = longestLengthZerosRun t
237
236
in (firstLongestZerosRunIndex t l,l)
238
- where firstLongestZerosRunIndex x y = sum . snd . unzip $ Prelude. takeWhile ( /= ( True ,y)) x
239
- longestLengthZerosRun x =
240
- maximum $ map longest x
241
- where longest t = case t of
242
- ( True ,i) -> i
243
- _ -> 0
244
- zerosRunsList x =
245
- map helper $ groupZerosRuns x
237
+ where
238
+ firstLongestZerosRunIndex x y = sum . snd . unzip $ Prelude. takeWhile ( /= ( True ,y)) x
239
+ longestLengthZerosRun x =
240
+ maximum $ map longest x
241
+ where longest t = case t of
242
+ ( True ,i) -> i
243
+ _ -> 0
244
+ zerosRunsList x = map helper $ groupZerosRuns x
246
245
where
247
246
helper h = (head h == AllZeros , lh) where lh = length h
248
247
groupZerosRuns = group . filter (/= Colon )
@@ -253,13 +252,14 @@ ipv6TokensToIPv6Addr l = Just $ IPv6Addr $ ipv6TokensToText l
253
252
networkInterfacesIPv6AddrList :: IO [(String ,IPv6 )]
254
253
networkInterfacesIPv6AddrList =
255
254
getNetworkInterfaces >>= \ n -> return $ map networkInterfacesIPv6Addr n
256
- where networkInterfacesIPv6Addr (NetworkInterface n _ a _) = (n,a)
255
+ where
256
+ networkInterfacesIPv6Addr (NetworkInterface n _ a _) = (n,a)
257
257
258
258
fullSixteenBit :: T. Text -> Maybe IPv6AddrToken
259
259
fullSixteenBit t =
260
260
case parse fourHexaChars t of
261
- Done a b -> if a== T. empty then Just $ SixteenBit $ T. pack b else Nothing
262
- _ -> Nothing
261
+ Done a b -> if a== T. empty then Just $ SixteenBit $ T. pack b else Nothing
262
+ _ -> Nothing
263
263
264
264
macAddr :: Parser (Maybe [IPv6AddrToken ])
265
265
macAddr = do
@@ -277,33 +277,33 @@ sixteenBit = do
277
277
-- "Leading zeros MUST be suppressed" (RFC 5952, 4.1)
278
278
let r' = T. dropWhile (== ' 0' ) $ T. pack r
279
279
return $ if T. null r'
280
- then AllZeros
281
- -- Hexadecimal digits MUST be in lowercase (RFC 5952 4.3)
282
- else SixteenBit $ T. toLower r'
280
+ then AllZeros
281
+ -- Hexadecimal digits MUST be in lowercase (RFC 5952 4.3)
282
+ else SixteenBit $ T. toLower r'
283
283
284
284
ipv4Addr :: Parser IPv6AddrToken
285
285
ipv4Addr = do
286
286
n1 <- manyDigits <*. dot
287
287
if n1 /= T. empty
288
- then do n2 <- manyDigits <*. dot
289
- if n2 /= T. empty
290
- then do n3 <- manyDigits <*. dot
291
- if n3 /= T. empty
292
- then do n4 <- manyDigits
293
- if n4 /= T. empty
294
- then return $ IPv4Addr $ T. intercalate dot [n1,n2,n3,n4]
295
- else parserFailure
296
- else parserFailure
297
- else parserFailure
298
- else parserFailure
288
+ then do n2 <- manyDigits <*. dot
289
+ if n2 /= T. empty
290
+ then do n3 <- manyDigits <*. dot
291
+ if n3 /= T. empty
292
+ then do n4 <- manyDigits
293
+ if n4 /= T. empty
294
+ then return $ IPv4Addr $ T. intercalate dot [n1,n2,n3,n4]
295
+ else parserFailure
296
+ else parserFailure
297
+ else parserFailure
298
+ else parserFailure
299
299
where
300
300
parserFailure = fail " ipv4Addr parsing failure"
301
301
dot = T. pack " ."
302
302
manyDigits = do
303
303
ds <- takeWhile1 isDigit
304
304
case R. decimal ds of
305
- Right (n,_) -> return (if n < 256 then T. pack $ show n else T. empty)
306
- Left _ -> return T. empty
305
+ Right (n,_) -> return (if n < 256 then T. pack $ show n else T. empty)
306
+ Left _ -> return T. empty
307
307
308
308
doubleColon :: Parser IPv6AddrToken
309
309
doubleColon = do
0 commit comments