wikk_ipv4 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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