ipaddr 1.2.9 → 1.3.1

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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/ipaddr.rb +128 -29
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d7f44f2a3874755d2b38a4cf417bc3b86f1298a92a47ce0df1c6da780982f10
4
- data.tar.gz: d7b75a507f7345cfdb5fa1e7141748031b102e843982a5d627fb3d2f9ff9c302
3
+ metadata.gz: b3a45f67694de980f29fe97b4b20675bf93b95d8250b26dfcc0549816129394a
4
+ data.tar.gz: 37d8f96d02031b7847bd8c32b22776cdf0e9596a416defc64769899d5e89c6d3
5
5
  SHA512:
6
- metadata.gz: 34b061ae03573b58b00b867655c94edb42970eccf6297ac29915fb5e9cec430479eadb0cae90c9857b395ed9d220cd9eaa596a791f0225237113ab010b6dcba4
7
- data.tar.gz: 7347ead0e35fa0bad997db445806eda0bdc6d8ddcffba1b8ff6d8d36f3c3febfa429e59bf36a0b5381690c3881163b070b858dc92cea1d8eca887657a4085f96
6
+ metadata.gz: 3da16382856d2668a53ca3f270b708e0ec8d3d109e6c103aa9be482aac4b84697d12a9b928b13516a522ae355ab8c47e79299d4c18e356c6944add55a6033613
7
+ data.tar.gz: 60ec70c14d1715254f564070d8f3b7bbac87a7a07af194f99604fbf222d7cea15f08fc858497b8f9a342ea94dbccd1706f1d14b5b686792a800fce2c9cec9206
data/README.md CHANGED
@@ -15,7 +15,7 @@ version than comes with older versions of ruby.
15
15
  For example, you can add this line to your application's Gemfile:
16
16
 
17
17
  ```ruby
18
- gem 'ipaddr', '~> 1.2'
18
+ gem 'ipaddr'
19
19
  ```
20
20
 
21
21
  And then execute:
data/lib/ipaddr.rb CHANGED
@@ -41,7 +41,7 @@ require 'socket'
41
41
 
42
42
  class IPAddr
43
43
  # The version string
44
- VERSION = "1.2.9"
44
+ VERSION = "1.3.1"
45
45
 
46
46
  # 32 bit mask for IPv4
47
47
  IN4MASK = 0xffffffff
@@ -205,9 +205,51 @@ class IPAddr
205
205
  return @addr
206
206
  end
207
207
 
208
+ # Returns a string containing the binary representation of the
209
+ # IP address value, right adjusted to the address size (32 bits
210
+ # for IPv4, 128 bits for IPv6), regardless of the prefix length.
211
+ #
212
+ # e.g.:
213
+ # require 'ipaddr'
214
+ # p IPAddr.new("192.168.1.1").to_bits
215
+ # #=> "11000000101010000000000100000001"
216
+ # p IPAddr.new("3ffe:505:2::1").to_bits
217
+ # #=> "00111111111111100000010100000101" \
218
+ # # "00000000000000100000000000000000" \
219
+ # # "00000000000000000000000000000000" \
220
+ # # "00000000000000000000000000000001"
221
+ def to_bits
222
+ case @family
223
+ when Socket::AF_INET
224
+ @addr.to_s(2).rjust(32, '0')
225
+ when Socket::AF_INET6
226
+ @addr.to_s(2).rjust(128, '0')
227
+ else
228
+ raise AddressFamilyError, "unsupported address family"
229
+ end
230
+ end
231
+
232
+ # Returns a string containing the hexadecimal representation of the
233
+ # IP address value, right adjusted to the address size.
234
+ #
235
+ # e.g.:
236
+ # require 'ipaddr'
237
+ # p IPAddr.new("192.168.1.1").to_hex #=> "c0a80101"
238
+ # p IPAddr.new("3ffe:505:2::1").to_hex #=> "3ffe0505000200000000000000000001"
239
+ def to_hex
240
+ case @family
241
+ when Socket::AF_INET
242
+ @addr.to_s(16).rjust(8, '0')
243
+ when Socket::AF_INET6
244
+ @addr.to_s(16).rjust(32, '0')
245
+ else
246
+ raise AddressFamilyError, "unsupported address family"
247
+ end
248
+ end
249
+
208
250
  # Returns a string containing the IP address representation.
