1. Introduction
Under Linux, the kernel, most native filesystems, and packages employ case sensitivity. However, that isn’t always true.
In this tutorial, we explore case sensitivity and how it affects hostnames in particular. First, we define case sensitivity in general, providing some examples. Next, we discuss different types of system identifiers. After that, we turn to case sensitivity during their resolution. Finally, we briefly discuss problems with resolving names connected with the letter case.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.
2. Case Sensitivity
Basically, case sensitivity means distinguishing between letter cases, i.e., lowercase and uppercase. In other words, to be case-sensitive is to know and consider whether any given character is a capital letter or not.
For example, the strings CASE SENSITIVE and case sensitive differ if we take the letter case into account but don’t otherwise.
Let’s see this in Bash:
$ [ 'CASE SENSITIVE' == 'case sensitive' ] && echo 'Same.' || echo 'Different.'
Different.
$ [ 'case sensitive' == 'case sensitive' ] && echo 'Same.' || echo 'Different.'
Same.
Here, we use a conditional expression shorthand with && and || to echo whether two strings are the Same or Different. So, Bash is case-sensitive by default.
Still, we might want to make a comparison without considering the case. For this, we can use the shopt built-in:
$ shopt -s nocasematch
$ [[ 'Case Sensitive' == 'case sensitive' ]] && echo 'Same.' || echo 'Different.'
Same.
$ shopt -u nocasematch
$ [[ 'Case Sensitive' == 'case sensitive' ]] && echo 'Same.' || echo 'Different.'
Different.
By setting (-s) nocasematch, we turn off the case sensitivity while -u reverts back. Notably, we use the Bash-specific [[]], since [] is compliant with the POSIX shell standard and is unaffected.
Further, POSIX defines case sensitivity as the norm. Moreover, implementations in many areas consider this for different strings:
- filenames
- variable, function, and other programming object names
- usernames and passwords
- data and metadata searching
- Uniform Resource Identifier (URL) and Uniform Resource Locator (URI) strings
Notably, the last point means networking is also influenced.
3. System Identification
Systems can have many identifiers:
- custom system-local names
- physical names, name tags, serial numbers, and similar
- numeric network address like Media Access Control (MAC) and Internet Protocol (IP)
- system-local networking name and address like localhost and 127.0.0.1
- local network names like NetBIOS and Avahi
- application-specific names and addresses like those for the Domain Name System (DNS), Simple Network Management Protocol (SNMP), and Secure Shell (SSH)
Yet, some of these are mainly useful to machines.
3.1. Physical Names
Naturally, we can use our own personal naming convention for any object. On top of that, computer components and configurations commonly have associated identifiers like serial numbers, brand names, model codes, and similar.
Although they’re usually printed on labels and the components themselves, we can also get some of the hardware identifiers within Linux.
3.2. Numeric Addresses
While IP and MAC addresses are typical for most network environments, they are by far not the only options.
For example, there are also telephone numbers, arcnet, pronet, X.25, netrom addresses, and others.
3.3. Hostnames and DNS Names
Of course, the predominant names that humans use and remember are DNS names and local hostnames.
In Linux, these usually come from one of the two major DNS resolution mechanisms and the content of /etc/hostname file as set via hostnamectl. There are also technologies like Avahi, which provide zero configuration options.
In most cases, we can use an IP address and its associated names interchangeably.
3.4. Custom Names
Protocols like SSH have options to use custom names.
In fact, we can do a simple implementation of our own using Bash associative arrays:
$ declare -A namemap=(["baeldung"]="192.168.6.66" ["xost"]="192.168.6.10" ["central"]="203.0.113.1")
$ echo ${namemap["xost"]}
192.168.6.10
Obviously, this implementation is case-sensitive. Let’s see whether that’s the norm for Linux.
4. Names of Hosts and Letter Case in Linux
While general adherence to POSIX is usual for UNIX, hostnames aren’t a Linux-specific concept.
In fact, there are guidelines for host naming and the valid characters in hostnames, as originally outlined in the RFC 952 DoD Internet Host Table Specification. Critically, the latter includes a statement about letter case: No distinction is made between upper and lower case. This general consensus benefits end-users which simply use web browsers, for example.
While the above Request for Comments (RFC) from 1985 can be seen as archaic, it still holds true today in most environments, so DNS names and hostnames are case-insensitive by default.
4.1. Hostnames
Let’s see an example with the simple local hosts file in Linux:
$ cat /etc/hosts
127.0.0.1 xost
127.0.0.2 Xost
$ ping Xost
PING xost (127.0.0.1) 56(84) bytes of data.
[...]
Since ping uses the first entry that matches, we can deduce xost is the same as Xost as far as our resolution mechanism is concerned. To verify, we can remove one and ping the other:
$ cat /etc/hosts
127.0.0.2 Xost
$ ping xost
PING Xost (127.0.0.2) 56(84) bytes of data.
[...]
Barring any caching, we still get a match of Xost for xost, but to the leftover address. What about the global DNS?
4.2. DNS Names
Now, let’s confirm all DNS names are case-insensitive, as also specified by RFC 4343 – Domain Name System (DNS) Case Insensitivity Clarification:
$ ping BAELDUNG.com
PING BAELDUNG.com (198.51.100.10) 56(84) bytes of data.
[...]
$ ping baeldung.COM
PING baeldung.COM (198.51.100.10) 56(84) bytes of data.
[...]
So, the main names humans use for systems aren’t usually case-sensitive. Let’s explore alternatives.
4.3. Application Implementations
On the application layer, some protocols support their own name resolution mechanisms. For example, the SSH Host statement in the client configuration file can assign hostnames to groups of statements:
Host xost
HostName 192.168.6.66
User x
Port 22
IdentityFile /x/key
Here, we map the SSH-internal xost to the actual IP 192.168.6.66, but that could have also been another hostname, e.g., from /etc/hosts, instead of the numeric address.
In fact, the ssh_config manual includes a note right above the description of Host declarations: keywords are case-insensitive, and arguments are case-sensitive. Basically, this means that the Host and HostName keywords must be written exactly, but their arguments will be matched case-insensitively.
5. Resolution and Case Sensitivity
There can be different name resolution issues. For example, DNS caching can get the results of hosts with new addresses mixed up with their old ones.
This might even lead to the often wrongful assumption that names are case-sensitive.
Naturally, we can implement our own case-sensitive DNS server, but it wouldn’t adhere to the standards. Resolving xost and Xost differently can lead to a lot of confusion. Yet, this can happen in some instances:
- server implementation, e.g., DNS resolution based on case-sensitive database queries
- client implementation
- tool implementation, e.g., older getent versions were case-sensitive
Notably, in most cases, it’s the particular way a given piece of software was developed that makes it ignore the standard.
6. Summary
In this article, we looked at types of system identifiers, numeric address to name resolution, and whether the latter is case-sensitive.
In conclusion, while all major standards state that name resolution shouldn’t be case-sensitive, particular implementations can ignore them.