From 2275684fd49b8ac0e6b8ba0a3f06de0cf99c04e7 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 10 Feb 2026 10:55:12 -0300 Subject: [PATCH] Enhance hostname validation and update help text in forms.py --- dns/forms.py | 32 ++++++++++++++++++++++++-------- dns/functions.py | 7 +++---- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/dns/forms.py b/dns/forms.py index 37a4309..1f515ed 100644 --- a/dns/forms.py +++ b/dns/forms.py @@ -63,7 +63,7 @@ class StaticHostForm(forms.ModelForm): self.helper = FormHelper() self.helper.form_method = 'post' self.fields['hostname'].label = _('Hostname') - self.fields['hostname'].help_text = _('Hostname or wildcard domain (e.g. *.example.com)') + self.fields['hostname'].help_text = _('Exact hostname or domain rule (e.g. *.example.com matches example.com and all subdomains)') self.fields['ip_address'].label = _('IP Address') back_label = _('Back') delete_label = _('Delete') @@ -77,7 +77,7 @@ class StaticHostForm(forms.ModelForm): Div( Field('hostname', css_class='form-control'), Field('ip_address', css_class='form-control'), - css_class='col-md-6' + css_class='col-md-12' ), ), FormActions( @@ -90,12 +90,28 @@ class StaticHostForm(forms.ModelForm): def clean(self): cleaned_data = super().clean() hostname = cleaned_data.get('hostname') - if hostname: - # Allow plain hostname (e.g. example.com) or wildcard (e.g. *.example.com) - plain_regex = r'^[a-zA-Z0-9]([a-zA-Z0-9-\.]*[a-zA-Z0-9])?$' - wildcard_regex = r'^\*\.([a-zA-Z0-9]([a-zA-Z0-9-\.]*[a-zA-Z0-9])?)$' - if not (re.match(plain_regex, hostname) or re.match(wildcard_regex, hostname)): - raise ValidationError(_('Invalid hostname. Use a hostname (e.g. example.com) or wildcard (e.g. *.example.com).')) + if not hostname: + raise ValidationError(_('Invalid hostname.')) + + hostname = hostname.strip().lower() + if '://' in hostname or '/' in hostname or ':' in hostname: + raise ValidationError(_('Invalid hostname.')) + + domain = hostname[2:] if hostname.startswith('*.') else hostname + labels = domain.split('.') + + if len(labels) < 2: + raise ValidationError(_('Invalid hostname.')) + + for label in labels: + if not label: + raise ValidationError(_('Invalid hostname.')) + if not re.match(r'^[a-z0-9-]+$', label): + raise ValidationError(_('Invalid hostname.')) + if label.startswith('-') or label.endswith('-'): + raise ValidationError(_('Invalid hostname.')) + + cleaned_data['hostname'] = hostname return cleaned_data diff --git a/dns/functions.py b/dns/functions.py index 1f8281e..00ddff0 100644 --- a/dns/functions.py +++ b/dns/functions.py @@ -124,12 +124,11 @@ bind-interfaces if static_hosts: dnsmasq_config += '\n' for static_host in static_hosts: - # dnsmasq uses /.example.com/ for wildcards (matches *.example.com and example.com) + hostname = static_host.hostname.strip().lower() if static_host.hostname.startswith('*.'): - dnsmasq_domain = '.' + static_host.hostname[2:] + dnsmasq_config += f'address=/{hostname[1:]}/{static_host.ip_address}\n' else: - dnsmasq_domain = static_host.hostname - dnsmasq_config += f'address=/{dnsmasq_domain}/{static_host.ip_address}\n' + dnsmasq_config += f'host-record={hostname},{static_host.ip_address}\n' if dns_lists: dnsmasq_config += '\n'