wikk_ipv4 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +10 -0
  3. data/lib/wikk_ipv4.rb +194 -31
  4. data/version +1 -1
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4777a6c555cb227258c37530ce246e908080cdf6e8bc2eb399fb84eb08fca280
4
- data.tar.gz: 9f0831860c41ccf98bfac61c6fbd7d5583c91fdfb50358145682d520a9a32c1f
3
+ metadata.gz: 45e4407cf771cc48e192398fae57b65900e66aa1cee3b05ec67921bfb1e93389
4
+ data.tar.gz: ecf43d3987463028f34e86a77618b9edcd72e0617200b68f5259a5d7a5e5335c
5
5
  SHA512:
6
- metadata.gz: 2a5a65ec6413b493f11e1100065f124e88de3614b16b995583e72cc5fd1ac3ce6f4a32a01f85af99de4dbb71a4808b13696df3b56e1f7f316896f53d4c59b2bd
7
- data.tar.gz: 3f8ada255ebd744c7d1afd074f1f31b60c71863a865ddbcc4b52cef52c3a15a1c849fd09454a928dca78aa75e1f513909ed12e01843ef448d13a53941c07fc05
6
+ metadata.gz: 2fc0da6d2a34617489427f20986f0cf17df5344560f1f647c58c659bc597d8e35b2353ee2784dd915e80516355238ada2a544159a01e1d1a75f69d6fd2e2d6a7
7
+ data.tar.gz: 635d50f75017ed60324a376e230d619826c5fdecef9584ac8df5abbc64e91a84570c3249a5254f8ade08a8590e845d136a82b99dd4eab383e18d911d93a3524e
data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ robertburrowes Fri Jun 24 18:27:50 2022 +1200
2
+ bump version
3
+ robertburrowes Fri Jun 24 18:27:27 2022 +1200
4
+ added methods last_host and first_host to return IPv4 address Modified network and broadcast to either return the IPv4 or calculate these with a different mask applied. Tidied up the revptr and revnet Fixed the issubnet? test
5
+ robertburrowes Fri Jun 24 18:24:32 2022 +1200
6
+ created tests
7
+ robertburrowes Fri Jun 24 16:31:08 2022 +1200
8
+ merge in the other copy from 2018
9
+ robertburrowes Fri Jun 24 12:53:27 2022 +1200
10
+ chmod
1
11
  robertburrowes Mon Jun 13 13:52:07 2022 +1200
2
12
  rubocop
3
13
  robertburrowes Mon Jun 13 13:45:19 2022 +1200
data/lib/wikk_ipv4.rb CHANGED
@@ -2,87 +2,250 @@
2
2
  module WIKK
3
3
  # Some utility IPv4 calles
4
4
  class IPv4
5
- VERSION = '0.0.1'
5
+ VERSION = '0.0.2'
6
6
 
7
- attr_reader :ip_address, :mask
7
+ attr_reader :host # [Integer] IPv4 Address
8
+ attr_reader :mask # [Integer] IPv4 Mask
9
+ attr_reader :mask_bytes # [Array] Integer values, for each byte
10
+ attr_reader :mask_length # [Integer] mask length i.e. 24 for /24
8
11
 
9
- def initialize(s, mask = 0xffffffff)
10
- @mask = mask
11
- if s.instance_of?(String)
12
- ip = s.split(/\./)
12
+ def initialize(host, mask = 32)
13
+ @mask, @mask_length, @mask_bytes = process_mask(mask)
14
+ if host.instance_of?(String)
15
+ ip = host.split(/\./)
13
16
  (0..3).each { |i| ip[i] = '0' if ip[i].nil? }
14
- @ip_address = ((ip[0].to_i << 24) | (ip[1].to_i << 16) | (ip[2].to_i << 8) | ip[3].to_i) & mask
15
- elsif s
16
- @ip_address = s & mask
17
+ @host = ((ip[0].to_i << 24) | (ip[1].to_i << 16) | (ip[2].to_i << 8) | ip[3].to_i)
18
+ elsif host.instance_of?(Integer)
19
+ @host = host
20
+ else
21
+ @host = nil
22
+ return
23
+ end
24
+ @network = @host & @mask
25
+ @broadcast = (~@network & ~@mask & 0xFFFFFFFF) | @network
26
+ @first_host = @network + 1
27
+ @last_host = @broadcast - 1
28
+ end
29
+
30
+ def process_mask(mask)
31
+ if mask.instance_of?(String)
32
+ return process_string_mask(mask)
33
+ elsif mask.instance_of?(Integer)
34
+ return process_int_mask(mask)
17
35
  else
18
- @ip_address = nil
36
+ raise "Unknown Mask type #{mask.class}"
37
+ end
38
+ end
39
+
40
+ # Takes an Integer mask, and returns the length in bits
41
+ # @param [Integer] Integer Mask (0xFF000000)
42
+ # @return [Integer] Mask length in bits (8)
43
+ def calc_mask_length(mask)
44
+ mask_length = 0
45
+ (1..32).each do |_i|
46
+ mask_length += 1 if (mask & 0x1) == 1
47
+ mask = mask >> 1
19
48
  end
49
+ return mask_length
50
+ end
51
+
52
+ def length
53
+ broadcast.to_i - network.to_i + 1
20
54
  end
21
55
 
22
- def ip_address=(value)
56
+ # Turns mask string into an Integer mask, mask length and Integer array
57
+ # @param mask [String] Mask of the form '255.0.0.0'
58
+ # @return [Array] Integer Mask (0xFF000000), Mask Length (8), Mask Integer Array ([0xFF,0,0,0])
59
+ def process_string_mask(mask)
60
+ return nil, nil, nil if mask.class != String
61
+
62
+ mask_bytes = mask.split('.') # Make into a byte array
63
+ mask_bytes.collect!(& :to_i) # Convert the string bytes into integers
64
+ # Turn the byte array into a single integer.
65
+ mask = (mask_bytes[0] << 24) + (mask_bytes[1] << 16) + (mask_bytes[2] << 8) + mask_bytes[3]
66
+ mask_length = calc_mask_length(mask)
67
+
68
+ return mask, mask_length, mask_bytes
69
+ end
70
+
71
+ # Turns mask into an Integer mask, mask length and Integer array
72
+ # @param mask [Integer] Either an Integer mask (0xFF000000), or the mask length (8) as an Integer
73
+ # @return [Array] Integer Mask (0xFF000000), Mask Length (8), Mask Integer Array ([0xFF, 0,0,0])
74
+ def process_int_mask(mask)
75
+ return nil, nil, nil unless mask.instance_of?(Integer)
76
+
77
+ if (mask & 0x800000) == 0 # Assume it is the mask length
78
+ mask_length = mask
79
+ mask = 0xFFFFFFFF << (32 - mask_length)
80
+ else # Assume it is a full mask
81
+ mask_length = calc_mask_length(mask)
82
+ end
83
+
84
+ mask_bytes = []
85
+ mask_bytes[3] = mask & 255
86
+ mask_bytes[2] = (mask >> 8) & 255
87
+ mask_bytes[1] = (mask >> 16) & 255
88
+ mask_bytes[0] = (mask >> 24) & 255
89
+
90
+ return mask, mask_length, mask_bytes
91
+ end
92
+
93
+ # Store IP address in @host
94
+ # @param value [String|Integer] Accepts "x.x.x.x" or a network order Integer IP address
95
+ def host=(value)
23
96
  if value.instance_of?(String)
24
97
  ip = s.split(/\./)
25
98
  (0..3).each { |i| ip[i] = '0' if ip[i].nil? }
26
- @ip_address = ((ip[0].to_i << 24) | (ip[1].to_i << 16) | (ip[2].to_i << 8) | ip[3].to_i) & mask
99
+ @host = ((ip[0].to_i << 24) | (ip[1].to_i << 16) | (ip[2].to_i << 8) | ip[3].to_i) & mask
27
100
  else
28
- @ip_address = value
101
+ @host = value
29
102
  end
30
103
  end
31
104
 
32
- def to_s(mask = 0xffffffff)
33
- if @ip_address
34
- ip = (@ip_address & mask)
105
+ alias ipaddress= host=
106
+ alias ipaddress host
107
+
108
+ # @return [String] the host address
109
+ def to_s(mask = 32) # 32 being a host ip address. Can also be a String, or Integer Mask
110
+ mask, _mask_length, _mask_bytes = process_mask(mask)
111
+ if @host
112
+ ip = (@host & mask)
35
113
  "#{(ip >> 24) & 255}.#{(ip >> 16) & 255}.#{(ip >> 8) & 255}.#{ip & 255}"
36
114
  else
37
115
  ''
38
116
  end
39
117
  end
40
118
 
41
- def network(mask)
42
- self.class.new(@ip_address, mask)
119
+ # @return [IPv4] the host address
120
+ def network(mask = nil)
121
+ if mask.nil?
122
+ self.class.new(@network, @mask)
123
+ else
124
+ mask, _mask_length, _mask_bytes = process_mask(mask)
125
+ self.class.new(@host & mask, mask)
126
+ end
43
127
  end
44
128
 
45
- def broadcast(mask)
46
- self.class.new(@ip_address & mask | ~mask)
129
+ # @return [IPv4] The broadcast address
130
+ def broadcast(mask = nil)
131
+ if mask.nil?
132
+ self.class.new(@broadcast, @mask)
133
+ else
134
+ self.class.new((~@host & ~mask & 0xFFFFFFFF) | @network, mask)
135
+ end
136
+ end
137
+
138
+ # @return [IPv4] First host IPv4 Address for this mask
139
+ def first_host
140
+ self.class.new(@first_host, @mask)
141
+ end
142
+
143
+ # @return [IPv4] Second to last IPv4 Address for this mask
144
+ def last_host
145
+ self.class.new(@last_host, @mask)
47
146
  end
48
147
 
148
+ # @return [Integer] the IPv4 address as an integer
49
149
  def to_i
50
- @ip_address
150
+ @host
51
151
  end
52
152
 
