ipaddr 1.2.6 → 1.2.8

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/README.md +1 -1
  3. data/lib/ipaddr.rb +88 -22
  4. metadata +4 -8
  5. data/ipaddr.gemspec +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f58727d4b57c7d063e7f6671b34b03f93de0b0b38f035528f9e3b6ef77842512
4
- data.tar.gz: 71c172f3e9506cfaacd857ad27099ca01f7862737590c3fd6ac4ca01952f96c1
3
+ metadata.gz: 27c05756ec16e7913ff99aab584bbcddab9e5ef419e5f5fb17850a846c8e562d
4
+ data.tar.gz: 6845f685c7cfcee252d97e6e74f597991ba7586fc7104242e64ccad5abe9acfc
5
5
  SHA512:
6
- metadata.gz: f97223995de559e291ba8058014e3ba23606f36670c2cf8360aa1f35c2dfa716fc0956cda1ceead863715ecd5065457c295f8c8653e999e63757f88c2d937a11
7
- data.tar.gz: 20d8934e68d7f4be367267661c398c452f65d066b8a623e0e6fc2d17569fca3e82381606001eb0a56294132cd438e98ba5e7a34faf18098093bb71ea3aee9e86
6
+ metadata.gz: 71535cdb0def5ae3bdc48c762f586c569dd3104e131da598620c43ac679b705e85dc48a45fa0142a69f98097d15dabdf3b427153cb39c283459a3d5d17471da6
7
+ data.tar.gz: 74c73fbf129bfdf9526e3e76269b7c82e75dbef4b63dda82868b465c83bcd29495e470fc1743664a5a065958e455fa53ca678ac8161427a0ab10b55c92b5dd05
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  IPAddr provides a set of methods to manipulate an IP address. Both
4
4
  IPv4 and IPv6 are supported.
5
5
 
