Not able to connect to socket using socat - bash

I am trying to parse rsyslog logs. For this i am sending all my logs to socat which is then sending them to Unix Domain Socket. That socket is created via perl script which is listening on that socket to parse logs.
My bash script to which rsyslog is sending all log is
if [ ! `pidof -x log_parser.pl` ]
then
./log_parser.pl & 1>&1
fi
if [ -S /tmp/sock ]
then
/usr/bin/socat -t0 -T0 - UNIX-CONNECT:/tmp/sock 2>> /var/log/socat.log
fi
/tmp/sock is created using perl script log_parser.pl which is
use IO::Socket::UNIX;
sub socket_create {
$socket_path = '/tmp/sock';
unlink($socket_path);
$listner = IO::Socket::UNIX->new(
Type => SOCK_STREAM,
Local => $socket_path,
Listen => SOMAXCONN,
Blocking => 0,
)
or die("Can't create server socket: $!\n");
$socket = $listner->accept()
or die("Can't accept connection: $!\n");
}
socket_create();
while(1) {
chomp($line=<$socket>);
print "$line\n";
}
There is this error i am getting from socat which is
2015/02/24 11:58:01 socat[4608] E connect(3, AF=1 "/tmp/sock", 11): Connection refused
I am no champion in sockets so i am not able to understand what is this. Please help. Thanks in advance.
The main issue is that when i kill my perl script then bash script is suppose to call it again and start it.
What actually happening is that sript is started but socat is not started instead it give this error and never start.

