isontheline / pro.webssh.net

iOS / iPadOS / macOS SSH Client
https://apps.apple.com/us/app/id497714887
MIT License
303 stars 44 forks source link

Ability to use a SSH Config File #327

Open jarrah31 opened 3 years ago

jarrah31 commented 3 years ago

Describe the feature I would like to suggest a new subnet detection feature that dynamically chooses a hostname/IP to connect to based on which network the app is running from, configured for each connection.

e.g. if I'm on my home network and the app detects I'm on a specified subnet such as 192.168.0.x, I would like the app to connect to a local IP address. If I'm connecting from a network other than the specified one (ie roaming on my iPhone), it uses another hostname such as an external URL (my.homenet.com).

I can illustrate this based on a method I use with .ssh/config (which as it happens also uses another feature request - ProxyJump)

Match exec "/Users/user1/onsubnet 192.168.1." host raspi1
 Hostname 192.168.1.100
 Port 22
 User pi

Match exec "/Users/user1/onsubnet --not 192.168.1." host raspi1
 ProxyJump proxypi
 Hostname 192.168.1.100
 User pi
 Port 22

Host proxypi
 HostName my.homenet.com
 Port 8700
 User pi

The file /Users/user1/onsubnet is a script I found that helps determine your subnet on a Mac. I realise it couldn't be used in the app like this, but I'm including it here in case it helps.

if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]  || [[ "$1" == "" ]] ; then
  printf "Usage:\n\tonsubnet [ --not ] partial-ip-address\n\n"
  printf "Example:\n\tonsubnet 10.10.\n\tonsubnet --not 192.168.0.\n\n"
  printf "Note:\n\tThe partial-ip-address must match starting at the first\n"
  printf "\tcharacter of the ip-address, therefore the first example\n"
  printf "\tabove will match 10.10.10.1 but not 110.10.10.1\n"
  exit 0
fi

on=0
off=1
if [[ "$1" == "--not" ]] ; then
  shift
  on=1
  off=0
fi

regexp="^$(sed 's/\./\\./g' <<<"$1")"

if [[ "$(uname)" == "Darwin" ]] ; then
  ifconfig | fgrep 'inet ' | fgrep -v 127.0.0. | cut -d ' ' -f 2 | egrep "$regexp" >/dev/null
else
  hostname -I | tr -s " " "\012" | fgrep -v 127.0.0. | egrep "$regexp" >/dev/null
fi

if [[ $? == 0 ]]; then
  exit $on
else
  exit $off
fi

In the absence of this feature I could always specify the external URL, but I'm not sure if that would work with ProxyJump where a connection to an internal device would keep having to hop via my proxypi to its destination when I'm at home.

The other alternative would be to have two connections - one local and one remote. This would work fine, but it would be neater if I only needed to configure one host.

Hope this makes sense. Thanks.

isontheline commented 3 years ago

Hello @jarrah31 πŸ‘‹

I think you have found a solution for a problem that myself I have πŸ˜‡ I need to switch between home and office and need to use a gateway when I'm home.

I'm now thinking how it will be implemented inside WebSSH πŸ€”

Perhaps SSH config file should be an option?

isontheline commented 3 years ago

Tasks for complete implementation

Examples of SSH config match uses

Client Configuration Options

jarrah31 commented 3 years ago

Hello @jarrah31 πŸ‘‹

I think you have found a solution for a problem that myself I have πŸ˜‡ I need to switch between home and office and need to use a gateway when I'm home.

You're welcome, thank you for considering this! I find it very useful being able to just use 'ssh raspi1' on my Mac when either at home or the office and it automatically choose which method to use (direct IP at home, proxy jump in the office)

I'm now thinking how it will be implemented inside WebSSH πŸ€”

Perhaps SSH config file should be an option?

Good question. I suspect having an SSH config file may complicate things and clash with the SSH Connection GUI, so I'd probably prefer it to be managed within the Servers page.

Seeing as ProxyJump plays a large part of this solution, I think there should be a checkbox option in each SSH Connection config page that allows it to be defined as a ProxyJump host and added to a list of other ProxyJump servers. This list of ProxyJump servers could then be presented as a drop-down list in each SSH Connection page, so that you can choose which ProxyJump Host to use for that particular connection. A clause would have to be put in place to prevent both options being selected at the same time (i.e. you can't choose another ProxyJump host if you are one yourself)

The subnet detection feature perhaps needs the user to define a list of subnets somewhere in Settings -> SSH. This list then becomes a drop-down list within each SSH Connection config page that can be selected as part of the following "If, then, else" user choice flow:

"If device is on subnet 192.168.0, use the specified Host entry (e.g. local IP address), else use selected ProxyJump host."

The option to use subnet detection in an SSH Connection config page could be greyed out until a tick-box to enable it is selected. Once enabled, you can choose a subnet from the drop-down list along with text saying something like "Use defined Host when device is using this subnet, else use selected ProxyJump Host".

The ProxyJump option could be enabled independently to the subnet detection option and be used by itself if the user wishes to. Maybe the drop-down list has a default "disabled" or "not required" choice in the list to save having a separate check box?

Hopefully the Apple API's let you determine which subnet the device is on, both within iOS, iPadOS and MacOS (when you bring WebSSH to Intel CPUs, which I'm very much looking forward to, though understandably no rush as it sounds like you have a day job too). :)

Thank you!

isontheline commented 3 years ago

Hopefully the Apple API's let you determine which subnet the device is on, both within iOS, iPadOS and MacOS (when you bring WebSSH to Intel CPUs, which I'm very much looking forward to, though understandably no rush as it sounds like you have a day job too). :)

I'm starting firstly with this quote because you're right I have a full day job that prevent me to make WebSSH better faster. So this quote could explain my statements below πŸ˜‡

Good question. I suspect having an SSH config file may complicate things and clash with the SSH Connection GUI, so I'd probably prefer it to be managed within the Servers page.

