Bash: monitoring TCP socket activity - bash

I use mpg123 to read an mp3 webradio stream (port 8000).
Sometimes, the webradio server stops but mpg123 doesn't quit. Also, if the network on my machine fails, mpg123 won't quit either.
I would like to monitor mpg123 activity using a bash script launched by cron.
Something like this:
tcpdump -i eth0 port 8000 2>/dev/null | head | wc -l &
sleep 5
killall tcpdump
If no stream is played by mpg123, the result will be 1. Otherwise, it will be > 1.
How can I get this result into a variable?
Then I could relaunch mpg123 if the streaming has failed.
Note that I can't use the timeout command and I can't write anything on my system.

possibly
isitthere=$(tcpdump -i eth0 port 8000 2>/dev/null | head | wc -l & sleep 5; killall tcpdump)
if [[ $isitthere -eq 1 ]]
then
SET FIRE TO EVERYTHING
fi
not sure if it'd handle the sleep 5. But can't you use a -ll switch on tcp dump so..
worth a shot.

Related

Find (AND KILL) port 23515 Mac osx

new here have learned tons over the years and happen to have a pretty puzzling question. I just purchased a product to help edit photos in Adobe Lightroom. Its called a Loupedeck. Comes with software and is a device that controls all the parameters in Lightroom (makes editing way quicker)
Once I installed their loupdeck software and opened Lightroom I immediately got this prompt.
"Loupedeck needs access to tcp ports 23515 and 23516.
Other process is currently occupying 23515.
Loupedeck will not work until that application is closed."
I have been searching for days trying to find what app I have installed thats using or used port 23515. I have tried checking in terminal with the simple netstat command, and found nothing. I've used little snitch to see if any programs are using that port, still nothing. Im a little lost and sadly the company is also lost and has no advice.
Computer - Macbook pro 2011 17" 2.3ghz OSX 10.12.6
Here is the error in Lightroom
From this answer:
lsof -n -i4TCP:23515
lsof -n -i TCP:23515 | grep LISTEN
lsof -n -i:23515 | grep LISTEN
Netstat may also work:
netstat -ap tcp | grep -i "23515"
Any of these commands should give you the name and PID of the process.
Once you have the PID, you can kill the process, or if you know the process name is process_name you can use killall -KILL process_name .
Just for the record though, your terminal isn't running an administrative shell by default. In order to execute commands in terminal as an administrator, you have to use the command sudo su and then enter your password. Once you have a prompt with a #, you can try these commands again, just to be sure.
In one command find and kill:
kill -9 `lsof -i : 23515 -t` or if the existing process was launched by root or an other user: sudo kill -9 `lsof -i : 23515 -t`
lsof -i : 23515 returns the process id using the port 23515 on your machine.
You may also want to restart your computer, just in case the process using this port went into a "zombie" mode or lock the port and went off without freeing the port.
You can try to fine the process listening to those ports:
lsof -i :23515 -t
If you want to save time in the long run, you can add this script "kill-process.sh" into your /usr/local/bin
#!/bin/bash
echo Killing process..
usage() { echo "Usage: $0 [-p <port-number>]" 1>&2; exit 1; }
while getopts ":p:" o; do
case "${o}" in
p)
p=${OPTARG}
((p > 0 )) || usage
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
if [ -z "${p}" ]; then
usage
fi
PID=$(lsof -ti:$p)
if [ -z "${PID}" ]; then
echo "No process running on port ${p}"
else
kill $PID
echo "Killed process PID: ${PID}"
fi
Add this line into your .zshrc
alias kill-process="sh /usr/local/bin/kill-process.sh"
Then just run from your terminal
kill-process -p 23515
You will save time in the long run and this is useful if you need to close any process in any port by specifying it as a parameter.

Passing a port number to lsof in a shell function

