I have the following nmap command:
nmap -n -p 25 10.11.1.1-254 --open | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\.[0-9]\{1,3\}' | cut -d" " -f5
This produces a list of ip addresses which I'm trying to pass to the following python script:
#!/usr/bin/python
# Python tool to check a range of hosts for SMTP servers that respond to VRFY requests
import socket
import sys
from socket import error as socket_error
# Read the username file
with open(sys.argv[1]) as f:
usernames = f.read().splitlines()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host_ip = sys.argv[2]
print("****************************")
print("Results for: " + host_ip)
try:
c = s.connect((host_ip,25))
banner=s.recv(1024)
#Send VRFY requests and print result
for user in usernames:
s.send('VRFY ' + user + '\r\n')
result = s.recv(1024)
print(result)
print("****************************")
#Close Socket
s.close()
#If error is thrown
except socket_error as serr:
print("\nNo SMTP verify for " +host_ip)
print("****************************")
I've tried to do this with the following command, however it's only running the script over the first ip that it finds:
./smtp_verify.py users.txt $(nmap -n -p 25 10.11.1.1-254 --open | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\.[0-9]\{1,3\}' | cut -d" " -f5)
I've also tried to do this with:
for $ip in (nmap -n -p 25 10.11.1.1-254 --open | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\.[0-9]\{1,3\}' | cut -d" " -f5); do ./smtp_verify.py users.txt $ip done
However I receive a syntax error for it which suggests to me I can't pass pipes this way?
bash: syntax error near unexpected token `('
Do not consciously use for loop for parsing command output, see DontReadLinesWithFor, rather use a Process-Subtitution syntax with a while loop
#!/bin/bash
while IFS= read -r line; do
./smtp_verify.py users.txt "$line"
done< <(nmap -n -p 25 10.11.1.1-254 --open | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\.[0-9]\{1,3\}' | cut -d" " -f5)
And for the error you are likely seeing, you are NOT using command-substitution $(..) syntax properly to run the piped commands, the commands should have been enclosed around () with a $ before it. Something like,
#!/bin/bash
for ip in $(nmap -n -p 25 10.11.1.1-254 --open | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\.[0-9]\{1,3\}' | cut -d" " -f5); do
./smtp_verify.py users.txt "$ip"
done
And remember to always double-quote shell variables to avoid Word Splitting done by the shell.
Related
Where I work, we have servers that are pre-configured for the use of the bash mail command to send attachments and messages. I'm working on a notification script that will monitor server activity and generate an email if it detects an issue. I'm using the subprocess.call function in order to send a bash command.
I am successful in sending messages, but in the body portion of the email, it is stringing each notification line together rather than putting each notification on a separate line. I have tried to append each line within the string with "\n" and "\r\n". I have to use double backslashes as python will interpret this as literal new lines when it sends the echo command. I also passed the command "shopt -s xpg_echo" before using the echo with pipe to mail using the double backspaces but this also had no effect. I also tried using echo without the "-e" option and this had no effect either.
The trick is that I need python to send the new line to bash and then somehow get bash to interpret this as a new line using echo piped through to mail. Here is a sample of the code:
import os
import shutil
import sys
import time
import re
import subprocess
import smtplib
serviceports["SCP Test"] = ["22"]
serviceports["Webtier"] = ["9282"]
bashCommand = "netstat -an | grep LISTEN | grep -v LISTENING"
netstat_results = subprocess.check_output(bashCommand, shell=True)
netstat_results = str(netstat_results)
#Iterate through all ports for each service and assign down ports to variable
for servicename, ports in serviceports.items():
for ind_port in ports:
ind_port_chk = ":" + ind_port
count = sum(1 for _ in re.finditer(r'\b%s\b' % re.escape(ind_port_chk), netstat_results))
if count == 0:
warning = servicename + " on port " + ind_port + " is currently down!"
report.append(warning)
for warning in report:
message = message + warning + "\\\n"
fromaddr=serveridsimp + "#xxxxx.com"
toaddr='email#xxxxx.com'
subject="Testing..."
body=message
cmd= cmd='echo -e '+body+' | mail -s '+subject+' -r '+fromaddr+' '+toaddr
send=subprocess.call(cmd,shell=True)
The code runs a netstat command and assigns it to a string. The code will then iterate through the specified ports and search for where that port doesn't exist in the netstat string (netstat_results). It then will create a list object (warning) containing all the ports not located in netstat_results and then append each line adding \n to a string called "message". It then sends an echo piped to the xmail command to generate an email to be sent containing all the ports not found. What happens currently is that I will get an email saying something like this:
SCP Test on port 22 is currently down!nOHS Webtier on port 9282 is currently down!n etc...
I want it to put each message on a new line like so:
SCP Test on port 22 is currently down!
Webtier on port 9282 is currently down!
I am trying to avoid writing the output to a file and then using bash to read it back into the mail command. Is this possible without having to create a file?
I was finally able to fix the issue by changing the command sent to bash and character being appended to the following:
message = message + warning + "\n"
cmd= cmd='echo -e '+'"'+body+'"'+'|awk \'{ print $0" " }\''+' | mail -s '+'"'+subject+'"'+' -r '+fromaddr+' '+toaddr
I'm writing two scripts, the first in bash and the second one in Python. The desired output is an IP address and the port number on the same line without spaces like
ip:port
Here's the bash:
#! /bin/sh
echo $(find /u01/ -name config.xml |grep -v bak| xargs grep -A4 AdminServer | grep listen-address | cut -d'>' -f 2 | cut -d'<' -f 1)
and its output
172.31.138.15
The Python:
import os
import sys
from java.lang import System
import getopt
import time
values = os.popen(str('sh /home/oracle/scripts/wls/adminurl.sh'))
url = str("".join(map(str, values)))
port = ":7001"
adminurl = url + port + "\n"
def connectToDomain():
try:
if ServerName != "" or username == "" and password == "" and adminUrl == "":
print (adminurl)
connect(userConfigFile='/home/oracle/scripts/wls/userconfig.secure', userKeyFile='/home/oracle/scripts/wls/userkey.secure', url=adminurl, timeout=60000)
[...]
and its output
Initializing WebLogic Scripting Tool (WLST) ...
Welcome to WebLogic Server Administration Scripting Shell
Type help() for help on available commands
172.31.138.15
:7001
Connecting to t3://172.31.138.15
:7001
with userid weblogic ...
This Exception occurred at Fri Jan 10 18:00:22 CET 2020.
javax.naming.ServiceUnavailableException: 172.31.138.15
: unknown error [Root exception is java.net.UnknownHostException: 172.31.138.15
: unknown error]
The domain is unreacheable
I need the ip value on the same line as the port value so that 'adminurl' is recognized as an argument within the 'connect' function.
Any help is appreciated!
adminurl = url.rstrip() + port + "\n"
Here's a quick snippet of my code using pexpect:
child.expect('tc#')
child.sendline('ps -o args | grep lp_ | grep -v grep | sort -n')
child.expect('tc#')
print(child.before)
child.sendline('exit')
and then the output:
user#myhost:~/Python$ python tctest.py
tc-hostname:~$ ps -o args | grep lp_ | grep -v grep | sort -n
/usr/local/bin/lp_server -n 5964 -d /dev/usb/lp1
/usr/local/bin/lp_server -n 5965 -d /dev/usb/lp0
{lp_supervisor} /bin/sh /usr/local/lp/lp_supervisor /dev/usb/lp0 SERIAL#1 /var/run/lp/lp_pid/usb_lp0
{lp_supervisor} /bin/sh /usr/local/lp/lp_supervisor /dev/usb/lp1 SERIAL#2 /var/run/lp/lp_pid/usb_lp1
user#myhost:~$
There's 4 lines of output. The first two lines show with printer port the usb device is assigned to (EX: first line shows port 5964 is assigned to lp1)
The 3rd and 4th lines show which device serial number is assigned to which usb port. (EX: SERIAL#1 is assigned to lp0)
I need to somehow parse that output so I can do the following:
If SERIAL#1 is not assigned to 5964:
run some command
else:
do something else
If SERIAL#2 is not assigned to 5965:
run some command
else:
do something else
I'm not sure how to manipulate that output so I can get the desired variables. Any help is appreciated.
You can extract port and serial information from pexpect data using re.findall and do something like this
import re
data = child.before
ports = re.findall(r'lp_server -n (\d+)', data)
# ['5964', '5965']
serials = re.findall(r'(SERIAL#\d+)', data)
# ['SERIAL#1', 'SERIAL#2']
list(zip(ports, serials))
# [('5964', 'SERIAL#1'), ('5965', 'SERIAL#2')]
for serial, port in zip(ports, serials):
# Check if serial and port matches expectation
Another way of doing it is by using dictionaries to build relationships between device serial numbers and printer ports:
inString = """/usr/local/bin/lp_server -n 5964 -d /dev/usb/lp1
/usr/local/bin/lp_server -n 5965 -d /dev/usb/lp0
{lp_supervisor} /bin/sh /usr/local/lp/lp_supervisor /dev/usb/lp0 SERIAL#1 /var/run/lp/lp_pid/usb_lp0
{lp_supervisor} /bin/sh /usr/local/lp/lp_supervisor /dev/usb/lp1 SERIAL#2 /var/run/lp/lp_pid/usb_lp1"""
inString = inString.split("\n")
matches = dict()
serials = dict()
for i in range(len(inString[:2])):
lp = inString[i][-3:]
printerPort = int(inString[i].split("-n ")[1][:4])
matches.update({lp:printerPort})
for i in range(2,len(inString)):
t = inString[i].split(" ")
lp = t[3][-3:]
serial = t[4]
serials.update({serial:lp})
finalLookup = dict((k,matches[v]) for k,v in serials.items())
print(finalLookup)
Output:
{'SERIAL#1': 5965, 'SERIAL#2': 5964}
Then you can do:
if not finalLookup['SERIAL#1'] == 5964:
run some command
else:
do something else
if not finalLookup['SERIAL#2'] == 5965:
run some command
else:
do something else
I am trying to use os.system to invoke an external (piped) shell command:
srcFile = os.path.abspath(sys.argv[1])
srcFileIdCmd = "echo -n '%s' | cksum | cut -d' ' -f1" % srcFile
print "ID command: %s" % srcFileIdCmd
srcFileID = os.system(srcFileIdCmd)
print "File ID: %s" % srcFileID
outputs
ID command: echo -n '/my/path/filename' | cksum | cut -d' ' -f1
File ID: 0
But when I run
echo -n '/my/path/filename' | cksum | cut -d' ' -f1
manually on a command line, I get 2379496500, not 0.
What do I need to change to get the correct value out of the shell command?
Use
sp = subprocess.Popen(["program", "arg"], stdout=subprocess.PIPE)
instead, and then read from the file sp.stdout. The pogram in question can be a shell, and you can pass complex shell commands to it as parameters (["/usr/bin/bash", "-c", "my-complex-command"]).
I use ifconfig command with awk to catch system's ip addresses
$ ifconfig | grep -E 'inet.[0-9]' | awk '{ print $2}'
127.0.0.1
192.168.8.2
How to convert o/p into a list using python ?
import sys
list_of_lines = [line.strip() for line in sys.stdin]
You might just skip shelling out to call a pipeline of commands. You can get the IP addresses without leaving Python. If you just need the non-loopback IP:
>>> socket.gethostbyname_ex(socket.gethostname())
('furby.home', [], ['192.168.1.5'])
>>> socket.gethostbyname_ex(socket.gethostname())[2][0]
'192.168.1.5'
And to get the loopback,
>>> socket.gethostbyname_ex('localhost')
('localhost', [], ['127.0.0.1'])
There's also a module called netifaces that'll do this in one fell swoop.
import subprocess
lines = subprocess.check_output(["ifconfig | grep -E 'inet.[0-9]' | awk '{ print $2
}'"]).split('\n')
Thanks all . I could do this way.
ipa=[]
f=os.popen("ifconfig | grep -E 'inet.[0-9]' | awk '{ print $2}'")
for i in f.readlines():
ipa.append(i.rstrip('\n'))
return ipa
I just modified the code posted by #Pujan to make it work for linux. (tested in Ubuntu 12.04):
import os
ipa=[]
f=os.popen("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " + "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
for i in f.readlines():
ipa.append(i.rstrip('\n'))
print ipa
Use sys.stdin to read this output.
Then redirect the output as follows:
$ ifconfig | grep -E 'inet.[0-9]' | awk '{ print $2}' | myProg.py