ipaddr 1.2.5 → 1.2.7

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 +92 -34
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06fb862bc853927b4eb39fd9026c6c8ad873faa1a68f9c39273dc138f7eb0d37
4
- data.tar.gz: 67115eb06827bcde6f1639535494f5b190529b127577af48f76ae3bf4886110c
3
+ metadata.gz: 566f76e26928f5a6014a11f985f08d1299dd06e7cb273cbc90b2553182b90006
4
+ data.tar.gz: f966e0490212bdb9194d05e6ee1d7e8df85ce622ed3692c46b2539c648e0315f
5
5
  SHA512:
6
- metadata.gz: 1e75fe29c69c244547d966127f1fd98b38352ad562ac2c5b2cdbb301374d390b99ab81f8bdc976f23668df2cfe9b03872a8fef559769f474668936bea5f219c2
7
- data.tar.gz: 62a69ec4cdbe84424750ec9b1947a4d6184bf835db3cc3a1053da8e646c7df5557ae9ba36c9943e827f6c3d4e238127d5d1ce6fab89b4bdf482dcd58753e0134
6
+ metadata.gz: 02e29f8adc3da01f5db2c02101dab218015ab78c9b628060945bbbf328e10391962afd254c0ce5cb9d6a86d68486120f9298673ca9ff133325fd7df700804af6
7
+ data.tar.gz: b14fd4218bfdb839dee0fa22a334a217a39a8493ea9e7977684a0418819a337386727d0c47f67868848d018e7f7659f52dabeef686e20ad948a462683915d69c
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,7 @@ 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.5"
43
+ VERSION = "1.2.7"
44
44
 
45
45
  # 32 bit mask for IPv4
46
46
  IN4MASK = 0xffffffff
@@ -52,7 +52,7 @@ class IPAddr
52
52
  # Regexp _internally_ used for parsing IPv4 address.
53
53
  RE_IPV4ADDRLIKE = %r{
54
54
  \A
55
- (\d+) \. (\d+) \. (\d+) \. (\d+)
55
+ \d+ \. \d+ \. \d+ \. \d+
56
56
  \z
57
57
  }x
58
58
 
@@ -110,8 +110,13 @@ class IPAddr
110
110
 
111
111
  # Convert a network byte ordered string form of an IP address into
112
112
  # human readable form.
113
+ # It expects the string to be encoded in Encoding::ASCII_8BIT (BINARY).
113
114
  def self.ntop(addr)
114
- case addr.size
115
+ if addr.is_a?(String) && addr.encoding != Encoding::BINARY
116
+ raise InvalidAddressError, "invalid encoding (given #{addr.encoding}, expected BINARY)"
117
+ end
118
+
119
+ case addr.bytesize
115
120
  when 4
116
121
  addr.unpack('C4').join('.')
117
122
  when 16
@@ -176,9 +181,7 @@ class IPAddr
176
181
  def include?(other)
177
182
  other = coerce_other(other)
178
183
  return false unless other.family == family
179
- range = to_range
180
- other = other.to_range
181
- range.begin <= other.begin && range.end >= other.end
184
+ begin_addr <= other.begin_addr && end_addr >= other.end_addr
182
185
  end
183
186
  alias === include?
184
187
 
@@ -224,6 +227,28 @@ class IPAddr
224
227
  return str
225
228
  end
226
229
 
230
+ # Returns a string containing the IP address representation with prefix.
231
+ def as_json(*)
232
+ if ipv4? && prefix == 32
233
+ to_s
234
+ elsif ipv6? && prefix == 128
235
+ to_s
236
+ else
237
+ cidr
238
+ end
239
+ end
240
+
241
+ # Returns a json string containing the IP address representation.
242
+ def to_json(*a)
243
+ %Q{"#{as_json(*a)}"}
244
+ end
245
+
246
+ # Returns a string containing the IP address representation in
247
+ # cidr notation
248
+ def cidr
249
+ "#{to_s}/#{prefix}"
250
+ end
251
+
227
252
  # Returns a network byte ordered string form of the IP address.
228
253
  def hton
229
254
  case @family
@@ -249,12 +274,17 @@ class IPAddr
249
274
  end
250
275
 
251
276
  # Returns true if the ipaddr is a loopback address.
