Commit 7479ab47 by Abhijit Menon-Sen

Be stricter about parsing hostname labels

Labels must start with an alphanumeric character, may contain
alphanumeric characters or hyphens, but must not end with a hyphen.
We enforce those rules, but allow underscores wherever hyphens are
accepted, and allow alphanumeric ranges anywhere.

We relax the definition of "alphanumeric" to include Unicode characters
even though such inventory hostnames cannot be used in practice unless
an ansible_ssh_host is set for each of them.

We still don't enforce length restrictions—the fact that we have to
accept ranges makes it more complex, and it doesn't seem especially
worthwhile.
parent 065bb521
...@@ -61,6 +61,17 @@ ipv4_component = r''' ...@@ -61,6 +61,17 @@ ipv4_component = r'''
) )
'''.format(range=numeric_range) '''.format(range=numeric_range)
# A hostname label, e.g. 'foo' in 'foo.example.com'. Consists of alphanumeric
# characters plus dashes (and underscores) or valid ranges. The label may not
# start or end with a hyphen or an underscore. This is interpolated into the
# hostname pattern below. We don't try to enforce the 63-char length limit.
label = r'''
(?:[\w]|{range}) # Starts with an alphanumeric or a range
(?:[\w_-]|{range})* # Then zero or more of the same or [_-]
(?<![_-]) # ...as long as it didn't end with [_-]
'''.format(range=alphanumeric_range)
patterns = { patterns = {
# This matches a square-bracketed expression with a port specification. What # This matches a square-bracketed expression with a port specification. What
# is inside the square brackets is validated later. # is inside the square brackets is validated later.
...@@ -138,14 +149,11 @@ patterns = { ...@@ -138,14 +149,11 @@ patterns = {
# 253 characters total) or make any attempt to process IDNs. # 253 characters total) or make any attempt to process IDNs.
'hostname': re.compile( 'hostname': re.compile(
r'''^ # We need at least one label, r'''^
(?: # which comprises: {label} # We must have at least one label
[a-z0-9_-]| # (a valid domain label character (?:\.{label})* # Followed by zero or more .labels
{0} # or a bracketed alphanumeric range)
)+
(?:\.(?:[a-z0-9_-]|{0})+)* # Followed by zero or more .labels
$ $
'''.format(alphanumeric_range), re.X|re.I '''.format(label=label), re.X|re.I|re.UNICODE
), ),
} }
......
# -*- coding: utf-8 -*-
import unittest import unittest
from ansible.parsing.utils.addresses import parse_address from ansible.parsing.utils.addresses import parse_address
...@@ -21,12 +23,19 @@ class TestParseAddress(unittest.TestCase): ...@@ -21,12 +23,19 @@ class TestParseAddress(unittest.TestCase):
'some-host:80': ['some-host', 80], 'some-host:80': ['some-host', 80],
'some.host.com:492': ['some.host.com', 492], 'some.host.com:492': ['some.host.com', 492],
'[some.host.com]:493': ['some.host.com', 493], '[some.host.com]:493': ['some.host.com', 493],
'a-b.3foo_bar.com:23': ['a-b.3foo_bar.com', 23],
u'fóöbär': [u'fóöbär', None],
u'fóöbär:32': [u'fóöbär', 32],
u'fóöbär.éxàmplê.com:632': [u'fóöbär.éxàmplê.com', 632],
# Various errors # Various errors
'': [None, None], '': [None, None],
'some..host': [None, None], 'some..host': [None, None],
'some.': [None, None], 'some.': [None, None],
'[example.com]': [None, None], '[example.com]': [None, None],
'some-': [None, None],
'some-.foo.com': [None, None],
'some.-foo.com': [None, None],
} }
range_tests = { range_tests = {
...@@ -34,7 +43,11 @@ class TestParseAddress(unittest.TestCase): ...@@ -34,7 +43,11 @@ class TestParseAddress(unittest.TestCase):
'192.0.2.[3:10]:23': ['192.0.2.[3:10]', 23], '192.0.2.[3:10]:23': ['192.0.2.[3:10]', 23],
'abcd:ef98::7654:[1:9]': ['abcd:ef98::7654:[1:9]', None], 'abcd:ef98::7654:[1:9]': ['abcd:ef98::7654:[1:9]', None],
'[abcd:ef98::7654:[6:32]]:2222': ['abcd:ef98::7654:[6:32]', 2222], '[abcd:ef98::7654:[6:32]]:2222': ['abcd:ef98::7654:[6:32]', 2222],
u'fóöb[a:c]r.éxàmplê.com:632': [u'fóöb[a:c]r.éxàmplê.com', 632],
'[a:b]foo.com': ['[a:b]foo.com', None],
'foo[a:b].com': ['foo[a:b].com', None],
'foo[a:b]:42': ['foo[a:b]', 42], 'foo[a:b]:42': ['foo[a:b]', 42],
'foo[a-b]-.com': [None, None],
'foo[a-b]:32': [None, None], 'foo[a-b]:32': [None, None],
'foo[x-y]': [None, None], 'foo[x-y]': [None, None],
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment