ipaddr 1.2.5 → 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
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