209
251
  def to_s
210
- str = to_string
252
+ str = _to_string(@addr)
211
253
  return str if ipv4?
212
254
 
213
255
  str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
@@ -227,6 +269,7 @@ class IPAddr
227
269
  str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
228
270
  end
229
271
 
272
+ str << @zone_id if @zone_id
230
273
  str
231
274
  end
232
275
 
@@ -267,12 +310,9 @@ class IPAddr
267
310
  # Returns a network byte ordered string form of the IP address.
268
311
  def hton
269
312
  case @family
270
- when Socket::AF_INET
271
- return [@addr].pack('N')
272
- when Socket::AF_INET6
273
- return (0..7).map { |i|
274
- (@addr >> (112 - 16 * i)) & 0xffff
275
- }.pack('n8')
313
+ when Socket::AF_INET, Socket::AF_INET6
314
+ value = to_hex
315
+ return [value].pack("H#{value.length}")
276
316
  else
277
317
  raise AddressFamilyError, "unsupported address family"
278
318
  end
@@ -294,11 +334,11 @@ class IPAddr
294
334
  def loopback?
295
335
  case @family
296
336
  when Socket::AF_INET
297
- @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
337
+ (@addr & 0xff000000 == 0x7f000000) && prefix >= 8 # 127.0.0.1/8
298
338
  when Socket::AF_INET6
299
339
  @addr == 1 || # ::1
300
340
  (@addr >> 32 == 0xffff && (
301
- @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
341
+ (@addr & 0xff000000 == 0x7f000000) && prefix >= 104 # ::ffff:127.0.0.0/104 (127.0.0.1/8)
302
342
  ))
303
343
  else
304
344
  raise AddressFamilyError, "unsupported address family"
@@ -313,22 +353,22 @@ class IPAddr
313
353
  def private?
314
354
  case @family
315
355
  when Socket::AF_INET
316
- @addr & 0xff000000 == 0x0a000000 || # 10.0.0.0/8
317
- @addr & 0xfff00000 == 0xac100000 || # 172.16.0.0/12
318
- @addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16
356
+ (@addr & 0xff000000 == 0x0a000000) && prefix >= 8 || # 10.0.0.0/8
357
+ (@addr & 0xfff00000 == 0xac100000) && prefix >= 12 || # 172.16.0.0/12
358
+ (@addr & 0xffff0000 == 0xc0a80000) && prefix >= 16 # 192.168.0.0/16
319
359
  when Socket::AF_INET6
320
- @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 ||
360
+ (@addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000) && prefix >= 7 || # fc00::/7
321
361
  (@addr >> 32 == 0xffff && (
322
- @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8
323
- @addr & 0xfff00000 == 0xac100000 || # ::ffff:172.16.0.0/12
324
- @addr & 0xffff0000 == 0xc0a80000 # ::ffff:192.168.0.0/16
362
+ (@addr & 0xff000000 == 0x0a000000) && prefix >= 104 || # ::ffff:10.0.0.0/104 (10.0.0.0/8)
363
+ (@addr & 0xfff00000 == 0xac100000) && prefix >= 108 || # ::ffff:172.16.0.0/108 (172.16.0.0/12)
364
+ (@addr & 0xffff0000 == 0xc0a80000) && prefix >= 112 # ::ffff:192.168.0.0/112 (192.168.0.0/16)
325
365
  ))
326
366
  else
327
367
  raise AddressFamilyError, "unsupported address family"
328
368
  end
329
369
  end