277
+ # Loopback IPv4 addresses in the IPv4-mapped IPv6
278
+ # address range are also considered as loopback addresses.
252
279
  def loopback?
253
280
  case @family
254
281
  when Socket::AF_INET
255
- @addr & 0xff000000 == 0x7f000000
282
+ @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
256
283
  when Socket::AF_INET6
257
- @addr == 1
284
+ @addr == 1 || # ::1
285
+ (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
286
+ @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
287
+ ))
258
288
  else
259
289
  raise AddressFamilyError, "unsupported address family"
260
290
  end
@@ -263,7 +293,8 @@ class IPAddr
263
293
  # Returns true if the ipaddr is a private address. IPv4 addresses
264
294
  # in 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 as defined in RFC
265
295
  # 1918 and IPv6 Unique Local Addresses in fc00::/7 as defined in RFC
266
- # 4193 are considered private.
296
+ # 4193 are considered private. Private IPv4 addresses in the
297
+ # IPv4-mapped IPv6 address range are also considered private.
267
298
  def private?
268
299
  case @family
269
300
  when Socket::AF_INET
@@ -271,22 +302,31 @@ class IPAddr
271
302
  @addr & 0xfff00000 == 0xac100000 || # 172.16.0.0/12
272
303
  @addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16
273
304
  when Socket::AF_INET6
274
- @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000
305
+ @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 ||
306
+ (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
307
+ @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8
308
+ @addr & 0xfff00000 == 0xac100000 || # ::ffff::172.16.0.0/12
309
+ @addr & 0xffff0000 == 0xc0a80000 # ::ffff::192.168.0.0/16
310
+ ))
275
311
  else
276
312
  raise AddressFamilyError, "unsupported address family"
277
313
  end
278
314
  end
279
315
 
280
316
  # Returns true if the ipaddr is a link-local address. IPv4
281
- # addresses in 169.254.0.0/16 reserved by RFC 3927 and Link-Local
317
+ # addresses in 169.254.0.0/16 reserved by RFC 3927 and link-local
282
318
  # IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are
283
- # considered link-local.
319
+ # considered link-local. Link-local IPv4 addresses in the
320
+ # IPv4-mapped IPv6 address range are also considered link-local.
284
321
  def link_local?
285
322
  case @family
286
323
  when Socket::AF_INET
287
324
  @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
288
325
  when Socket::AF_INET6
289
- @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
326
+ @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
327
+ (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
328
+ @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
329
+ ))
290
330
  else
291
331
  raise AddressFamilyError, "unsupported address family"
292
332
  end
@@ -400,17 +440,6 @@ class IPAddr
400
440
 
401
441
  # Creates a Range object for the network address.
402
442
  def to_range
403
- begin_addr = (@addr & @mask_addr)
404
-
405
- case @family
406
- when Socket::AF_INET
407
- end_addr = (@addr | (IN4MASK ^ @mask_addr))
408
- when Socket::AF_INET6
409
- end_addr = (@addr | (IN6MASK ^ @mask_addr))
410
- else
411
- raise AddressFamilyError, "unsupported address family"
412
- end
413
-
414
443
  self.class.new(begin_addr, @family)..self.class.new(end_addr, @family)
415
444
  end
416
445
 
@@ -439,7 +468,7 @@ class IPAddr
439
468
  when Integer
440
469
  mask!(prefix)
441
470
  else
442
- raise InvalidPrefixError, "prefix must be an integer: #{@addr}"
471
+ raise InvalidPrefixError, "prefix must be an integer"
443
472
  end
444
473
  end
445
474
 
@@ -464,6 +493,20 @@ class IPAddr
464
493
  _to_string(@mask_addr)
465
494
  end
466
495
 
496
+ # Returns the wildcard mask in string format e.g. 0.0.255.255
497
+ def wildcard_mask
498
+ case @family
499
+ when Socket::AF_INET
500
+ mask = IN4MASK ^ @mask_addr
501
+ when Socket::AF_INET6
502
+ mask = IN6MASK ^ @mask_addr
503
+ else
504
+ raise AddressFamilyError, "unsupported address family"
505
+ end
506
+
507
+ _to_string(mask)
508
+ end
509
+
467
510
  # Returns the IPv6 zone identifier, if present.
468
511
  # Raises InvalidAddressError if not an IPv6 address.
469
512
  def zone_id
@@ -491,6 +534,21 @@ class IPAddr
491
534
 
492
535
  protected
493
536
 
537
+ def begin_addr
538
+ @addr & @mask_addr
539
+ end
540
+
541
+ def end_addr
542
+ case @family
543
+ when Socket::AF_INET
544
+ @addr | (IN4MASK ^ @mask_addr)
545
+ when Socket::AF_INET6
546
+ @addr | (IN6MASK ^ @mask_addr)
547
+ else
548
+ raise AddressFamilyError, "unsupported address family"
549
+ end
550
+ end
551
+
494
552
  # Set +@addr+, the internal stored ip address, to given +addr+. The
495
553
  # parameter +addr+ is validated using the first +family+ member,
496
554
  # which is +Socket::AF_INET+ or +Socket::AF_INET6+.
@@ -498,11 +556,11 @@ class IPAddr
498
556
  case family[0] ? family[0] : @family
499
557
  when Socket::AF_INET
500
558
  if addr < 0 || addr > IN4MASK
501
- raise InvalidAddressError, "invalid address: #{@addr}"
559
+ raise InvalidAddressError, "invalid address: #{addr}"
502
560
  end
503
561
  when Socket::AF_INET6
504
562
  if addr < 0 || addr > IN6MASK
505
- raise InvalidAddressError, "invalid address: #{@addr}"
563
+ raise InvalidAddressError, "invalid address: #{addr}"
506
564
  end
507
565
  else
508
566
  raise AddressFamilyError, "unsupported address family"
@@ -529,12 +587,12 @@ class IPAddr
529
587
  else
530
588
  m = IPAddr.new(mask)
531
589
  if m.family != @family
532
- raise InvalidPrefixError, "address family is not same: #{@addr}"
590
+ raise InvalidPrefixError, "address family is not same"
533
591
  end
534
592
  @mask_addr = m.to_i
535
593
  n = @mask_addr ^ m.instance_variable_get(:@mask_addr)
536
594
  unless ((n + 1) & n).zero?
537
- raise InvalidPrefixError, "invalid mask #{mask}: #{@addr}"
595
+ raise InvalidPrefixError, "invalid mask #{mask}"
538
596
  end
539
597
  @addr &= @mask_addr
540
598
  return self
@@ -545,13 +603,13 @@ class IPAddr
545
603
  case @family
546
604
  when Socket::AF_INET
547
605
  if prefixlen < 0 || prefixlen > 32
548
- raise InvalidPrefixError, "invalid length: #{@addr}"
606
+ raise InvalidPrefixError, "invalid length"
549
607
  end
550
608
  masklen = 32 - prefixlen
551
609
  @mask_addr = ((IN4MASK >> masklen) << masklen)
552
610
  when Socket::AF_INET6
553
611
  if prefixlen < 0 || prefixlen > 128
554
- raise InvalidPrefixError, "invalid length: #{@addr}"
612
+ raise InvalidPrefixError, "invalid length"
555
613
  end
556
614
  masklen = 128 - prefixlen
557
615
  @mask_addr = ((IN6MASK >> masklen) << masklen)
@@ -647,12 +705,12 @@ class IPAddr
647
705
  when Array
648
706
  octets = addr
649
707
  else
650
- m = RE_IPV4ADDRLIKE.match(addr) or return nil
651
- octets = m.captures
708
+ RE_IPV4ADDRLIKE.match?(addr) or return nil
709
+ octets = addr.split('.')
652
710
  end
653
711
  octets.inject(0) { |i, s|
654
712
  (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address: #{@addr}"
655
- s.match(/\A0./) and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{@addr}"
713
+ (s != '0') && s.start_with?('0') and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{@addr}"
656
714
  i << 8 | n
657
715
  }
658
716
  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.5
4
+ version: 1.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akinori MUSHA
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-12-05 00:00:00.000000000 Z
12
+ date: 2024-10-19 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: |
15
15
  IPAddr provides a set of methods to manipulate an IP address.
@@ -45,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
45
45
  - !ruby/object:Gem::Version
46
46
  version: '0'
47
47
  requirements: []
48
- rubygems_version: 3.4.0.dev
48
+ rubygems_version: 3.5.21
49
49
  signing_key:
50
50
  specification_version: 4
51
51
  summary: A class to manipulate an IP address in ruby