One-liner
I've put together a nice one-liner that quickly serves the purpose, allowing to grab an arbitrary number of ports in an arbitrary range (here it's divided in 4 lines for readability):
comm -23 \
<(seq "$FROM" "$TO" | sort) \
<(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) \
| shuf | head -n "$HOWMANY"
Line by line
comm
is a utility that compares lines in two files that must appear sorted alphabetically. It outputs three columns: lines that appear only in the first file, lines that only appear in the second one and common lines. By specifying -23
we suppress the latter columns and only keep the first one. We can use this to obtain the difference of two sets, expressed as a sequence of text lines. I learned about comm
here.
The first file is the range of ports that we can select from. seq
produces a sorted sequence of numbers from $FROM
to $TO
. The result is sorted alphabetically (instead of numerically, in order to comply with comm
s requirement) and piped to comm
as the first file using process substitution.
The second file is the sorted list of ports, that we obtain by calling the ss
command (with -t
meaning TCP ports, -a
meaning all - established and listening - and -n
numeric - don't try to resolve, say, 22
to ssh
). We then pick only the fourth column with awk
, which contains the local address and port. We use cut
to split address and port with the :
delimiter and keep only the latter (-f2
). We then comply with comm
's requirement by sort
ing without duplicates -u
.
Now we have a sorted list of open ports, that we can shuf
fle to then grab the first "$HOWMANY"
ones with head -n
.
Example
Grab the three random open ports in the private range (49152-65535)
comm -23 <(seq 49152 65535 | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) | shuf | head -n 3
could return for example
54930
57937
51399
Notes
- switch
-t
with -u
in ss
to get free UDP ports instead.
- replace
shuf
with sort -n
if you prefer to get available ports numerically sorted instead of at random
-n
to netstat and a more selective grep). The way to do it is to try and open a port in whatever mode you need, and try another one if it's not available. – Mat Nov 16 '12 at 16:04ssh -D
as a SOCKS server. – mybuddymichael Nov 16 '12 at 16:08