Skip to content

Instantly share code, notes, and snippets.

@alainwolf
Last active December 19, 2023 22:35
Show Gist options
  • Save alainwolf/7bb8571e98e3ac08be1b526d08c51a3c to your computer and use it in GitHub Desktop.
Save alainwolf/7bb8571e98e3ac08be1b526d08c51a3c to your computer and use it in GitHub Desktop.
Make SSH use my IPv4 jump host only if the target host is unreachable by IPv6
# /etc/ssh/ssh_config
#
# All my hosts are reachable by IPv6 only. IPv6 addresses don't get spammed with SSH login probes.
# But what if I need to connect from a network which has no IPv6 enabled?
# Setup an SSH jump host which is reachable over IPv4 and use that only if the target host is unreachable by IPv6
#
Match host *.example.net,!ipv4.example.net !exec "ip route get $(host %h | grep 'IPv6 address' | awk '{print $NF}') &> /dev/null"
ProxyJump ipv4.example.net
@alainwolf
Copy link
Author

This snippet is part of an SSH client configuration using the ~/.ssh/config or /etc/ssh/ssh_configfile.

It makes use of the Match directive to conditionally apply configuration settings based on the host being connected to. Let's break down the snippet:

  • Match host *.example.net,!ipv4.example.net: This line specifies that the following configuration block should only apply to hosts matching the pattern *.example.net and not matching ipv4.example.net. The ! symbol is used for negation.

Let's delve into the ip route get command in the exec part of the configuration. This command is used to determine the route information for a given IP address. Here's a detailed breakdown of that portion:

ip route get $(host %h | grep 'IPv6 address' | awk '{print $NF}') &> /dev/null
  • host %h: This command resolves the hostname (%h) to an IP address using DNS. The output includes information about both IPv4 and IPv6 addresses.

  • grep 'IPv6 address': This filters the output to only include lines containing 'IPv6 address'. This is done to focus on the IPv6 address if it exists.

  • awk '{print $NF}': This uses awk to print the last field of the line, which should be the IPv6 address.

  • $(...): This is command substitution. The result of the command within the parentheses is substituted into the overall command.

  • ip route get ...: This part of the command uses the ip route get command to determine the routing information for the extracted IPv6 address. It is a way to check if there is a route to the given address.

  • &> /dev/null: This redirects both standard output and standard error to /dev/null, effectively suppressing any output. The command is used for its exit status to determine if a route to the IPv6 address exists.

The entire line is enclosed in !exec, which means that the Match block will match if the exit status of the command is non-zero, indicating that there is no valid route to the IPv6 address. This is essentially a way to conditionally match hosts that do not have a valid IPv6 route.

In summary, this part of the configuration is checking if the host has an IPv6 address and if there is a valid route to that address. If not, the Match block will be considered a match, and the specified configuration (in this case, the ProxyJump to ipv4.example.net) will be applied.

Detailed explanation courtesy of ChatGPT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment