1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Sanitize IPv6 hostname/port handling

Now we accept IPv6 addresses _with port numbers_ only in the standard
[xxx]:NN notation (though bare IPv6 addresses may be given, as before,
and non-IPv6 addresses may also be placed in square brackets), and any
other host identifiers (IPv4/hostname/host pattern) as before, with an
optional :NN suffix.
This commit is contained in:
Abhijit Menon-Sen 2015-08-20 22:03:22 +05:30
parent 74aab6f726
commit 745ecd4845

View file

@ -250,43 +250,36 @@ class InventoryParser(object):
return hosts return hosts
def _expand_hostpattern(self, pattern): def _expand_hostpattern(self, hostpattern):
''' '''
Takes a single host pattern and returns a list of hostnames and an Takes a single host pattern and returns a list of hostnames and an
optional port number that applies to all of them. optional port number that applies to all of them.
''' '''
# First, we extract the port number. This is usually ":NN" at the end of # Is a port number specified?
# the expression, but for IPv6 addresses it's ".NN" instead. In either #
# case, we remove it. # This may be a mandatory :NN suffix on any square-bracketed expression
# (IPv6 address, IPv4 address, host name, host pattern), or an optional
# :NN suffix on an IPv4 address, host name, or pattern. IPv6 addresses
# must be in square brackets if a port is specified.
port = None port = None
if ':' in pattern:
pos = pattern.rindex(':') for type in ['bracketed_hostport', 'hostport']:
try: m = self.patterns[type].match(hostpattern)
port = int(pattern[pos+1:])
pattern = pattern[0:pos]
except ValueError:
pass
else:
m = self.patterns['ipv6_hostport'].match(pattern)
if m: if m:
(pattern, port) = m.groups() (hostpattern, port) = m.groups()
continue
# We're done, because we know this is a single IPv6 address.
# But should we support ranges for IPv6 address generation?
# See the FIXME note below. We should probably just accept
# "[xxx]:nn" syntax instead, and then let xxx be expanded.
return ([pattern], int(port))
# Now we're left with just the pattern, which results in a list of one # Now we're left with just the pattern, which results in a list of one
# or more hostnames, depending on whether it contains any [x:y] ranges. # or more hostnames, depending on whether it contains any [x:y] ranges.
#
# FIXME: We could be more strict here about validation.
if detect_range(pattern): if detect_range(hostpattern):
hostnames = expand_hostname_range(pattern) hostnames = expand_hostname_range(hostpattern)
else: else:
hostnames = [pattern] hostnames = [hostpattern]
return (hostnames, port) return (hostnames, port)
@ -362,7 +355,7 @@ class InventoryParser(object):
# should they be? At the moment, they must be non-empty sequences of non # should they be? At the moment, they must be non-empty sequences of non
# whitespace characters excluding ':' and ']', but we should define more # whitespace characters excluding ':' and ']', but we should define more
# precise rules in order to support better diagnostics. The same applies # precise rules in order to support better diagnostics. The same applies
# to hostnames. # to hostnames. It seems sensible for them both to follow DNS rules.
self.patterns['groupname'] = re.compile( self.patterns['groupname'] = re.compile(
r'''^ r'''^
@ -373,18 +366,28 @@ class InventoryParser(object):
''', re.X ''', re.X
) )
# This matches an IPv6 address, a '.', and a port number. It's not yet # The following patterns match the various ways in which a port number
# very strict about matching the IPv6 address. # may be specified on an IPv6 address, IPv4 address, hostname, or host
# # pattern. All of the above may be enclosed in square brackets with a
# FIXME: There are various shortcomings in the IPv6 handling in the # mandatory :NN suffix; or all but the first may be given without any
# old code, which aren't fixed here yet. For example, Inventory's # brackets but with an :NN suffix.
# parse_inventory() method seems to accept "[ipv6]:nn" syntax. We
# should pick one and stick with it.
self.patterns['ipv6_hostport'] = re.compile( self.patterns['bracketed_hostport'] = re.compile(
r'''^ r'''^
([a-fA-F0-9:]+) \[(.+)\] # [host identifier]
\.([0-9]+) :([0-9]+) # :port number
$
''', re.X
)
self.patterns['hostport'] = re.compile(
r'''^
((?: # We want to match:
[^:\[\]] # (a non-range character
| # ...or...
\[[^\]]*\] # a complete bracketed expression)
)*) # repeated as many times as possible
:([0-9]+) # followed by a port number
$ $
''', re.X ''', re.X
) )