Socket.gethostbyname respond with "<any>" and "<broadcast>" hosts #2111

Closed
wants to merge 4 commits into
from
View
@@ -357,8 +357,10 @@ def self.getaddrinfo(host, service = nil, family = 0, socktype = 0, protocol =
hints[:ai_protocol] = protocol
hints[:ai_flags] = flags
- if host && host.empty?
+ if host && (host.empty? || host == '<any>')
host = "0.0.0.0"
+ elsif host == '<broadcast>'
+ host = '255.255.255.255'
end
res_p = FFI::MemoryPointer.new :pointer
@@ -688,6 +690,32 @@ def self.gethostbyname(hostname)
addresses << a[3] if a[4] == family
end
+ addresses.map! do |addr|
@dbussink
dbussink Dec 31, 2012 Member

Could you explain what this code does? Personally I don't find it very readable, maybe there is a way we can make this cleaner / more obvious as to what it does?

@sdaubert
sdaubert Dec 31, 2012 Contributor

This code transforms a dotted IPv4 address into a packed address, as returned by MRI.
First, if addr seems to be an IPv4 address, each address byte is packed into string s. Else addr is returned unchanged.

Now, for packing, i think it should use pack:

$~[1..4].map(:to_i).pack("C*")

instead of

$~[1..4].each { |v| s << v.to_i.chr }
+ case addr
+ when /^\d+\.\d+\.\d+\.\d+$/
+ # IPv4 address
+ addr.split('.').map(&:to_i).pack('C*')
+ when /^::(ffff:)?(\d+\.\d+\.\d+\.\d+)$/i
+ # IPv4-mapped and IPv4-compatible IPv6 address
+ constant_bytes = "\x00" * 10
+ if $1
+ constant_bytes += "\xff" * 2
+ else
+ constant_bytes += "\x00" * 2
+ end
+ constant_bytes + $2.split('.').map(&:to_i).pack('C*')
+ else
+ # IPv6 address
+ left, right = addr.split('::')
+ right ||= ''
+ l = left.split(':')
+ r = right.split(':')
+ rest = 8 - l.size - r.size
+ ary = l + ['0'] * rest + r
+ ary.map { |v| v.to_i(16) }.pack('n8')
+ end
+ end
+
[hostname, alternatives.uniq, family] + addresses.uniq
end
@@ -1,2 +0,0 @@
-fails:Socket#gethostbyname returns broadcast address info for '<broadcast>'
-fails:Socket#gethostbyname returns broadcast address info for '<any>'