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 :|