6
- [![Build Status](https://travis-ci.org/ruby/ipaddr.svg?branch=master)](https://travis-ci.org/ruby/ipaddr)
6
+ [![build](https://github.com/ruby/ipaddr/actions/workflows/test.yml/badge.svg)](https://github.com/ruby/ipaddr/actions/workflows/test.yml)
7
7
 
8
8
  ## Installation
9
9
 
data/lib/ipaddr.rb CHANGED
@@ -40,7 +40,8 @@ require 'socket'
40
40
  # p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
41
41
 
42
42
  class IPAddr
43
- VERSION = "1.2.6"
43
+ # The version string
44
+ VERSION = "1.2.8"
44
45
 
45
46
  # 32 bit mask for IPv4
46
47
  IN4MASK = 0xffffffff
@@ -52,7 +53,7 @@ class IPAddr
52
53
  # Regexp _internally_ used for parsing IPv4 address.
53
54
  RE_IPV4ADDRLIKE = %r{
54
55
  \A
55
- (\d+) \. (\d+) \. (\d+) \. (\d+)
56
+ \d+ \. \d+ \. \d+ \. \d+
56
57
  \z
57
58
  }x
58
59
 
@@ -110,8 +111,13 @@ class IPAddr
110
111
 
111
112
  # Convert a network byte ordered string form of an IP address into
112
113
  # human readable form.
114
+ # It expects the string to be encoded in Encoding::ASCII_8BIT (BINARY).
113
115
  def self.ntop(addr)
114
- case addr.size
116
+ if addr.is_a?(String) && addr.encoding != Encoding::BINARY
117
+ raise InvalidAddressError, "invalid encoding (given #{addr.encoding}, expected BINARY)"
118
+ end
119
+
120
+ case addr.bytesize
115
121
  when 4
116
122
  addr.unpack('C4').join('.')
117
123
  when 16
@@ -146,6 +152,16 @@ class IPAddr
146
152
  return self.clone.set(addr_mask(~@addr))
147
153
  end
148
154
 
155
+ # Returns a new ipaddr greater than the original address by offset
156
+ def +(offset)
157
+ self.clone.set(@addr + offset, @family)
158
+ end
159
+
160
+ # Returns a new ipaddr less than the original address by offset
161
+ def -(offset)
162
+ self.clone.set(@addr - offset, @family)
163
+ end
164
+
149
165
  # Returns true if two ipaddrs are equal.
150
166
  def ==(other)
151
167
  other = coerce_other(other)
@@ -222,6 +238,28 @@ class IPAddr
222
238
  return str
223
239
  end
224
240
 
241
+ # Returns a string containing the IP address representation with prefix.
242
+ def as_json(*)
243
+ if ipv4? && prefix == 32
244
+ to_s
245
+ elsif ipv6? && prefix == 128
246
+ to_s
247
+ else
248
+ cidr
249
+ end
250
+ end
251
+
252
+ # Returns a json string containing the IP address representation.
253
+ def to_json(*a)
254
+ %Q{"#{as_json(*a)}"}
255
+ end
256
+
257
+ # Returns a string containing the IP address representation in
258
+ # cidr notation
259
+ def cidr
260
+ "#{to_s}/#{prefix}"
261
+ end
262
+
225
263
  # Returns a network byte ordered string form of the IP address.
226
264
  def hton
227
265
  case @family
@@ -247,12 +285,17 @@ class IPAddr
247
285
  end
248
286
 
249
287
  # Returns true if the ipaddr is a loopback address.
288
+ # Loopback IPv4 addresses in the IPv4-mapped IPv6
289
+ # address range are also considered as loopback addresses.
250
290
  def loopback?
251
291
  case @family
252
292
  when Socket::AF_INET
253
- @addr & 0xff000000 == 0x7f000000
293
+ @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
254
294
  when Socket::AF_INET6
255
- @addr == 1
295
+ @addr == 1 || # ::1
296
+ (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
297
+ @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
298
+ ))
256
299
  else
257
300
  raise AddressFamilyError, "unsupported address family"
258
301
  end
@@ -282,15 +325,19 @@ class IPAddr
282
325
  end
283
326
 
284
327
  # Returns true if the ipaddr is a link-local address. IPv4
285
- # addresses in 169.254.0.0/16 reserved by RFC 3927 and Link-Local
328
+ # addresses in 169.254.0.0/16 reserved by RFC 3927 and link-local
286
329
  # IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are
287
- # considered link-local.
330
+ # considered link-local. Link-local IPv4 addresses in the
331
+ # IPv4-mapped IPv6 address range are also considered link-local.
288
332
  def link_local?
289
333
  case @family
290
334
  when Socket::AF_INET
291
335
  @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
292
336
  when Socket::AF_INET6
293
- @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
337
+ @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
338
+ (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
339
+ @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
340
+ ))
294
341
  else
295
342
  raise AddressFamilyError, "unsupported address family"
296
343
  end
@@ -307,7 +354,7 @@ class IPAddr
307
354
  _ipv4_compat?
308
355
  end
309
356
 
310
- def _ipv4_compat?
357
+ def _ipv4_compat? # :nodoc:
311
358
  if !ipv6? || (@addr >> 32) != 0
312
359
  return false
313
360
  end
@@ -335,7 +382,9 @@ class IPAddr
335
382
  if !ipv4?
336
383
  raise InvalidAddressError, "not an IPv4 address: #{@addr}"
337
384
  end
338
- return self.clone.set(@addr, Socket::AF_INET6)
385
+ clone = self.clone.set(@addr, Socket::AF_INET6)
386
+ clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000)
387
+ clone
339
388
  end
340
389
 
341
390
  # Returns a new ipaddr built by converting the IPv6 address into a
@@ -432,7 +481,7 @@ class IPAddr
432
481
  when Integer
433
482
  mask!(prefix)
434
483
  else
435
- raise InvalidPrefixError, "prefix must be an integer: #{@addr}"
484
+ raise InvalidPrefixError, "prefix must be an integer"
436
485
  end
437
486
  end
438
487
 
@@ -457,6 +506,20 @@ class IPAddr
457
506
  _to_string(@mask_addr)
458
507
  end
459
508
 
509
+ # Returns the wildcard mask in string format e.g. 0.0.255.255
510
+ def wildcard_mask
511
+ case @family
512
+ when Socket::AF_INET
513
+ mask = IN4MASK ^ @mask_addr
514
+ when Socket::AF_INET6
515
+ mask = IN6MASK ^ @mask_addr
516
+ else
517
+ raise AddressFamilyError, "unsupported address family"
518
+ end
519
+
520
+ _to_string(mask)
521
+ end
522
+
460
523
  # Returns the IPv6 zone identifier, if present.
461
524
  # Raises InvalidAddressError if not an IPv6 address.
462
525
  def zone_id
@@ -483,6 +546,7 @@ class IPAddr
483
546
  end
484
547
 
485
548
  protected
549
+ # :stopdoc:
486
550
 
487
551
  def begin_addr
488
552
  @addr & @mask_addr
@@ -498,6 +562,7 @@ class IPAddr
498
562
  raise AddressFamilyError, "unsupported address family"
499
563
  end
500
564
  end
565
+ #:startdoc:
501
566
 
502
567
  # Set +@addr+, the internal stored ip address, to given +addr+. The
503
568
  # parameter +addr+ is validated using the first +family+ member,
@@ -506,11 +571,11 @@ class IPAddr
506
571
  case family[0] ? family[0] : @family
507
572
  when Socket::AF_INET
508
573
  if addr < 0 || addr > IN4MASK
509
- raise InvalidAddressError, "invalid address: #{@addr}"
574
+ raise InvalidAddressError, "invalid address: #{addr}"
510
575
  end
511
576
  when Socket::AF_INET6
512
577
  if addr < 0 || addr > IN6MASK
513
- raise InvalidAddressError, "invalid address: #{@addr}"
578
+ raise InvalidAddressError, "invalid address: #{addr}"
514
579
  end
515
580
  else
516
581
  raise AddressFamilyError, "unsupported address family"
@@ -537,12 +602,12 @@ class IPAddr
537
602
  else
538
603
  m = IPAddr.new(mask)
539
604
  if m.family != @family
540
- raise InvalidPrefixError, "address family is not same: #{@addr}"
605
+ raise InvalidPrefixError, "address family is not same"
541
606
  end
542
607
  @mask_addr = m.to_i
543
608
  n = @mask_addr ^ m.instance_variable_get(:@mask_addr)
544
609
  unless ((n + 1) & n).zero?
545
- raise InvalidPrefixError, "invalid mask #{mask}: #{@addr}"
610
+ raise InvalidPrefixError, "invalid mask #{mask}"
546
611
  end
547
612
  @addr &= @mask_addr
548
613
  return self
@@ -553,13 +618,13 @@ class IPAddr
553
618
  case @family
554
619
  when Socket::AF_INET
555
620
  if prefixlen < 0 || prefixlen > 32
556
- raise InvalidPrefixError, "invalid length: #{@addr}"
621
+ raise InvalidPrefixError, "invalid length"
557
622
  end
558
623
  masklen = 32 - prefixlen
559
624
  @mask_addr = ((IN4MASK >> masklen) << masklen)
560
625
  when Socket::AF_INET6
561
626
  if prefixlen < 0 || prefixlen > 128
562
- raise InvalidPrefixError, "invalid length: #{@addr}"
627
+ raise InvalidPrefixError, "invalid length"
563
628
  end
564
629
  masklen = 128 - prefixlen
565
630
  @mask_addr = ((IN6MASK >> masklen) << masklen)
@@ -639,6 +704,7 @@ class IPAddr
639
704
  end
640
705
  end
641
706
 
707
+ # :stopdoc:
642
708
  def coerce_other(other)
643
709
  case other
644
710
  when IPAddr
@@ -655,12 +721,12 @@ class IPAddr
655
721
  when Array
656
722
  octets = addr
657
723
  else
658
- m = RE_IPV4ADDRLIKE.match(addr) or return nil
659
- octets = m.captures
724
+ RE_IPV4ADDRLIKE.match?(addr) or return nil
725
+ octets = addr.split('.')
660
726
  end
661
727
  octets.inject(0) { |i, s|
662
- (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address: #{@addr}"
663
- s.match(/\A0./) and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{@addr}"
728
+ (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address: #{addr}"
729
+ (s != '0') && s.start_with?('0') and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{addr}"
664
730
  i << 8 | n
665
731
  }
666
732
  end
@@ -750,7 +816,7 @@ unless Socket.const_defined? :AF_INET6
750
816
  class << IPSocket
751
817
  private
752
818
 
753
- def valid_v6?(addr)
819
+ def valid_v6?(addr) # :nodoc:
754
820
  case addr
755
821
  when IPAddr::RE_IPV6ADDRLIKE_FULL
756
822
  if $2
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ipaddr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.6
4
+ version: 1.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akinori MUSHA
8
8
  - Hajimu UMEMOTO
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-12-16 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: |
15
14
  IPAddr provides a set of methods to manipulate an IP address.
@@ -23,14 +22,12 @@ extra_rdoc_files: []
23
22
  files:
24
23
  - LICENSE.txt
25
24
  - README.md
26
- - ipaddr.gemspec
27
25
  - lib/ipaddr.rb
28
26
  homepage: https://github.com/ruby/ipaddr
29
27
  licenses:
30
28
  - Ruby
31
29
  - BSD-2-Clause
32
30
  metadata: {}
33
- post_install_message:
34
31
  rdoc_options: []
35
32
  require_paths:
36
33
  - lib
@@ -38,15 +35,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
38
35
  requirements:
39
36
  - - ">="
40
37
  - !ruby/object:Gem::Version
41
- version: '2.3'
38
+ version: '2.4'
42
39
  required_rubygems_version: !ruby/object:Gem::Requirement
43
40
  requirements:
44
41
  - - ">="
45
42
  - !ruby/object:Gem::Version
46
43
  version: '0'
47
44
  requirements: []
48
- rubygems_version: 3.5.0.dev
49
- signing_key:
45
+ rubygems_version: 3.6.9
50
46
  specification_version: 4
51
47
  summary: A class to manipulate an IP address in ruby
52
48
  test_files: []
data/ipaddr.gemspec DELETED
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
- # coding: utf-8
3
-
4
- if File.exist?(File.expand_path("ipaddr.gemspec"))
5
- lib = File.expand_path("../lib", __FILE__)
6
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
7
-
8
- file = File.expand_path("ipaddr.rb", lib)
9
- else
10
- # for ruby-core
11
- file = File.expand_path("../ipaddr.rb", __FILE__)
12
- end
13
-
14
- version = File.foreach(file).find do |line|
15
- /^\s*VERSION\s*=\s*["'](.*)["']/ =~ line and break $1
16
- end
17
-
18
- Gem::Specification.new do |spec|
19
- spec.name = "ipaddr"
20
- spec.version = version
21
- spec.authors = ["Akinori MUSHA", "Hajimu UMEMOTO"]
22
- spec.email = ["knu@idaemons.org", "ume@mahoroba.org"]
23
-
24
- spec.summary = %q{A class to manipulate an IP address in ruby}
25
- spec.description = <<-'DESCRIPTION'
26
- IPAddr provides a set of methods to manipulate an IP address.
27
- Both IPv4 and IPv6 are supported.
28
- DESCRIPTION
29
- spec.homepage = "https://github.com/ruby/ipaddr"
30
- spec.licenses = ["Ruby", "BSD-2-Clause"]
31
-
32
- spec.files = ["LICENSE.txt", "README.md", "ipaddr.gemspec", "lib/ipaddr.rb"]
33
- spec.require_paths = ["lib"]
34
-
35
- spec.required_ruby_version = ">= 2.3"
36
- end