Automatically use jump proxy when initiating SSH connection from an external network.
Two years ago I have described how to match network inside SSH client configuration. Today, I will extend this technique to match specific network and perform DNS query to determine if a jump proxy is needed.
Prerequisites
Install utility to manage Python packages.
$ sudo apt install python3-pip
Install psutil
Python package.
$ pip3 install psutil
Collecting psutil Downloading psutil-5.8.0-cp39-cp39-manylinux2010_x86_64.whl (293 kB) |████████████████████████████████| 293 kB 1.2 MB/s Installing collected packages: psutil Successfully installed psutil-5.8.0
Create helper script
Create ~/.ssh/ipnetext.py
Python helper script.
#!/usr/bin/env python3 # SSH helper - Check if machine is in specific network and dns name is resolvable # Usage: ipnetext.py network # Example: ipnet.py 172.16.0.0/16 server.example.org # Exit codes: 0 - true, 1 - false (different network), 2 - false (same network, dns query failed) import ipaddress import socket import sys import psutil import dns.resolver for interface, snicaddrs in psutil.net_if_addrs().items(): for snicaddr in snicaddrs: if snicaddr.family is socket.AF_INET: if (ipaddress.ip_network(sys.argv[1], strict=False) == ipaddress.ip_network((snicaddr.address, snicaddr.netmask),strict=False)): try: dns.resolver.query(sys.argv[2],rdtype=dns.rdatatype.A,lifetime=1) except: exit(2) exit(0) exit(1)
Ensure that the executable bit is set.
$ chmod +x ~/.ssh/ipnetext.py
This helper script will be used to perform match operation as it will return true when the computer is in the specific network (provided by the first argument) and DNS query for the remote server (provided the second argument) will succeed.
SSH client configuration
The pi-hole.example.org
server is available and resolvable in 10.10.0.0/16
network, so the following configuration will ensure that the jump proxy will be defined when computer is outside of this network or the DNS query fails.
Match host pi-hole !exec "~/.ssh/ipnetext.py 10.10.0.0/16 %h.example.org" ProxyJump proxy.example.org User milosz Host pi-hole Hostname pi-hole.example.org User milosz Match user milosz IdentityFile ~/.ssh/milosz
Usage
Verify configuration within a defined network (do not use jump proxy).
$ ssh -A pi-hole -vv
OpenSSH_8.4p1 Ubuntu-5ubuntu1.1, OpenSSL 1.1.1j 16 Feb 2021 debug1: Reading configuration data /home/milosz/.ssh/config debug2: checking match for 'host pi-hole !exec "~/.ssh/ipnetext.py 10.10.0.0/16 %h.example.org"' host pi-hole originally pi-hole debug1: Executing command: '~/.ssh/ipnetext.py 10.10.0.0/16 pi-hole.example.org' debug2: match not found debug1: /home/milosz/.ssh/config line 136: Applying options for pi-hole debug2: checking match for 'user milosz' host pi-hole.example.org originally pi-hole debug2: match found debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files debug1: /etc/ssh/ssh_config line 21: Applying options for * debug2: resolving "pi-hole.example.org" port 22 debug2: ssh_connect_direct debug1: Connecting to pi-hole.example.org [10.10.2.1] port 22. debug1: Connection established. debug1: identity file /home/milosz/.ssh/milosz type 0 debug1: identity file /home/milosz/.ssh/milosz-cert type -1 debug1: Local version string SSH-2.0-OpenSSH_8.4p1 Ubuntu-5ubuntu1.1 debug1: Remote protocol version 2.0, remote software version OpenSSH_7.9p1 Raspbian-10+deb10u2+rpt1 debug1: match: OpenSSH_7.9p1 Raspbian-10+deb10u2+rpt1 pat OpenSSH* compat 0x04000000 debug2: fd 3 setting O_NONBLOCK debug1: Authenticating to pi-hole.example.org:22 as 'milosz' [...] Authenticated to pi-hole.example.org ([10.10.2.1]:22). [...] Linux DietPi 5.10.63-v7+ #1457 SMP Tue Sep 28 11:25:31 BST 2021 armv7l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Thu Oct 21 00:51:58 2021 from 10.10.10.254 milosz@DietPi:~ $
Verify configuration outside of a defined network (set jump proxy).
$ ssh -A pi-hole -vv
OpenSSH_8.4p1 Debian-5, OpenSSL 1.1.1k 25 Mar 2021 [195/1965] debug1: Reading configuration data /home/milosz/.ssh/config debug2: checking match for 'host pi-hole !exec "~/.ssh/ipnetext.py 10.10.0.0/16 %h.example.org"' host pi-hole originally pi-hole debug1: Executing command: '~/.ssh/ipnetext.py 10.10.0.0/16 pi-hole.example.org' debug2: match found debug1: /home/milosz/.ssh/config line 5: Applying options for pi-hole debug2: checking match for 'user milosz' host pi-hole.example.org originally pi-hole debug2: match found debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files debug1: /etc/ssh/ssh_config line 21: Applying options for * debug1: Setting implicit ProxyCommand from ProxyJump: ssh -vv -W '[%h]:%p' proxy.example.org debug1: Executing proxy command: exec ssh -vv -W '[pi-hole.example.org]:22' proxy.example.org debug1: identity file /home/milosz/.ssh/milosz type -1 debug1: identity file /home/milosz/.ssh/milosz-cert type -1 debug1: Local version string SSH-2.0-OpenSSH_8.4p1 Debian-5 OpenSSH_8.4p1 Debian-5, OpenSSL 1.1.1k 25 Mar 2021 debug1: Reading configuration data /home/milosz/.ssh/config debug2: checking match for 'host pi-hole !exec "~/.ssh/ipnetext.py 10.10.0.0/16 %h.example.org"' host proxy.example.org originally proxy.example.org debug2: match not found debug2: checking match for 'user milosz' host proxy.example.org originally proxy.example.org debug2: match found debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files debug1: /etc/ssh/ssh_config line 21: Applying options for * debug2: resolving "proxy.example.org" port 22 debug2: ssh_connect_direct debug1: Connecting to proxy.example.org [10.10.10.254] port 22. debug1: Connection established. debug1: identity file /home/milosz/.ssh/milosz type -1 debug1: identity file /home/milosz/.ssh/milosz-cert type -1 debug1: Local version string SSH-2.0-OpenSSH_8.4p1 Debian-5 debug1: Remote protocol version 2.0, remote software version OpenSSH_8.4p1 Ubuntu-5ubuntu1.1 debug1: match: OpenSSH_8.4p1 Ubuntu-5ubuntu1.1 pat OpenSSH* compat 0x04000000 debug2: fd 3 setting O_NONBLOCK debug1: Authenticating to proxy.example.org:22 as 'milosz' [...] Authenticated to proxy.example.org ([10.10.10.254]:22). debug1: channel_connect_stdio_fwd pi-hole.example.org:22 [...] debug1: Authenticating to pi-hole.example.org:22 as 'milosz' [...] Authenticated to pi-hole.example.org (via proxy). [...] Linux DietPi 5.10.63-v7+ #1457 SMP Tue Sep 28 11:25:31 BST 2021 armv7l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Thu Oct 21 01:37:47 2021 from 10.10.10.254 milosz@DietPi:~ $
What a neat idea!