wget script to connect, wait if successful, continue if no connection - bash

I have to create a script that sends a wget contact message to all devices on our network. wget connects to a url and this trigger the endpoint to contact a server.
The problem I have is I need to be able to send the command to each IP address on the network and if the connection is successful do noting for 30 seconds then move on to the next url in the list. However if the connection isn't successful I want the script to move on to the next url with no pause.
Currently I'm using a bash script to send the command with a pause=30 in-between url's, connection attempts set to 1 and time-out set to 1. this works OK for the connections that are successful but it also hangs on the addresses that are not.
Any advise on how I can pause on success and move on after time out on dead addresses?
This is the command I'm currently running,
wget --connect-timeout=1 --tries=1 http://xx.xx.xx.xx:8085/contact_dls.html/ContactDLS
sleep 30
wget --connect-timeout=1 --tries=1 http://xx.xx.xx.xx:8085/contact_dls.html/ContactDLS
etc etc etc
thanks

You don't need wget for this task - everything can be done in Perl.
Simply use code like this:
use LWP::UserAgent;
use HTTP::Request;
my $ua = new LWP::UserAgent;
$ua->timeout(1);
my $req = new HTTP::Request(GET => $url);
my $res = $ua->request($req);
if ($res->is_success()) {
print("Connection to '$url' was OK");
sleep(30);
} else {
print("Cannot access '$url'");
sleep(1);
}
This will hit your url, but will timeout in just 1 second.

I would probably load the urls into an array and iterate through the array. Something like this
#!/usr/bin/perl
use warnings;
use strict;
my #urls = qw(test.com url.com 123abc.com fail.aa);
foreach my $url (#urls){
my $check = `wget --server-response $url 2>&1 | grep HTTP/ | awk '{print \$2}'`;
#if there is a successful response you can set the sleep(3) to sleep(30) for your instance.
if($check){
print "Found $url -- sleeping 3 seconds\n";
sleep(3);
}
else{
print "$url does not exist\n";
#If the url does not exist or respond it will move on to the next item in the array. You could add a sleep(1) before the next for a 1 second pause
next;
}
}
Of course this is assuming that you are using linux. The urls could be loaded another way as well, I don't know how your current script it getting them. The above is an example and you of course would need to be adjusted to fit your environment

Related

single line bash script for wget with retries

I currently run two commands:
sleep 180
wget https://somedomain.com/api/up
So it waits for 3 minutes and then calls api up
I would like to change that so it continuously checks every minute for up to ten minutes until wget returns 200.
so it should be the equivalent of this php function, but in bash. It is important to be a one liner (can be multiple statements separated by ;)
foreach(range(1,10) as $i) {
sleep(60);
try {
Http::get('https://somedomain.com/api/up');
break;
} catch(Exception $e) {
if($i>=10) throw $e;
}
}
the two things where my bash knowledge fails me:
how to do the try catch or check for a 200 response code.
how to get that all into one line/statement
Use a for loop with all the statements separated by ;
for i in {1..10}; do sleep 60; wget 'https://somedomain.com/api/up' && break; done
for i in {1..5}; do wget -- "$1" && break || sleep 15; done

Getting an error for unexpected else in bash

[SOLVED]
I'm pretty new tho bash-/shell-scripting and trying setup a check for ip address on a server which gets about once a week a new ip.
The script will then send the new ip to the users.
My problem is, that I'm getting a syntax-error in the last if-else statement for "unexpected" else and can wrap my head around why.
My first iteration didn't use functions, but instead one multi lined if-else which got me the same error. The functions on their own seem to work just fine.
#!/bin/bash
# script to send the new server ip to the users
# get the recent ip address of the system
new_ip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}')
file=old_ip.txt
function ip_mail(){
source $file
if [ $new_ip != $old_ip ]
then
# email-address changed for obvious reasons
mail -s "New Server IP" [hidden]#[hidden].com <<< "$new_ip"
echo "old_ip=$new_ip" > old_ip.txt
exit 0
fi
exit 0
}
function set_old(){
touch old_ip.txt
echo "old_ip=$new_ip" > old_ip.txt
exit 0
}
if [ $file ]
then
ip_mail()
else
set_old()
fi

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

Not able to connect to socket using socat

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.

How to use bash/expect to check if an SSH login works

My team manages many servers, and company policy dictates that the passwords on these servers must be changed every couple of weeks. Sometimes, our official database of passwords gets out of date for whatever reason (people forget to update it, usually), but we cannot identify this sometimes until months later, since we don't consistently use every server.
I want to write a script that will scrape the passwords from the database, and use those passwords to attempt an (ssh) login to each server every night, and send an email with the results to the team. I am able to scrape the database for login information, but I'm not sure how to check whether ssh login was successful or not in expect.
I cannot use public key authentication for this task. I want password authentication so I can verify the passwords.
I disable public-key authentication by specifying the following file:
PasswordAuthentication=yes
PubkeyAuthentication=no
My attempts at the expect script:
# $1 = host, $2 = user, $3 = password, $4 = config file
expect -c "spawn ssh $2#$1 -F $4
expect -re \".*?assword.*?\"
send \"$3\n\"
...
send \'^D\'"
I thought maybe exit status could indicate the success? Couldn't find anything in the man pages though.
I've been using something like the script below for a similar task.
#!/bin/sh
# Run using expect from path \
exec expect -f "$0" "$#"
# Above line is only executed by sh
set i 0; foreach n $argv {set [incr i] $n}
set pid [ spawn -noecho ssh $1#$3 $4 ]
set timeout 30
expect {
"(yes/no)" {
sleep 1
send "yes\n"
exp_continue
}
"(y/n)" {
sleep 1
send "y\n"
exp_continue
}
password {
sleep 1
send "$2\n"
exp_continue
}
Password {
sleep 1
send "$2\n"
exp_continue
}
"Last login" {
interact
}
"Permission denied" {
puts "Access not granted, aborting..."
exit 1
}
timeout {
puts "Timeout expired, aborting..."
exit 1
}
eof {
#puts "EOF reached."
}
}
set status [split [wait $pid]]
set osStatus [lindex $status 2]
set procStatus [lindex $status 3]
if { $osStatus == 0 } {
exit $procStatus
} else {
exit $procStatus
}
Do you specifically need to check if you can obtain a shell or is trying to execute a command also OK ?
If you just want to check authentication, you may want to do ssh asimplecommand (using echo, hostname, or something as such) and check if you get the expected result.
You may also want to launch ssh with -v option, and look for Authentication succeeded (at the debug1 log level).
crowbent has provided you an expect script to test ssh login however I would recommend using Non-interactive ssh password auth for testing out ssh/sftp. sshpass is much more secured and less error prone than expect.
The solution to the underlying problem (password database getting out of sync) is to use public key authentication. For everyone. Do NOT bother with passwords when it comes to SSH.
Successful login could be checked like this:
ssh -o PasswordAuthentication=no USER#HOST 'exit' || echo "SSH login failed."

Resources