153
+ # @return [Integer] IPv4 mask from a string to an Int
53
154
  def self.mask_to_i(s)
54
155
  ip = s.split(/\./)
55
156
  ((ip[0].to_i << 24) | (ip[1].to_i << 16) | (ip[2].to_i << 8) | ip[3].to_i)
56
157
  end
57
158
 
159
+ # @return [Integer] mask for number of bits in mask
58
160
  def self.maskbits_to_i(n)
59
161
  0xffffffff >> (32 - n) << (32 - n)
60
162
  end
61
163
 
164
+ # @return [IPv4] add two addresses
62
165
  def +(other)
63
- self.class.new(@ip_address + other)
166
+ self.class.new(@host + other)
64
167
  end
65
168
 
66
- def revptr(bytes)
67
- rip = [ "#{@ip_address & 255}", "#{(@ip_address >> 8) & 255}", "#{(@ip_address >> 16) & 255}", "#{(@ip_address >> 24) & 255}" ]
68
- rip[0, 4 - bytes].join('.')
169
+ # @return [IPv4] Difference between two addresses
170
+ def -(other)
171
+ self.class.new(@host - other)
69
172
  end
70
173
 
71
- def revnet(bytes)
72
- rip = [ "#{@ip_address & 255}", "#{(@ip_address >> 8) & 255}", "#{(@ip_address >> 16) & 255}", "#{(@ip_address >> 24) & 255}" ]
73
- rip[4 - bytes, bytes].join('.')
174
+ # @return [String] host part of IPv4 as DNS reverse string
175
+ def revptr(bytes = nil, mask = nil)
176
+ if mask.nil?
177
+ mask = @mask
178
+ else
179
+ mask, _mask_length, _mask_bytes = process_mask(mask)
180
+ end
181
+ addr = (@host & ~mask)
182
+ bytes ||= 4 - ((@mask_length - 1) / 8 + 1)
183
+ rip = [ "#{addr & 255}", "#{(addr >> 8) & 255}", "#{(addr >> 16) & 255}", "#{(addr >> 24) & 255}" ]
184
+ rip[0..bytes].join('.')
185
+ end
186
+
187
+ # @return [String] host part of IPv4 as DNS reverse string
188
+ def revnet(bytes = nil, mask = nil)
189
+ if mask.nil?
190
+ mask = @mask
191
+ else
192
+ mask, _mask_length, _mask_bytes = process_mask(mask)
193
+ end
194
+ addr = (@host & mask)
195
+ bytes ||= ((@mask_length - 1) / 8 + 1) - 4
196
+ rip = [ "#{addr & 255}", "#{(addr >> 8) & 255}", "#{(addr >> 16) & 255}", "#{(addr >> 24) & 255}" ]
197
+ rip[bytes..-1].join('.')
74
198
  end
75
199
 
200
+ # Test if IP addresses are the same
201
+ # @param i [IPV4] address to check against local ip address
202
+ # @return [Boolean]
76
203
  def ==(other)
77
- @ip_address == other.ip_address
204
+ @host == other.host
78
205
  end
79
206
 
207
+ # @return [Boolean] the IP address is not nil
80
208
  def notnil?
81
- @ip_address != nil
209
+ @host != nil
82
210
  end
83
211
 
212
+ # Test to see if one network is a subnet of another
213
+ # @param net [IPV4] Net we want to check is a subnet of this net
214
+ # @return [Boolean]
84
215
  def issubnet?(net)
85
- (@ip_address & @mask) == (net.ip_address & @mask)
216
+ (@network == (net.host & @mask)) && @mask_length <= net.mask_length
217
+ end
218
+
219
+ # @return [Array] Split IPv4 address (integer) into 4 bytes
220
+ def to_bytes(address)
221
+ bytes = []
222
+ bytes[3] = address & 255
223
+ bytes[2] = (address >> 8) & 255
224
+ bytes[1] = (address >> 16) & 255
225
+ bytes[0] = (address >> 24) & 255
226
+ return bytes
227
+ end
228
+
229
+ # @return [String] IPv4 address
230
+ def ip_to_s(address)
231
+ bytes = to_bytes(address)
232
+ "#{bytes[0]}.#{bytes[1]}.#{bytes[2]}.#{bytes[3]}"
233
+ end
234
+
235
+ # Iterate over a network's IP addresses
236
+ # @yield [IPv4] addresses
237
+ def each_ip
238
+ ((@network + 1)..@last_host).each { |ip| yield ip_to_s(ip) }
239
+ end
240
+
241
+ # Compare two IPv4 addresses
242
+ def <=>(other)
243
+ @host.to_i <=> other.to_i
244
+ end
245
+
246
+ # @return [IPv4] the next IPv4 address
247
+ def succ
248
+ self.class.new(@host + 1)
86
249
  end
87
250
  end
88
251
  end
data/version CHANGED
@@ -1,2 +1,2 @@
1
1
  PROJECT="wikk_ipv4"
2
- VERSION="0.0.1"
2
+ VERSION="0.0.2"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wikk_ipv4
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Burrowes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-18 00:00:00.000000000 Z
11
+ date: 2022-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hoe-yard