How can I programmatically find the port allocated for SSH reverse forwarding?
Asked by
SwiftPanda42
I'm using OpenSSH 8.0p1 on Oracle Linux 8.10. When I SSH into a remote host and want to set up a reverse port forward (tunneling from the remote machine back to my local machine), I specify a port of zero (0) to let SSH find an unused port automatically. This allocated port is displayed during the connection setup, like this: `Allocated port 45515 for remote forward to localhost:3289`. This is fine for manual sessions, but I want to capture that port number programmatically so I can set up environment variables on the remote system without needing to manually check the output of the command. Here's what I've tried with no success:
1. I looked around `/proc/$PPID`, the parent process of my shell, but as expected, those entries are owned by root, and I can't access them.
2. I examined the environment variables in my shell, but there's nothing about the allocated port.
3. I can type `~#` in the SSH session to list current port forwards, but that only works if I'm actively using it, which defeats my purpose.
4. Using `~C` allows adding/removing port forwards, but there's no command to list all established forwards.
5. I did find the port using `lsof` run as root, but I don't want to go that route.
Am I overlooking something? Is there really no way to programmatically obtain the allocated port? I appreciate any help!
Answers
One way to grab the allocated port is to use `netstat`. You can run this command to see ports your user is listening on:
```
netstat -ltne | awk -v uid=$(id -u) '$7 == uid {print $4}' | awk -F: '{print $NF}' | sort -u
```
Alternatively, for a more direct approach, here's how you can access `/proc/net/tcp`:
```
awk -v uid=$(id -u) '$8 == uid && $4 == "0A" {print $2}' /proc/net/tcp{,6} | awk -F: '{print "0x"$NF}' | while read hex; do printf "%dn" "$hex"; done | sort -u
```
Reply to this answer
If you're after the port for a specific session, you could use this command:
```
ss -4 -H -t -l -p -n state listening | grep -Eo ".*,pid=${PPID}," | awk '{print $3}' | awk -F ':' '{print $2}'
```
Reply to this answer
Are you wanting to capture the port from the client or the server side? Just clarifying your goal might help others assist you better.
SwiftPanda42: Sorry for any confusion! I'm trying to find the port allocated to me on the server side where I'm connecting so I can set up environment variables accordingly.
Reply to this answer
Consider checking the `man netstat` documentation for additional flags that might help identify your specific needs, though it might require a manual process.
SwiftPanda42: How would `netstat` identify specifically which port `sshd` allocated for me among all the listening ports?
Reply to this answer
Add your answer
Answers are reviewed before publication.
FixItFrank: This is brilliant, thank you! I especially like the second method; it's precise for my use case where I shouldn't have other listening ports. I think I might suggest this as a feature for OpenSSH or even propose a patch for it!
NetSavvyJoe: I just noticed I could simplify the awk command for better efficiency: ``` awk -v uid=$(id -u) '$8 == uid && $4 == "0A" {printf "%dn", strtonum("0x"$NF)}' /proc/net/tcp{,6} | sort -u ```