I can duplicate your error if I don't run your perl program before trying to use socat. Here is what works for me:
1) my_prog.pl:
use strict;
use warnings;
use 5.016;
use Data::Dumper;
use IO::Socket::UNIX;
my $socket_path = '/tmp/sock';
unlink $socket_path;
my $socket = IO::Socket::UNIX->new(
Local => $socket_path,
Type => SOCK_STREAM,
Listen => SOMAXCONN,
) or die "Couldn't create socket: $!";
say "Connected to $socket_path...";
my $CONN = $socket->accept()
or die "Whoops! Failed to open a connection: $!";
{
local $/ = undef; #local -> restore previous value when the enclosing scope, delimited by the braces, is exited.
#Setting $/ to undef puts file reads in 'slurp mode' => whole file is considered one line.
my $file = <$CONN>; #Read one line.
print $file;
}`
2) $ perl my_prog.pl
3) socat -u -v GOPEN:./data.txt UNIX-CONNECT:/tmp/sock
The -u and -v options aren't necessary:
-u Uses unidirectional mode. The first address is only used for
reading, and the second address is only used for writing (exam-
ple).
-v Writes the transferred data not only to their target streams,
but also to stderr. The output format is text with some conver-
sions for readability, and prefixed with "> " or "< " indicating
flow directions.
4) You can also do it like this:
cat data.txt | socat STDIN UNIX-CONNECT:/tmp/sock
Pipe stdout of cat command to socat, then list STDIN as one of socat's files.
Response to comment:
This bash script works for me:
#!/usr/bin/env bash
echo 'bash script'
../pperl_programs/my_prog.pl &
sleep 1s
socat GOPEN:./data.txt UNIX-CONNECT:/tmp/sock
It looks like the perl script doesn't have enough time to setup the socket before socat tries to transfer data.

Related

Difference in behavior between shell and script

I have a set of commands that I am attempting to run in a script. To be exact, the lines are
rm tmp_pipe
mkfifo tmp_pipe
python listen_pipe.py &
while [ true ]; do nc -l -w30 7036 >>tmp_pipe; done &
listen_pipe.py is simply
if __name__ == "__main__":
f = open("tmp_pipe")
vals = " "
while "END" not in vals:
vals = f.readline()
if len(vals) > 0:
print(vals)
else:
f = open("tmp_pipe")
If I run the commands in the order shown I get my desired output, which is a connection to an ESP device that streams motion data. The connection resets after 30 seconds if the ESP device leaves the network range or if the device is turned off. The python script continues to read from the pipe and does not terminate when the tcp connection is reset. However, if I run this code inside a script file nc fails to connect and the device remains in an unconnected state indefinitely. The script is just
#!/bin/bash
rm tmp_pipe
mkfifo tmp_pipe
python listen_pipe.py &
while [ true ]; do nc -l -w30 7036 >>tmp_pipe; done &
This is being run on Ubuntu 16.04. Any suggestions are greatly welcomed, I have been fighting with this code all day. Thanks,
Ian

Retrieve output from HP Switch using Net::SSH2 Perl Module

I am trying to connect to HP Switch via SSH using Net::SSH2 Perl module (Windows OS). The script is able to connect and authenticate to the device, but the output is not getting retrieved. I am getting blank output.
I have tried with Net::SSH2 shell and exec both, but no luck till now.
Also tried with Net::SSH::Any, still no result.
Hp Switch Model : HP 5900 - 7.1.045
Code
use strict;
use Net::SSH2;
my $ssh = Net::SSH2->new();
$ssh->connect('xx.xx.xx.xx');
$ssh->auth(username => 'xxxxx', password => 'xxxxxx');
my $channel = $ssh->channel() or die 'Error creating channel';
$channel->blocking(0);
$channel->shell();
print $channel "display supervlan\n";
sleep(5);
while(<$channel>)
{
print $_;
}
$channel->close();
$ssh->disconnect();
Can somebody please help.
Net::SSH::Any can use any of available backend ssh modules (under windows uses Net::SSH2 if available)
use Net::SSH::Any;
my $ssh = Net::SSH::Any->new(
"127.0.0.1",
port => "22",
user => "xx",
password => "xx",
strict_host_key_checking =>0
);
$ssh->error and die $ssh->error;
my ($out, $err) = $ssh->capture2("ls -l /");
print $out;

Reply to IRC PING with PONG in bash script

So far I have a basic IRC Bot which I hope to be able to successfully PRIVMSG myself with but on the server I am testing on it requires a PONG response to PING.
I have absolutely no idea how to get around this. How do I reply to the PING?
My current code:
#!/bin/bash
function ircpreamble {
echo "NICK ${1}"
}
function privmsg {
TARGET=$1
sed -re "s/^(.*)\$/PRIVMSG ${TARGET} :\1/"
}
function delay {
while read LINE; do
sleep 2
echo $LINE
done
}
function messages {
msg=`cat pmmsg.txt`
echo $msg
}
function disconnect {
echo "QUIT goodbye :)"
}
(
nick=`cat randnick.txt`
pms=`cat pmnickname.txt`
ircpreamble "$nick";
messages | privmsg "$pms";
disconnect;
) | delay | nc irc.seersirc.net 6667
You first need to "catch" the server responses. This can be done like:
$ nc irc.seersirc.net 6667 |while read res;do echo "==>$res";done
==>:irc.seersirc.net NOTICE AUTH :*** Looking up your hostname...
==>:irc.seersirc.net NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead
Since now you catch the response in a variable, you can filter out these responses and send the appropriate commands back to the server.
The problem is that when running netcat/telnet from a script a simple echo "PONG" is not sending the messages back to server but echo prints the messages locally in your terminal.
To send messages to the server you need either to pipe those messages to netcat in the beginning (the technique you already use) or to use some kind of expect script or to use a file to feed the netcat.
Regarding the PONG response, note that in order pong to be accepted by the server it must include the message sent by the server along with it's ping request.
Your server sends something like PING :D7AA1D1D (different every time) and thus the correct pong response is PONG :D7AA1D1D
As a result you can not just include a pong response in the first messages send in the beginning to netcat, since you don't know what is the ID that your server will sent to you along with the ping request.
This is a working draft script using a file to continuously feed the netcat:
rm .ircbot
touch .ircbot
prmnick="gv"
tail -f .ircbot |nc irc.seersirc.net 6667 |while read res
do
echo "==>$res"
if [[ "$res" == *"Couldn't resolve your hostname; using your IP address instead"* ]];then
sleep 2
echo "NICK gvgv" >>.ircbot
tail -n1 .ircbot #used just to display the last line of the helper file in my screen.
elif [[ "$res" == *"PING"* ]]; then
sleep 2
echo "$res" |sed 's/PING/PONG/' >>.ircbot
tail -n1 .ircbot
sleep 2
echo "USER gvgv 8 * :gvgv " >>.ircbot
tail -n1 .ircbot
sleep 2
echo "PRIVMSG $prmnick : hello from bot" >>.ircbot
tail -n1 .ircbot
fi
done
Tip: By opening a second terminal , you can manually "control" above bot by sending more commands to the .ircbot file (i.e $ echo "JOIN #channel" >>.ircbot) which will be also fed to netcat.
By the way, some web search about bash irc bots will return some useful results.
This is one easy bash script to use as an irc bot: https://github.com/Newbrict/bash-irc-bot/blob/master/bot.sh
Also , i found this useful IRC Over Telnet guide: http://archive.oreilly.com/pub/h/1963
Finally , this is an alternative using the /dev/tcp directly : https://gist.github.com/Wollw/3330337

Can bash be used to create a server?

Is there any way to program a server in bash?
Basically I want be able to connect to a bash server from a PHP client and send messages that will be displayed in console.
The bad news first
Unfortunately, there seems to be no hope to do this in pure Bash.
Even doing a
exec 3<> /dev/tcp/<ip>/<port>
does not work, because these special files are implemented on top on connect() instead of bind(). This is apparent if we look at the source.
In Bash 4.2, for example, the function _netopen4() (or _netopen6() for IPv6) reads as follows (lib/sh/netopen.c):
s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0);
if (s < 0)
{
sys_error ("socket");
return (-1);
}
if (connect (s, (struct sockaddr *)&sin, sizeof (sin)) < 0)
{
e = errno;
sys_error("connect");
close(s);
errno = e;
return (-1);
}
But
It is possible to use a command line tool such as nc. E.g.,
nc -l <port>
will listen for incoming connections on localhost:<port>.
There is a project on GIT which implements a HTTP web server fully written in bash;
https://github.com/avleen/bashttpd
Create a process that reads from a socket, executes the data via shell, and prints back the response. Possible with the following script, which listens on port 9213:
ncat -l -kp 9213 | while read line; do
out=$($line)
# or echo $line
echo $out
done
If all you want is to display the data, ncat -l -p 9213 is sufficient though.

Code to count number of types of files on client in Unix

Hi I am new to shell scripting.
my requirement is:
There is one server & 3 clients. On each client error logs files are generated which are of 4 types.Say type 1 error , type 2 error like this type 4 error.
I want to write a script which read all the 3 clients from server & provide me number of times 4 different type of error logs are genereted on each client.
In short it should use ssh & grep command combination.
I have written the demo script but it's not providing me the number of times different type of logs occured on clients.
#error[1]='Exception: An application error occurred during an address lookup request, please contact IT'
#error[2]='SocketTimeoutException: Read timed out'
#error[3]='Exception: The search has produced too many matches to be returned'
#error[4]='Exception: No matching address found'
error_1='exception 1'
error_2='exception 2'
function get_list_of_clients()
{
NUM_OF_CLIENTS=$(wc -l ${CLIENT_IP_LIST} | awk -F " " '{ print $1 }' )
echo $NUM_OF_CLIENTS
if [ "${NUM_OF_CLIENTS}" -gt 0 ]
then
for ((row=2; row<=$NUM_OF_CLIENTS; row++))
do
CLIENTS_IP=$(sed -n ${row}p ${CLIENT_IP_LIST}| awk -F " " '{print $3 }')
echo ${CLIENTS_IP}
# get_number_of_errors
# copy_count_errors
echo ${$error_$row}
done
fi
}
function get_number_of_errors()
{
for((row_no=1; row_no<=4; row_no++))
do
{
/usr/bin/expect - <<- EndMark
spawn ssh root#${CLIENTS_IP} "grep $error[$row_no] var/error.log |wc -l" >> /tmp/${CLIENTS_IP}_error${row_no}.txt
match_max 50000
expect {
"*yes/no*" {
send -- "yes\r"
send -- "\r"
exp_continue
}
"*?assword:*" {
send -- "${CLIENT_PASSWORD}\r"
send -- "\r"
}
}
expect eof
EndMark
}
done
}
function copy_count_errors()
{
/usr/bin/expect - <<- EndMark
spawn scp root#${CLIENTS_IP}:/tmp/${CLIENTS_IP}* /tmp/
match_max 50000
expect {
"*yes/no*" {
send -- "yes\r"
send -- "\r"
exp_continue
}
"*?assword:*" {
send -- "${CLIENT_PASSWORD}\r"
send -- "\r"
}
}
expect eof
EndMark
}
get_list_of_clients
================================================================================
please help.
This is not really an answer, an attempt to help you getting your own.
The Problem
If I understand it correctly:
Your script runs on the server
You have three clients, each has log files
Your list of clients is in a file named $CLIENT_IP_LIST, where the IP is the third field and the first line is some sort of header, which you want to exclude.
Suggestions
It seems you need to ssh and scp to the clients. If possible, I suggest setting up SSH Public Key Authentication between your server and clients. This will greatly simplify your scripts.
Use the -C flag for compression with the scp and ssh commands.
You should copy the log files from the clients to the server and do processing on the server.
If you can choose a different scripting language such as Python, Tcl (You used Expect, which is really Tcl). Bash can handle your problem, but you will find other languages work better. This is my opinion, of course.
Get one piece of your puzzle to work before moving on to the next. For example, right now, your get_list_of_clients() function does not yet working.
That being said, here is a rewrite of get_list_of_clients, which I tested and it works within my assumptions about your $CLIENT_IP_LIST file:
function get_list_of_clients() {
let row=1
while read line
do
if (( row > 1 ))
then
set $line # Breaks line into pieces
CLIENT_IP="$3"
echo "$CLIENT_IP"
fi
let row=row+1
done < $CLIENT_IP_LIST
}

Resources