更改DenyHosts报告:从Python调用外部命令

时间:2012-03-21 08:16:25

标签: python

首先,我不知道关于Python的第一件事......所以我真的可以使用你拥有的任何指针。我知道一些Perl,Bash脚本和一点C ++。

我正在运行DenyHosts(http://denyhosts.sourceforge.net/),它时不时地通过电子邮件向我发送一条消息,说明IP地址已添加到/etc/deny.hosts。例如:

Added the following hosts to /etc/hosts.deny:

87.215.133.109 (unknown)

----------------------------------------------------------------------

到目前为止一直很好,但我想在此消息中添加IP地址的国家/地区。为此,我创建了一个小的Perl脚本,它吐出了国家:

/usr/local/bin/geo-ip.pl --short 87.215.133.109
Netherlands

所以我想做的就是从Python调用这个Perl脚本,然后在消息字符串中填充结果。我找到了我怀疑需要更改的源代码,但正如本消息顶部所公布的,我不知道Python的第一件事。

这是来自主程序的一个sniplet,它调用report.py

中的子程序

deny_hosts.py:

#print deny_hosts
new_denied_hosts, status = self.update_hosts_deny(deny_hosts)
if new_denied_hosts:
    if not status:
        msg = "WARNING: Could not add the following hosts to %s" % self.__prefs.get('HOSTS_DENY')
    else:
        msg = "Added the following hosts to %s" % self.__prefs.get('HOSTS_DENY')
    self.__report.add_section(msg, new_denied_hosts)
    if self.__sync_server: self.sync_add_hosts(new_denied_hosts)
    plugin_deny = self.__prefs.get('PLUGIN_DENY')
    if plugin_deny: plugin.execute(plugin_deny, new_denied_hosts)

我认为改变应该在这里。 report.py定义了add_section:

def add_section(self, message, iterable):
    self.report += "%s:\n\n" % message
    for i in iterable:
        if type(i) in (TupleType, ListType):
            extra = ": %d\n" % i[1]
            i = i[0]
        else:
            extra = ""
        if self.hostname_lookup:
            hostname = self.get_hostname(i)
            debug("get_host: %s", hostname)
        else: hostname = i

        self.report += "%s%s\n" % (hostname, extra)

        if self.use_syslog:
            syslog.syslog("%s - %s%s" %(message, hostname, extra))
    self.report += "\n" + "-" * 70 + "\n"

请帮我改变代码,以便它会发出如下信息:

Added the following hosts to /etc/hosts.deny:

87.215.133.109 (Netherlands, unknown)

----------------------------------------------------------------------

EDIT3: 这就是我解决它的方式。输出与原始消息相同。更改源后,需要重启守护进程(sudo /etc/init.d/denyhosts restart)

    def add_section(self, message, iterable):
    # added geo-ip
    # moving this from statement to the top of the file makes pycheck generate
    # a lot of errors, so I left it here.
    from subprocess import Popen, PIPE
    # end geo-ip hack import
    self.report += "%s:\n\n" % message
    for i in iterable:
        if type(i) in (TupleType, ListType):
            extra = ": %d\n" % i[1]
            i = i[0]
        else:
            extra = ""
        if self.hostname_lookup:
            hostname = self.get_hostname(i)
            debug("get_host: %s", hostname)
        else: hostname = i

        # self.report += "%s%s\n" % (hostname, extra)
        # JPH: added geo-ip
        geocmd = "/usr/local/bin/geo-ip.pl --short %s" % i
        country = Popen( geocmd, shell=True, stdout=PIPE).communicate()[0]
        country = country.strip()
        self.report += "%s%s\n%s\n" % (hostname, extra, country)
        # end geo-ip hack            

        if self.use_syslog:
            syslog.syslog("%s - %s%s" %(message, hostname, extra))
    self.report += "\n" + "-" * 70 + "\n"

也帮助我理解我改变了什么,所以我今天也可以学习一点Python。

EDIT2 :为了共享指向geo-ip.pl脚本的链接http://wirespeed.xs4all.nl/mediawiki/index.php/Geo-ip.pl

EDIT1 :当源更改时自动完成重新编译,以便回答以下问题。 我遇到的第二个问题是我在我的系统上找到了两个匹配的文件:

  • /usr/share/denyhosts/DenyHosts/report.py
  • /usr/share/denyhosts/DenyHosts/report.pyc

其中.py是源代码,我怀疑.pyc实际上正在执行。因此,当我更改源代码时,如果我之后不以某种方式编译它,我不会感到惊讶。

2 个答案:

答案 0 :(得分:2)

我只会回答你关于如何通过python调用你的perl脚本并得到输出的问题的具体部分。关于在这个信息中的哪个位置的部分对我来说有点太模糊,无法从你的片段中猜出......

from subprocess import Popen, PIPE

hostIP = "87.215.133.109"
cmd = "/usr/local/bin/geo-ip.pl --short %s" % hostIP
output = Popen(cmd, shell=True, stdout=PIPE).communicate()[0]

## alternate form ##
# cmd = ["/usr/local/bin/geo-ip.pl, "--short", hostIP]
# output = Popen(cmd, stdout=PIPE).communicate()[0]

print output.strip() 
# Netherlands

更新

由于我在Popen系列上同时做了一些事情,而你是python的新手(基于你在下面的评论),我想为你分解一下......

# this call to Popen actually returns a 
# Popen object with a number of methods and attributes
# to interact with the process that was just created
p = Popen(cmd, shell=True, stdout=PIPE)

# communicate() is a method of a Popen object which
# allows you to wait for the return output of the pipes
# that you named (or send data to stdin)
# It blocks until data is ready and returns a tuple (stdout, stderr)
stdout, stderr = p.communicate()

# We only wanted the stdout in this case, so we took the first index
output = p.communicate()[0]

# output is a string, and strings have the strip() method to remove 
# surrounding whitespace
stripped_output = output.strip()

答案 1 :(得分:1)

这可以解决问题:

import subprocess
country = subprocess.check_output(
    ["/usr/local/bin/geo-ip.pl", "--short", "87.215.133.109"])