On Thu, Oct 29, 2026 at 11:58:14PM -0400, Laine Stump wrote:
> On 10/26/26 8:18 AM, Daniel P. Berrangé via Devel wrote:
> > From: Daniel P. Berrangé <[email protected]>
> > 
> > Hostnames must comply with certain rules about maximum length
> > and permitted characters. Since these need to be validated in
> > several places, introduce a helper to centralize the rules
> > and provide testing.
> > 
> > Signed-off-by: Daniel P. Berrangé <[email protected]>
> > ---
> >   src/libvirt_private.syms |  1 +
> >   src/util/virutil.c       | 50 ++++++++++++++++++++++++++++
> >   src/util/virutil.h       |  2 ++
> >   tests/utiltest.c         | 72 ++++++++++++++++++++++++++++++++++++++++
> >   4 files changed, 125 insertions(+)
> > 
> > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> > index 798d2d28c8..66520a3e35 100644
> > --- a/src/libvirt_private.syms
> > +++ b/src/libvirt_private.syms
> > @@ -3791,6 +3791,7 @@ virGetUserRuntimeDirectory;
> >   virGetUserShell;
> >   virHostGetDRMRenderNode;
> >   virHostHasIOMMU;
> > +virHostnameValidate;
> >   virIndexToDiskName;
> >   virKernelCmdlineMatchParam;
> >   virKernelCmdlineNextParam;
> > diff --git a/src/util/virutil.c b/src/util/virutil.c
> > index 2be9a460ac..75ecb6da5a 100644
> > --- a/src/util/virutil.c
> > +++ b/src/util/virutil.c
> > @@ -1979,3 +1979,53 @@ virPipeNonBlock(int fds[2])
> >   {
> >       return virPipeImpl(fds, true, true);
> >   }
> > +
> > +#define VIR_HOSTNAME_VALID_CHARS \
> > +    "abcdefghijklmnopqrstuvwxyz" \
> > +    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
> > +    "0123456789-"
> > +
> > +int virHostnameValidate(const char *hostname, bool qualified)
> > +{
> > +    g_auto(GStrv) labels = g_strsplit(hostname, ".", -1);
> > +    size_t i;
> > +
> > +    if (!qualified && g_strv_length(labels) > 1) {
> > +        virReportError(VIR_ERR_INVALID_ARG,
> > +                       _("Hostname '%1$s' must not be qualified"),
> > +                       hostname);
> > +        return -1;
> > +    }
> > +    if (strlen(hostname) > 253) {
> > +        virReportError(VIR_ERR_INVALID_ARG,
> > +                       _("Hostname '%1$s' must be 253 characters or less"),
> > +                       hostname);
> > +        return -1;
> > +    }
> > +
> > +    for (i = 0; labels[i] != NULL; i++) {
> > +        size_t labellen = strlen(labels[i]);
> > +        if (labellen == 0) {
> > +            virReportError(VIR_ERR_INVALID_ARG,
> > +                           _("Hostname '%1$s' components must be 
> > non-empty"),
> > +                           hostname);
> > +            return -1;
> > +        }
> > +
> > +        if (labellen > 63) {
> > +            virReportError(VIR_ERR_INVALID_ARG,
> > +                           _("Hostname '%1$s' components must be 63 
> > characters or less"),
> > +                           hostname);
> > +            return -1;
> > +        }
> > +
> > +        if (strspn(labels[i],
> > +                   VIR_HOSTNAME_VALID_CHARS) != labellen) {
> > +            virReportError(VIR_ERR_INVALID_ARG,
> > +                           _("Hostname '%1$s' components must only contain 
> > a-z, A-Z, 0-9 and -"),
> > +                           hostname);
> > +            return -1;
> > +        }
> 
> 1) Additionally, although a hostname is now allowed to start with a number
> (originally it wasn't), it cannot start or end with a "-" (more
> specifically, each individual label cannot start or end with a "-".

Ok, we need the '-' validation.

Also for TXT/SRV records I need to allow a leading '_' 

> 2) In general, a domainname's octets can't be interpreted or limited by a
> DNS server; that is declared to be the responsibility of the application
> that is actually using the information. (e.g. a DNS A or AAAA record key can
> completely legitimately contain a "_", or any other character and the DNS
> server is supposed to accept that and forward it on or whatever). It's only
> when an application decides to use a domainname.
> 
> And actually I've been reading RFC2181 for the first time and section 11
> says "any binary string whatever can be used as the label of any resource
> record" (after first listing the length limitations you've checked for
> above). It also says "DNS server must not refuse to serve a zone because it
> contains labels that might not be acceptable to some DNS client programs"
> (oddly the "must" isn't capitalized, which has always had a special meaning
> in RFCs (at least to me).
> (https://www.rfc-editor.org/info/rfc2181/#section-11). So technically we
> *could* allow anything in a hostname and rely on the receiving client to
> validate. Not that I'm suggesting that, I just found it interesting that was
> the case :-)
> 
> 3) I was curious about what happens with hostnames/domain names containing
> international characters. I've known for several years that it's now
> supported, but never looked at the details before. This is my chance!
> 
> So, on the wire, only the characters you've specified are supported (in a
> hostname), and any character beyond 0x80 will cause the name to be
> translated into "Punycode"[*], which I won't try to describe fully, but it
> ends up with a string that starts with "xn--" and then does a special
> encoding of the source string that I'll let you look up for yourself.
> 
> We *could* just say that libvirt only allows using the Punycode-encoded
> version of international hostnames in its config files (and thus your
> validation would remain the same, but with addition of checking leading and
> trailing "-"), but dnsmasq actually has support for international characters
> in hostnames and domainnames in its config files, and will automatically
> translate any hostname/domainname with non-ascii characters to Punycode
> before putting it on the wire. And certainly it would be much easier to
> recognize:
> 
>    mötleycrüe.com
> 
> in the config file rather than
> 
>    xn-mtleycre-n4a5pc.com
> 
> :-P. (and possibly there are even already people doing this in their libvirt
> config files, so adding the validation as you've written it could break
> someone's setup.)

Yes, you're right, we must not restrict what is already permitted
by dnsmasq. What matters is that we don't break the config file
format ultimately.

I guess I need to throw most of this away and just allow anything that
is not whitespace, or control characters.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|

Reply via email to