I wrote an alias in my bash profile to help me kill rogue rails server processes that don't cleanly close. This alias works well.
alias kill3000="lsof -i tcp: 3000 -t | xargs kill -9 | echo 'killed processes on port 3000'"
I wanted to make it more general purpose, for frameworks that work on other ports. I tried to make a similar function, so I could pass the port number as a variable, but I get an error. The function I wrote looks like this...
function killproc (){
"lsof -i tcp:$1 -t | xargs kill -9 | echo 'killed processes on port $1'"
}
However, when I run "killproc 3000", I get the following error:
lsof: unacceptable port specification in: -i tcp:
I'm struggling to understand the problem, I appreciate any help.
Maybe the double-quotes are involved.
Give a try to this:
function killproc (){
lsof -i tcp:"$1" -t | xargs kill -9
lsof -i tcp:"$1" -t 2>/dev/null >/dev/null || printf "killed processes on port %s\n" "$1"
}
The message is printed only if there is no more process found listening on the port pspecified.
If you get some troubles, follow #shellter instruction.
Run a test with set -vx ; killproc 300 ; set +vxand edit the question to add the output generated.

bash receive udp packets tcpdump

On one server, I am receiving udp packets on 192.168.0.51 from an application running on 192.168.0.21, and have to reply with a specific acknowledgement packet.
The solution I wrote works as following:
#!/bin/bash
send_ack() {
<calculate $ack - code removed>
echo -n "$ack" | nc -u -w1 192.168.0.21 8076
}
while [ 1 ]
do
for string in $(/usr/sbin/tcpdump -Avnni eth0 -c 1 dst 192.168.0.51 and udp port 8076)
do
send_ack &
done
done
The issue is that I seem to have some running condition when packets arrive too quickly, I guess they arrive before tcpdump restarts.
I tried -l for single line buffer instead of -c 1 to no success.
Would anyone have any ideas of how to solve this issue?
Thanks, looking forward :)
The problem in your program is that packets will slip by in between tcpdump invocations, since you're just running it to capture a single packet using -c 1 and then exiting again each time.
The solution would be to run tcpdump continuously in line buffered mode (-l) with its output piped to a process reading that.
#!/bin/bash
# tcpdump line buffered and piped to infinite loop
/usr/sbin/tcpdump -Avnni eth0 -l dst 192.168.0.51 and udp port 8076 | \
while true; do
# read output line by line
read result
# only act on non-blank output
if [ "$result" != "" ]; then
echo "Read a packet: $result"
# perform whatever action
send_ack &
fi
done
In addition to this you may also want to experiment with the -B option to tcpdump which lets you set the buffer size, and with different options for read.

Closing all processes holding a given port from shell

I am trying to automate one of the jobs I am facing again and again.
There are some ports which are sometimes not closed correctly by some previous jobs..
Lets say port 5000,5001
WHat I want to do is see if these ports are open
and kill these ports if they are open
So right now, I am doing
lsof -i :5000
and
kill -9 pid1
kill -9 pid2
and so on..
Is there a way to pass 5000 and 5001 as arguments and automate this process
If you want to automate it as you use it do something like this.
Create a bash script, for example call it 'killMyPorts' and add the following content:
#!/bin/bash
kill -9 `lsof -i :"${1}" | awk '{if (NR!=1) {print $2}}'`
Once you made the script executable (chmod u+x), you can execute it as follows:
./killMyPorts 5000
fuser can do this job for you.
kill_port_users() {
for port; do
fuser -n tcp -k "$port"
done
}
kill_port_users 5000 5001
Have you tried
kill -9 `lsof -i :5000`
or
kill -9 $(lsof -i :5000)

How do I kill a backgrounded/detached ssh session?

I am using the program synergy together with an ssh tunnel
It works, i just have to open an console an type these two commands:
ssh -f -N -L localhost:12345:otherHost:12345 otherUser#OtherHost
synergyc localhost
because im lazy i made an Bash-Script which is run with one mouseclick on an icon:
#!/bin/bash
ssh -f -N -L localhost:12345:otherHost:12345 otherUser#OtherHost
synergyc localhost
the Bash-Script above works as well, but now i also want to kill synergy and the ssh tunnel via one mouseclick, so i have to save the PIDs of synergy and ssh into file to kill them later:
#!/bin/bash
mkdir -p /tmp/synergyPIDs || exit 1
rm -f /tmp/synergyPIDs/ssh || exit 1
rm -f /tmp/synergyPIDs/synergy || exit 1
[ ! -e /tmp/synergyPIDs/ssh ] || exit 1
[ ! -e /tmp/synergyPIDs/synergy ] || exit 1
ssh -f -N -L localhost:12345:otherHost:12345 otherUser#OtherHost
echo $! > /tmp/synergyPIDs/ssh
synergyc localhost
echo $! > /tmp/synergyPIDs/synergy
But the files of this script are empty.
How do I get the PIDs of ssh and synergy?
(I try to avoid ps aux | grep ... | awk ... | sed ... combinations, there has to be an easier way.)
With all due respect to the users of pgrep, pkill, ps | awk, etc, there is a much better way.
Consider that if you rely on ps -aux | grep ... to find a process you run the risk of a collision. You may have a use case where that is unlikely, but as a general rule, it's not the way to go.
SSH provides a mechanism for managing and controlling background processes. But like so many SSH things, it's an "advanced" feature, and many people (it seems, from the other answers here) are unaware of its existence.
In my own use case, I have a workstation at home on which I want to leave a tunnel that connects to an HTTP proxy on the internal network at my office, and another one that gives me quick access to management interfaces on co-located servers. This is how you might create the basic tunnels, initiated from home:
$ ssh -fNT -L8888:proxyhost:8888 -R22222:localhost:22 officefirewall
$ ssh -fNT -L4431:www1:443 -L4432:www2:443 colocatedserver
These cause ssh to background itself, leaving the tunnels open. But if the tunnel goes away, I'm stuck, and if I want to find it, I have to parse my process list and home I've got the "right" ssh (in case I've accidentally launched multiple ones that look similar).
Instead, if I want to manage multiple connections, I use SSH's ControlMaster config option, along with the -O command-line option for control. For example, with the following in my ~/.ssh/config file,
host officefirewall colocatedserver
ControlMaster auto
ControlPath ~/.ssh/cm_sockets/%r#%h:%p
the ssh commands above, when run, will leave spoor in ~/.ssh/cm_sockets/ which can then provide access for control, for example:
$ ssh -O check officefirewall
Master running (pid=23980)
$ ssh -O exit officefirewall
Exit request sent.
$ ssh -O check officefirewall
Control socket connect(/home/ghoti/.ssh/cm_socket/ghoti#192.0.2.5:22): No such file or directory
And at this point, the tunnel (and controlling SSH session) is gone, without the need to use a hammer (kill, killall, pkill, etc).
Bringing this back to your use-case...
You're establishing the tunnel through which you want syngergyc to talk to syngergys on TCP port 12345. For that, I'd do something like the following.
Add an entry to your ~/.ssh/config file:
Host otherHosttunnel
HostName otherHost
User otherUser
LocalForward 12345 otherHost:12345
RequestTTY no
ExitOnForwardFailure yes
ControlMaster auto
ControlPath ~/.ssh/cm_sockets/%r#%h:%p
Note that the command line -L option is handled with the LocalForward keyword, and the Control{Master,Path} lines are included to make sure you have control after the tunnel is established.
Then, you might modify your bash script to something like this:
#!/bin/bash
if ! ssh -f -N otherHosttunnel; then
echo "ERROR: couldn't start tunnel." >&2
exit 1
else
synergyc localhost
ssh -O exit otherHosttunnel
fi
The -f option backgrounds the tunnel, leaving a socket on your ControlPath to close the tunnel later. If the ssh fails (which it might due to a network error or ExitOnForwardFailure), there's no need to exit the tunnel, but if it did not fail (else), synergyc is launched and then the tunnel is closed after it exits.
You might also want to look in to whether the SSH option LocalCommand could be used to launch synergyc from right within your ssh config file.
Quick summary: Will not work.
My first idea is that you need to start the processes in the background to get their PIDs with $!.
A pattern like
some_program &
some_pid=$!
wait $some_pid
might do what you need... except that then ssh won't be in the foreground to ask for passphrases any more.
Well then, you might need something different after all. ssh -f probably spawns a new process your shell can never know from invoking it anyway. Ideally, ssh itself would offer a way to write its PID into some file.
just came across this thread and wanted to mention the "pidof" linux utility:
$ pidof init
1
You can use lsof to show the pid of the process listening to port 12345 on localhost:
lsof -t -i #localhost:12345 -sTCP:listen
Examples:
PID=$(lsof -t -i #localhost:12345 -sTCP:listen)
lsof -t -i #localhost:12345 -sTCP:listen >/dev/null && echo "Port in use"
well i dont want to add an & at the end of the commands as the connection will die if the console wintow is closed ... so i ended up with an ps-grep-awk-sed-combo
ssh -f -N -L localhost:12345:otherHost:12345 otherUser#otherHost
echo `ps aux | grep -F 'ssh -f -N -L localhost' | grep -v -F 'grep' | awk '{ print $2 }'` > /tmp/synergyPIDs/ssh
synergyc localhost
echo `ps aux | grep -F 'synergyc localhost' | grep -v -F 'grep' | awk '{ print $2 }'` > /tmp/synergyPIDs/synergy
(you could integrate grep into awk, but im too lazy now)
You can drop the -f, which makes it run it in background, then run it with eval and force it to the background yourself.
You can then grab the pid. Make sure to put the & within the eval statement.
eval "ssh -N -L localhost:12345:otherHost:12345 otherUser#OtherHost & "
tunnelpid=$!
Another option is to use pgrep to find the PID of the newest ssh process
ssh -fNTL 8073:localhost:873 otherUser#OtherHost
tunnelPID=$(pgrep -n -x ssh)
synergyc localhost
kill -HUP $tunnelPID
This is more of a special case for synergyc (and most other programs that try to daemonize themselves). Using $! would work, except that synergyc does a clone() syscall during execution that will give it a new PID other than the one that bash thought it has. If you want to get around this so that you can use $!, then you can tell synergyc to stay in the forground and then background it.
synergyc -f -n mydesktop remoteip &
synergypid=$!
synergyc also does a few other things like autorestart that you may want to turn off if you are trying to manage it.
Based on the very good answer of #ghoti, here is a simpler script (for testing) utilising the SSH control sockets without the need of extra configuration:
#!/bin/bash
if ssh -fN -MS /tmp/mysocket -L localhost:12345:otherHost:12345 otherUser#otherHost; then
synergyc localhost
ssh -S /tmp/mysocket -O exit otherHost
fi
synergyc will be only started if tunnel has been established successfully, which itself will be closed as soon as synergyc returns.
Albeit the solution lacks proper error reporting.
You could look out for the ssh proceess that is bound to your local port, using this line:
netstat -tpln | grep 127\.0\.0\.1:12345 | awk '{print $7}' | sed 's#/.*##'
It returns the PID of the process using port 12345/TCP on localhost. So you don't have to filter all ssh results from ps.
If you just need to check, if that port is bound, use:
netstat -tln | grep 127\.0\.0\.1:12345 >/dev/null 2>&1
Returns 1 if none bound or 0 if someone is listening to this port.
There are many interesting answers here, but nobody mentioned that the manpage of SSH does describe this exact case! (see TCP FORWARDING section). And the solution they offer is much simpler:
ssh -fL 12345:localhost:12345 user#remoteserver sleep 10
synergyc localhost
Now in details:
First we start SSH with a tunnel; thanks to -f it will initiate the connection and only then fork to background (unlike solutions with ssh ... &; pid=$! where ssh is sent to background and next command is executed before the tunnel is created). On the remote machine it will run sleep 10 which will wait 10 seconds and then end.
Within 10 seconds, we should start our desired command, in this case synergyc localhost. It will connect to the tunnel and SSH will then know that the tunnel is in use.
After 10 seconds pass, sleep 10 command will finish. But the tunnel is still in use by synergyc, so SSH will not close the underlying connection until the tunnel is released (i.e. until synergyc closes socket).
When synergyc is closed, it will release the tunnel, and SSH in turn will terminate itself, closing a connection.
The only downside of this approach is that if the program we use will close and re-open connection for some reason then SSH will close the tunnel right after connection is closed, and the program won't be able to reconnect. If this is an issue then you should use an approach described in #doak's answer which uses control socket to properly terminate SSH connection and uses -f to make sure tunnel is created when SSH forks to the background.

Resources