330
370
 
331
- # Returns true if the ipaddr is a link-local address. IPv4
371
+ # Returns true if the ipaddr is a link-local unicast address. IPv4
332
372
  # addresses in 169.254.0.0/16 reserved by RFC 3927 and link-local
333
373
  # IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are
334
374
  # considered link-local. Link-local IPv4 addresses in the
@@ -336,11 +376,65 @@ class IPAddr
336
376
  def link_local?
337
377
  case @family
338
378
  when Socket::AF_INET
339
- @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
379
+ (@addr & 0xffff0000 == 0xa9fe0000) && prefix >= 16 # 169.254.0.0/16
340
380
  when Socket::AF_INET6
341
- @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
381
+ (@addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000) && prefix >= 10 || # fe80::/10
342
382
  (@addr >> 32 == 0xffff && (
343
- @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
383
+ (@addr & 0xffff0000 == 0xa9fe0000) && prefix >= 112 # ::ffff:169.254.0.0/112 (169.254.0.0/16)
384
+ ))
385
+ else
386
+ raise AddressFamilyError, "unsupported address family"
387
+ end
388
+ end
389
+
390
+ alias link_local_unicast? link_local?
391
+
392
+ # Returns true if the ipaddr is an unspecified address. The IPv4
393
+ # address 0.0.0.0 and the IPv6 address :: are unspecified. Unspecified
394
+ # IPv4 addresses in the IPv4-mapped IPv6 address range are also
395
+ # considered unspecified.
396
+ def unspecified?
397
+ case @family
398
+ when Socket::AF_INET
399
+ @addr == 0 && prefix == 32 # 0.0.0.0
400
+ when Socket::AF_INET6
401
+ @addr == 0 && prefix == 128 || # ::
402
+ (@addr >> 32 == 0xffff && (@addr & IN4MASK) == 0) && prefix == 128 # ::ffff:0.0.0.0
403
+ else
404
+ raise AddressFamilyError, "unsupported address family"
405
+ end
406
+ end
407
+
408
+ # Returns true if the ipaddr is a multicast address. IPv4
409
+ # addresses in 224.0.0.0/4 and IPv6 multicast addresses
410
+ # in ff00::/8 are considered multicast. Multicast IPv4 addresses in the
411
+ # IPv4-mapped IPv6 address range are also considered multicast.
412
+ def multicast?
413
+ case @family
414
+ when Socket::AF_INET
415
+ (@addr & 0xf0000000 == 0xe0000000) && prefix >= 4 # 224.0.0.0/4
416
+ when Socket::AF_INET6
417
+ (@addr & 0xff00_0000_0000_0000_0000_0000_0000_0000 == 0xff00_0000_0000_0000_0000_0000_0000_0000) && prefix >= 8 || # ff00::/8
418
+ (@addr >> 32 == 0xffff &&
419
+ (@addr & 0xf0000000 == 0xe0000000) && prefix >= 100 # ::ffff:224.0.0.0/100 (224.0.0.0/4)
420
+ )
421
+ else
422
+ raise AddressFamilyError, "unsupported address family"
423
+ end
424
+ end
425
+
426
+ # Returns true if the ipaddr is a link-local multicast address. IPv4
427
+ # addresses in 224.0.0.0/24 and link-local IPv6 Multicast Addresses in ff02::/16
428
+ # are considered link-local multicast. Link-local multicast IPv4 addresses in the
429
+ # IPv4-mapped IPv6 address range are also considered link-local multicast.
430
+ def link_local_multicast?
431
+ case @family
432
+ when Socket::AF_INET
433
+ (@addr & 0xffffff00 == 0xe0000000) && prefix >= 24 # 224.0.0.0/24 Local Network Control Block
434
+ when Socket::AF_INET6
435
+ (@addr & 0xffff_0000_0000_0000_0000_0000_0000_0000 == 0xff02_0000_0000_0000_0000_0000_0000_0000) && prefix >= 16 || # ff02::/16
436
+ (@addr >> 32 == 0xffff && (
437
+ (@addr & 0xffffff00 == 0xe0000000) && prefix >= 120 # ::ffff:224.0.0.0/120 (224.0.0.0/24)
344
438
  ))
