Open matsmcp opened 10 months ago
Internet hostnames are case-insensitive
No distinction is made between upper and lower case.
So technically PowerShell is not at fault for not preserving what does not need to be preserved.
See the section referring to the mapping of values, just after where it says
One interpretation is that by saying -Hostname
you have already provided the hostname
Have you tried -Computername
to map to -o Host
?
This is not about internet hostnames. Its about Host aliases in .SSH/config and they are case sensitive in OpenSSH (Both "native" on Ubuntu and the MS implementation). Therefore Powershell needs to preserve the case.
To repro. Create the following .ssh/config file
Host DC Hostname 127.0.0.1 or some other suitable ip/fqdn
now try:
SSH DC - it will work
SSH dc - it will fail proving that the config file is case sensitive.
With that established try: Enter-pssession -Hostname dc -it will fail since there is no alias for dc Enter-pssession -Hostname DC - it should work but it also fails and complain that it cant resolve dc (observe the lower case).
@PaulHigin assigned the bug label on the previous issue
I can confirm that PowerShell is not just passing through the hostname as provided but is using the lower case variant.
if ($IsWindows) {
$sshAuditPath = './psremoting-ssh.bat'
Set-Content $sshAuditPath -Value @'
@echo off
echo %*> ssh_audit.txt
ssh.exe %*
'@
} else {
$sshAuditPath = './psremoting-ssh'
Set-Content $sshAuditPath -Value @'
#!/usr/bin/env bash
echo "$@" > ssh_audit.txt
ssh "$@"
'@
chmod +x ./psremoting-ssh
}
$ExecutionContext.InvokeCommand.PostCommandLookupAction = {
param ($Command, $EA)
if ($Command -eq ($IsWindows ? 'ssh.exe' : 'ssh')) {
$EA.Command = Get-Command $sshAuditPath
}
}
try {
Invoke-Command -HostName Server2022.Domain.test -UserName vagrant -ScriptBlock { $env:USERPROFILE }
}
finally {
$ExecutionContext.InvokeCommand.PostCommandLookupAction = $null
}
Get-Content ssh_audit.txt
On both Windows and Linux the ssh_audit.txt
for the above has the following arguments set
-l vagrant -s server2022.domain.test powershell
We can see instead of using Server2022.Domain.test
it is using server2022.domain.test
. As mentioned by OP this breaks things in the ~/.ssh/config
file where you want to match a config entry. Even the original comment https://github.com/PowerShell/PowerShell/issues/15219#issuecomment-866320687 states that PowerShell should still preserve the case for this scenario.
The problem here is at https://github.com/PowerShell/PowerShell/blob/71ae6070c2ecfa27e4103894331ea94c616e6921/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs#L896-L897. By creating a Uri
object it will lowercase the hostname portion so uri.Host
is going to be changed here. The code will have to be adjusted to ensure the case is preserved while still extracting the username/port. You can see Uri doing this with
[Uri]::new("ssh://Foo.BaR").Host
# foo.bar
I set up a .ssh/config with two Host entries...
$ cat .ssh/config
Host BANANA
Hostname 10.1.2.9
Host banana
Hostname 10.1.2.1
And passing -Hostname BANANA
resolved to the second one, the 10.1.2.1 when using
Invoke-Command -Hostname BANANA -Command { /sbin/ifconfig -a | grep inet }
When using ComputerName it tried to use WSMan
Invoke-Command -ComputerName BANANA -Command { /sbin/ifconfig -a | grep inet }
Invoke-Command: This parameter set requires WSMan, and no supported WSMan client library was found. WSMan is either not installed or unavailable for this system.
You could argue that it is SSH that is at fault, for instance if I have
/etc/hosts with
10.1.2.1 BANANA
and do "ping banana"
I get
~# ping banana
PING BANANA (10.1.2.1) 56(84) bytes of data.
64 bytes from BANANA (10.1.2.1): icmp_seq=1 ttl=64 time=0.736 ms
64 bytes from BANANA (10.1.2.1): icmp_seq=2 ttl=64 time=0.662 ms
When I tried
ssh BANANA
and
ssh banana
they went to the different hosts, so SSH treats the host entry as case-sensitive but a real host entry in /etc/hosts is insensitive
According to the spec of the config file ssh_config
Host' Restricts the following declarations (up to the next Host keyword) to be only for those hosts that match one of the patterns given after the keyword. If more than one pattern is provided, they should be separated by whitespace. A single '*' as a pattern can be used to provide global defaults for all hosts. The host is the hostname argument given on the command line (i.e. the name is not converted to a canonicalized host name before matching).
See PATTERNS for more information on patterns.
Host
is not a simple string, it is a regular expression. So you could put something which matches both upper case and lowercase in it.
@rhubarb-geek-nz
Once again - this is not about internet hostnames. The entire .ssh/config file and all of its keywords are defined by the OpenSSH project so no they do not break their own standard.
Etc/hosts contains internet hostnames. The keyword host in .ssh/config does not. Therefore you can't compare them or their functionality.
The keyword that contains internet hostnames in .ssh/config is HostName and that is case insensitive in compliance with rfc952.
The fault is caused by Powershell not following OpenSSH:s standard of preserving the case of SSH aliases. Adjusting Powershell so that it behaves as OpenSSH does fixes the problem.
Changing aliases because of Powershell not being in compliance with OpenSSH is not realistic. There are millions of current .ssh/config files and an unknown number of documents, scripts and in worst case compiled code that depends on current aliases
The Host field in .ssh/config is not really a hostname alias, it is a regular expression to match hostnames.
Changing aliases because of Powershell not being in compliance with OpenSSH is not realistic.
It might be because it means you can solve the problem right now and is a localised backward compatible fix, and most examples on the internet use lowercase for the host field so if you followed those you would not be affected.
It might be because it means you can solve the problem right now and is a localised backward compatible fix, and most examples on the internet use lowercase for the host field so if you followed those you would not be affected.
It can be a workaround while waiting for a fix if it's on a small scale, one config on one box - sure that's probably an easy workaround.
But make it 50K boxes -both Windows and Linux, a few thousand accounts (some service, some human accounts), a number of thousands of scripts, central config files that are included or copied from network shares and in worst case even compiled code that expects upper case names - Now it becomes a little harder ......
Therefore a code change is the better way to make sure that it will work in both cases. As you can see in #15219 it has been classed as a bug and bugs should preferably be fixed ;)
edit: fixed a few spelling errors
Ironically, when ssh does a proxy forward, it will lowercase the hostname...
Server FaultI'm using an SSH config file with a ProxyCommand to hop through a bastion host to my target host. Specifically, the ProxyCommand uses a cloud service CLI that takes the hostname / user / port I
OpenSSH is supposed to have a CanonicalizeHostname option, but have not been able to get it to work. When set to always it is supposed to make the hostname lowercase before the Host and Match field processing.
Prerequisites
Steps to reproduce
I found this one while working with a personal config file (.ssh/config) in my config I have an entry:
Host DC Hostname dc.example.org
if I run SSH DC it will work. if I try to do enter-pssession -hostname DC it will fail and complain that it cant resolve dc (observe the lower case). It seems like SSH preserves the case but enter-pssession doesn't.
Powershell 74.0 openssh 9.5 server 2022
It's the same bug as #15219 just updated for current Powershell and SSH
Expected behavior
Actual behavior
Error details
No response
Environment data
Visuals
No response