Seeing as ProxyJump plays a large part of this solution, I think there should be a checkbox option in each SSH Connection config page that allows it to be defined as a ProxyJump host and added to a list of other ProxyJump servers. This list of ProxyJump servers could then be presented as a drop-down list in each SSH Connection page, so that you can choose which ProxyJump Host to use for that particular connection. A clause would have to be put in place to prevent both options being selected at the same time (i.e. you can't choose another ProxyJump host if you are one yourself) The option to use subnet detection in an SSH Connection config page could be greyed out until a tick-box to enable it is selected. Once enabled, you can choose a subnet from the drop-down list along with text saying something like "Use defined Host when device is using this subnet, else use selected ProxyJump Host".

The ProxyJump option could be enabled independently to the subnet detection option and be used by itself if the user wishes to. Maybe the drop-down list has a default "disabled" or "not required" choice in the list to save having a separate check box?

If I implement like you describe it :

The subnet detection feature perhaps needs the user to define a list of subnets somewhere in Settings -> SSH. This list then becomes a drop-down list within each SSH Connection config page that can be selected as part of the following "If, then, else" user choice flow:

"If device is on subnet 192.168.0, use the specified Host entry (e.g. local IP address), else use selected ProxyJump host."

Sorry, it's too complicated to implement as described πŸ˜“

I'm dreaming a simpler implementation that will let the user to do the following steps (the same steps you do on your mac) :

  1. User creates their connections as usual "raspi1" and "proxypi" with their own credentials / ports / hostname
  2. User creates a new config file like the .ssh/config one, this config file will overwrite the connections based on the "matches" statements

By implementing a .ssh/config inside WebSSH it :

It's very likely that I'm wrong but I would like to find with you the best implementation.

Thanks for your feedback

jarrah31 commented 3 years ago

Hi Arnaud, I completely understand and I'm happy with your suggestion. It helps keep the connection interface clean whilst still letting advanced users do more with WebSSH.

My only thoughts then with the config file is how best to detect which subnet the device is on? At the moment I use a local script that does the logic (/Users/user1/onsubnet 192.168.1.) - are you thinking of doing something similar?

Does WebSSH already have the ability to parse a standard .ssh/config file?

I know you already have a built-in port forwarding feature, but would it pick up the same settings within a config file like this?

# Laptop -> mypi -> dockersrv
Host dockervnc
 ProxyJump proxypi
 HostName 192.168.1.105
 User pi
 Port 22
 LocalForward 5901 localhost:5901
isontheline commented 3 years ago

My only thoughts then with the config file is how best to detect which subnet the device is on? At the moment I use a local script that does the logic (/Users/user1/onsubnet 192.168.1.) - are you thinking of doing something similar?

Yes I can add a command line utility that reproduce your script' logic.

Does WebSSH already have the ability to parse a standard .ssh/config file?

Not already. The big question : reuse the same format ? or implement a new one ? I prefer the first, but I need to check how hard it is.

I know you already have a built-in port forwarding feature, but would it pick up the same settings within a config file like this?

Yes I think that port forwarding would also be used with config file.

This issue could be hard to implement but I like it a lot πŸ˜…

jarrah31 commented 3 years ago

This issue could be hard to implement but I like it a lot

Good luck! I know how hard coding can be (I've tried myself but just don't have the right brain-wiring for it)! I'll be happy to test it out when you're ready.

akuropka commented 3 years ago

Actually interesting idea as some people may come across such situation (including myself but not limited to SSH). However, I am wondering why to take the hassle, since this can be easily managed through DNS. If I am within a local network the local IP will be returned and outside the public one will be used.

isontheline commented 3 years ago

@akuropka I agree that DNS is easier to implement on the user side but sometimes your IT guys won't let you setup custom local DNS and you will need an alternative to DNS.

akuropka commented 3 years ago

oh well noted. (since I'm the IT I did not consider this... would be using two profiles then.)

isontheline commented 1 year ago

Hello @jarrah31 πŸ‘‹

It has been months since your request about SSH Config File, sorry for the delay 😒

WebSSH (beta on TestFlight) has now gained support of a "SSH Config File". Of course only a (very) few SSH settings are available but, I will improve in the upcoming months.

Right now WebSSH supports these settings : https://webssh.net/documentation/help/SSH/ssh-config-file/

"Match" is not yet supported but I would like to work on it soon. I think I can implement a script like your "onsubnet" so you will be able to customize "Hostname" setting when you aren't on your LAN.

BUT

I'm not ready (yet) to implement the "ProxyJump" setting right now so you will need to launch a tunnel or a VPN. So you will be able to use a custom Hostname but not the full ProxyJump as you said in your example. (The ProxyJump feature should come later).

Are you OK?

Have a nice day β˜€οΈ

jarrah31 commented 1 year ago

Hi Arnaud!

This is great, thank you very much!! (no worries about the delay)

Looking forward to it, thank you!

"Match" is not yet supported but I would like to work on it soon. I think I can implement a script like your "onsubnet" so you will be able to customize "Hostname" setting when you aren't on your LAN.

I have a couple of suggestions for future additions please.

isontheline commented 1 year ago

Hi @jarrah31 πŸ‘‹

Thank you so much for your strong feedback!

I guess at the moment we still need to create a Connection as well as a config file entry? If so, perhaps the ability to automatically create new Connections if a Host entry within the ssh config file doesn't match an existing Connection "Name"? This would help people easily import/migrate their ssh config file into WebSSH. Maybe a pop-up box after saving saying something like "detected new entry in ssh config file, do you want to create a new Connection?" If there's are lots of new entries, maybe a "Yes to all" option would help?

You're right WebSSH needs to have the connections created in order to work as it. Yes import from the SSH Config could be a great addition!

Only one drawback : Hosts with wildcard "*" won't be imported

I'm creating an issue to track import from SSH Config File : https://github.com/isontheline/pro.webssh.net/issues/792

Support the "IdentityFile" keyword that translates to "Private key" within Connection settings? I have a few .ssh/config entries with these.

When implemented it should check within the "Keys inside WebSSH Settings UI" and if the key name has not been found it should check if a file exists named by the "IdentifyFile" parameter.

leolbyy commented 1 year ago

Hi, can i check what’s the status now on proxy jump?

isontheline commented 1 year ago

Hi @leolbyy πŸ‘‹

Sorry, no progress yet. You still need to use Dynamic Port Forwarding to emulate the jump.

I will work on jump but I can't tell you any ETA though.