345
439
  else
346
440
  raise AddressFamilyError, "unsupported address family"
@@ -539,7 +633,7 @@ class IPAddr
539
633
  def zone_id=(zid)
540
634
  if @family == Socket::AF_INET6
541
635
  case zid
542
- when nil, /\A%(\w+)\z/
636
+ when nil, /\A%[-0-9A-Za-z._~]+\z/
543
637
  @zone_id = zid
544
638
  else
545
639
  raise InvalidAddressError, "invalid zone identifier for address"
@@ -673,12 +767,14 @@ class IPAddr
673
767
  raise AddressFamilyError, "unsupported address family: #{family}"
674
768
  end
675
769
  end
770
+ requested_family = family
676
771
  prefix, prefixlen = addr.split('/', 2)
677
772
  if prefix =~ /\A\[(.*)\]\z/i
678
773
  prefix = $1
679
774
  family = Socket::AF_INET6
775
+ bracketed = true
680
776
  end
681
- if prefix =~ /\A(.*)(%\w+)\z/
777
+ if prefix =~ /\A(.*)(%[-0-9A-Za-z._~]+)\z/
682
778
  prefix = $1
683
779
  zone_id = $2
684
780
  family = Socket::AF_INET6
@@ -698,11 +794,17 @@ class IPAddr
698
794
  @family = Socket::AF_INET6
699
795
  end
700
796
  @zone_id = zone_id
701
- if family != Socket::AF_UNSPEC && @family != family
797
+ if requested_family != Socket::AF_UNSPEC && @family != requested_family
702
798
  raise AddressFamilyError, "address family mismatch"
703
799
  end
704
800
  if prefixlen
705
801
  mask!(prefixlen)
802
+
803
+ if bracketed
804
+ warn "bracketed IPv6 address with a prefix length is an invalid address " \
805
+ "and will raise IPAddr::InvalidAddressError in a future version: #{addr}",
806
+ uplevel: 1
807
+ end
706
808
  else
707
809
  @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
708
810
  end
@@ -747,7 +849,7 @@ class IPAddr
747
849
  right = ''
748
850
  when RE_IPV6ADDRLIKE_COMPRESSED
749
851
  if $4
750
- left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{left}"
852
+ left.count(':') <= ($1.empty? ? 7 : 6) or raise InvalidAddressError, "invalid address: #{left}"
751
853
  addr = in_addr($~[4,4])
752
854
  left = $1
753
855
  right = $3 + '0:0'
@@ -764,9 +866,6 @@ class IPAddr
764
866
  l = left.split(':')
765
867
  r = right.split(':')
766
868
  rest = 8 - l.size - r.size
767
- if rest < 0
768
- return nil
769
- end
770
869
  (l + Array.new(rest, '0') + r).inject(0) { |i, s|
771
870
  i << 16 | s.hex
772
871
  } | addr
@@ -790,7 +889,7 @@ class IPAddr
790
889
  (@addr >> (8 * i)) & 0xff
791
890
  }.join('.')
792
891
  when Socket::AF_INET6
793
- return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
892
+ return to_hex.reverse.chars.join('.')
794
893
  else
795
894
  raise AddressFamilyError, "unsupported address family"
796
895
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ipaddr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.9
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akinori MUSHA
@@ -42,7 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
42
42
  - !ruby/object:Gem::Version
43
43
  version: '0'
44
44
  requirements: []
45
- rubygems_version: 4.0.6
45
+ rubygems_version: 3.6.9
46
46
  specification_version: 4
47
47
  summary: A class to manipulate an IP address in ruby
48
48
  test_files: []