]> gitweb.michael.orlitzky.com - hath.git/blob - src/Cidr.hs
Move the is_valid_cidr function in to the Cidr module.
[hath.git] / src / Cidr.hs
1 module Cidr
2 ( Cidr,
3 from_string,
4 is_valid_cidr,
5 min_first_octet,
6 max_first_octet,
7 min_second_octet,
8 max_second_octet,
9 min_third_octet,
10 max_third_octet,
11 min_fourth_octet,
12 max_fourth_octet
13 ) where
14
15 import Data.Char (digitToInt, intToDigit)
16 import Numeric (readInt, showIntAtBase)
17 import Text.Regex.Posix
18
19 import ListUtils
20
21 type Maskbits = Int
22 type Octet = Int
23 type OctetList = (Octet, Octet, Octet, Octet)
24 type BaseTwoOctetList = (String, String, String, String)
25
26 data Cidr = Cidr { octet1 :: Octet,
27 octet2 :: Octet,
28 octet3 :: Octet,
29 octet4 :: Octet,
30 maskbits :: Maskbits }
31 deriving (Show)
32
33 -- Will return True if the passed String is in CIDR notation, False
34 -- otherwise.
35 is_valid_cidr :: String -> Bool
36 is_valid_cidr cidr = cidr =~ "([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}"
37
38 first :: (a,b,c,d) -> a
39 first (w,_,_,_) = w
40
41 second :: (a,b,c,d) -> b
42 second (_,x,_,_) = x
43
44 third :: (a,b,c,d) -> c
45 third (_,_,y,_) = y
46
47 fourth :: (a,b,c,d) -> d
48 fourth (_,_,_,z) = z
49
50 min_first_octet :: Cidr -> Octet
51 min_first_octet cidr = first (min_octets cidr)
52
53 min_second_octet :: Cidr -> Octet
54 min_second_octet cidr = second (min_octets cidr)
55
56 min_third_octet :: Cidr -> Octet
57 min_third_octet cidr = third (min_octets cidr)
58
59 min_fourth_octet :: Cidr -> Octet
60 min_fourth_octet cidr = fourth (min_octets cidr)
61
62 max_first_octet :: Cidr -> Octet
63 max_first_octet cidr = first (max_octets cidr)
64
65 max_second_octet :: Cidr -> Octet
66 max_second_octet cidr = second (max_octets cidr)
67
68 max_third_octet :: Cidr -> Octet
69 max_third_octet cidr = third (max_octets cidr)
70
71 max_fourth_octet :: Cidr -> Octet
72 max_fourth_octet cidr = fourth (max_octets cidr)
73
74
75 -- Returns the mask portion of a CIDR address. That is, everything
76 -- after the trailing slash.
77 maskbits_from_string :: String -> Maskbits
78 maskbits_from_string s = read ((splitWith (`elem` "/") s) !! 1)
79
80
81 -- Takes an IP address String in CIDR notation, and returns a list of
82 -- its octets (converted to Int).
83 octets_from_string :: String -> [Octet]
84 octets_from_string s = map read (take 4 (splitWith (`elem` "./") s))
85
86
87 from_string :: String -> Cidr
88 from_string s = Cidr (octs !! 0) (octs !! 1) (octs !! 2) (octs !! 3) mbits
89 where
90 octs = octets_from_string s
91 mbits = maskbits_from_string s
92
93
94 -- The base_two_to_base_ten function requires a way to determine
95 -- whether or not the character it's currently parsing is valid. This
96 -- should do it.
97 is_binary_digit :: Char -> Bool
98 is_binary_digit c =
99 if c `elem` ['0','1'] then
100 True
101 else
102 False
103
104
105 -- Takes an Int, and returns its base-two representation as a String.
106 base_two :: Int -> String
107 base_two n = showIntAtBase 2 intToDigit n ""
108
109
110 -- Takes a set of octets, and converts them to base-two
111 -- individually. The results are then zero-padded on the left to 8
112 -- characters, and concatenated together.
113 octets_base_two :: Cidr -> String
114 octets_base_two cidr =
115 s1 ++ s2 ++ s3 ++ s4
116 where
117 s1 = ((pad_left_to 8 '0') . base_two) (octet1 cidr)
118 s2 = ((pad_left_to 8 '0') . base_two) (octet2 cidr)
119 s3 = ((pad_left_to 8 '0') . base_two) (octet3 cidr)
120 s4 = ((pad_left_to 8 '0') . base_two) (octet4 cidr)
121
122
123 base_two_octetlist_to_octetlist :: BaseTwoOctetList -> OctetList
124 base_two_octetlist_to_octetlist b2ol =
125 (oct1, oct2, oct3, oct4)
126 where
127 oct1 = base_two_to_base_ten (first b2ol)
128 oct2 = base_two_to_base_ten (second b2ol)
129 oct3 = base_two_to_base_ten (third b2ol)
130 oct4 = base_two_to_base_ten (fourth b2ol)
131
132
133 -- Convert a base-two String to an Int.
134 base_two_to_base_ten :: String -> Int
135 base_two_to_base_ten s =
136 if (length parsed) == 0 then
137 0
138 else
139 fst (parsed !! 0)
140 where
141 parsed = readInt 2 is_binary_digit digitToInt s
142
143
144 -- Returns the minimum address (as a base-two string) satisfying the
145 -- given CIDR string.
146 min_base_two_address :: Cidr -> String
147 min_base_two_address cidr =
148 pad_right_to 32 '0' netpart
149 where
150 netpart = take (maskbits cidr) (octets_base_two cidr)
151
152
153 -- Returns the maximum address (as a base-two string) satisfying the
154 -- given CIDR string.
155 max_base_two_address :: Cidr -> String
156 max_base_two_address cidr =
157 pad_right_to 32 '1' netpart
158 where
159 netpart = take (maskbits cidr) (octets_base_two cidr)
160
161
162 -- The octet components of min_base_two_address, as a base-two String.
163 min_base_two_octets :: Cidr -> BaseTwoOctetList
164 min_base_two_octets cidr =
165 (oct1, oct2, oct3, oct4)
166 where
167 addr = min_base_two_address cidr
168 oct1 = fst (splitAt 8 addr)
169 oct2 = fst (splitAt 8 (snd (splitAt 8 addr)))
170 oct3 = fst (splitAt 8 (snd (splitAt 16 addr)))
171 oct4 = snd (splitAt 24 addr)
172
173
174 -- The octet components of max_base_two_address, as a base-two String.
175 max_base_two_octets :: Cidr -> BaseTwoOctetList
176 max_base_two_octets cidr =
177 (oct1, oct2, oct3, oct4)
178 where
179 addr = max_base_two_address cidr
180 oct1 = fst (splitAt 8 addr)
181 oct2 = fst (splitAt 8 (snd (splitAt 8 addr)))
182 oct3 = fst (splitAt 8 (snd (splitAt 16 addr)))
183 oct4 = snd (splitAt 24 addr)
184
185
186 -- The octet components of min_base_two_address, as Ints.
187 min_octets :: Cidr -> OctetList
188 min_octets cidr = base_two_octetlist_to_octetlist (min_base_two_octets cidr)
189
190
191 -- The octet components of max_base_two_address, as Ints.
192 max_octets :: Cidr -> OctetList
193 max_octets cidr = base_two_octetlist_to_octetlist (max_base_two_octets cidr)