LoginSignup
2
1

More than 1 year has passed since last update.

ろうとるがPythonを扱う、、(その7:nmapとmultiping)

Posted at

ポートOpen/Close確認やマルチpingの実行

pythonのnmapモジュールおよびICMPLibを使って、ポートOpen/Closeなどの確認やマルチpingの実行を、tkinterによりGUIプログラム化する。

ポートOpen/Closeなどの確認

ある特定のIPアドレスおよびポート番号にて、nmapのいくつかのオプション結果を同時に確認したかった(あまりそのようなものを見たことがなかった)ので、作ってみることにした。下記スキャンの結果を同時に表示する。

  • -sS:TCP Synスキャン
  • -sA:TCP Ackスキャン
  • -sN:TCP Nullスキャン
  • -sU:UDPスキャン

同一サブネット内のIPアドレス複数にping

例えば、「192.168.1.42/29」の場合、下記のIPアドレスにpingを行い、リプライがあったIPアドレスを表示する。

  • 192.168.1.41
  • 192.168.1.42
  • 192.168.1.43
  • 192.168.1.44
  • 192.168.1.45
  • 192.168.1.46

実行結果例

nmap

nmap結果.png

マルチping

MultiPing.png

ソースコード

nmap

import nmap

def ExecNmap(ip, num, arg, out):
    nm = nmap.PortScanner()
    scan_result = nm.scan(hosts = ip, ports = num, arguments = arg)
    out = out + nm.command_line() + '\n'
    #print(scan_result['scan'])
    target = next(iter(scan_result['scan'])) # for domain name ('ip' cannot be used.)
    if arg == '-sU':
        detail = scan_result['scan'][target]['udp']
    else:
        detail = scan_result['scan'][target]['tcp']
    first = next(iter(detail)) # 'num' does not work
    out = out + ' state: ' + detail[first]['state'] \
        + '\t\t\treason: ' + detail[first]['reason'] + '\n\n'
    return out
  • out:結果を格納するバッファ
  • nm.scan():nmap実行
  • nm.command_line():コマンドラインをバッファに格納
  • scan_result['scan']:nmap実行結果(下記はサンプル)
    {'74.6.143.26': {'hostnames': [{'name': 'yahoo.com', 'type': 'user'}, {'name': 'media-router-fp74.prod.media.vip.bf1.yahoo.com', 'type': 'PTR'}], 'addresses': {'ipv4': '74.6.143.26'}, 'vendor': {}, 'status': {'state': 'up', 'reason': 'echo-reply'}, 'tcp': {80: {'state': 'open', 'reason': 'syn-ack', 'name': 'http', 'product': '', 'version': '', 'extrainfo': '', 'conf': '3', 'cpe': ''}}}}
  • target = next(iter(scan_result['scan'])):結果の最初の要素であるIPアドレスを取得(対象IPアドレスをドメイン名で指定したときにも対応するため)
  • TCPスキャンかUDPスキャンかで取得の仕方を変える
  • first = next(iter(detail)):ポート番号を文字列化
  • 「state」および「reason」の結果をバッファに格納

multiPing

from netaddr import *
from icmplib import *

def ExecPing(arg):
    ipNet = IPNetwork(arg)
    ipList=list(ipNet)
    Len = len(ipList)
    target = []
    for ip in ipList[1:Len-1]:
        target.append(str(ip))
    hosts = multiping(target, count=3)
    return hosts
  • netaddr(IPNetwork())により同一サブネット内のIPアドレス群を取得
  • 最初(ネットワークアドレス)および最後(ブロードキャストアドレス)を除いたIPアドレスのリスト化(target)
  • マルチping実行

OKボタンクリック

def ok_clk(frm, arg):
    ip = frm.entry1.get()
    if arg == 0:
        num = frm.entry2.get()
        out = ''
        out = ExecNmap(ip, num, '-sS', out)
        out = ExecNmap(ip, num, '-sA', out)
        out = ExecNmap(ip, num, '-sN', out)
        out = ExecNmap(ip, num, '-sU', out)
    else:
        hosts = ExecPing(ip)
        out = 'ping to ' + ip + '\n'
        for host in hosts:
            if host.is_alive:
                out = out + ' ' + host.address + '\tis up' + '\n'
    frm.text.config(state='normal')   # editable
    frm.text.insert(tk.END, out)
    frm.text.config(state='disabled') # not editable
    frm.text.see('end')
    return
  • Entryボックスに入力された内容の取得
  • nmap実行関数またはマルチping実行関数の呼び出し
  • マルチpingの場合は、結果の加工
  • テキストボックスへ結果をアウトプット

タブ作成

def create_content(frm, arg):
    frm1 = tk.Frame(frm)
    frm2 = tk.Frame(frm)
    frm1.pack()
    frm2.pack()
    frm.entry1 = ttk.Entry(frm1, width=20)
    frm.entry1.grid(row=0, column=1)
    if arg == 0:
        label = ttk.Label(frm1, text='Enter IP address and Port Number')
        frm.entry2 = ttk.Entry(frm1, width=10)
        frm.entry2.grid(row=0, column=2)
    else:
        label = ttk.Label(frm1, text='Enter Network (ex 192.168.1.0/24)')
    label.grid(row=0, column=0)
    okBtn = ttk.Button(frm1, text='OK', command=lambda:ok_clk(frm, arg))
    okBtn.grid(row=0, column=3)
    frm.text = tk.Text(frm2, width=80, height=40)
    ysc = tk.Scrollbar(frm2, orient=tk.VERTICAL, command=frm.text.yview)
    frm.text["yscrollcommand"] = ysc.set
    ysc.pack(side=tk.RIGHT, fill="y")
    frm.text.config(state='disabled') # not editable
    frm.text.pack()
    return

ここは、その5あたりを参照されたし。

メインプログラム

# root main window
root = tk.Tk()
root.title("Port Check & Multi Ping")
root.geometry("600x400")

# Create an instance of ttk style
fgcolor = "lightskyblue2"
bgcolor = "gray80"
style = ttk.Style()
style.theme_create("style1", parent="alt", settings={
        "TNotebook.Tab": {
            "configure": {"background": bgcolor },
            "map":       {"background": [("selected", fgcolor)],
                          } } } )
style.theme_use("style1")

# Create Notebook Widget
note = ttk.Notebook(root)

# Create tab
tab0 = tk.Frame(note)
tab1 = tk.Frame(note)

# Add tab
note.add(tab0, text=tab_list[0])
note.add(tab1, text=tab_list[1])

# Create content of tab
create_content(tab0, 0)
create_content(tab1, 1)

# Locate tab
note.pack(expand=True, fill='both')

# main loop
root.mainloop()

ここも、その5を参照されたし。

全体

import nmap
from netaddr import *
from icmplib import *
import tkinter as tk
import tkinter.ttk as ttk

# command to execute
tab_list = [' nmap: -sS, -sA, -sN, -sU ', ' ping for subnet ']

# execute nmap
def ExecNmap(ip, num, arg, out):
    nm = nmap.PortScanner()
    scan_result = nm.scan(hosts = ip, ports = num, arguments = arg)
    out = out + nm.command_line() + '\n'
    #print(scan_result['scan'])
    target = next(iter(scan_result['scan'])) # for domain name ('ip' cannot be used.)
    if arg == '-sU':
        detail = scan_result['scan'][target]['udp']
    else:
        detail = scan_result['scan'][target]['tcp']
    first = next(iter(detail)) # 'num' does not work
    out = out + ' state: ' + detail[first]['state'] \
        + '\t\t\treason: ' + detail[first]['reason'] + '\n\n'
    return out

# execute multi-ping
def ExecPing(arg):
    ipNet = IPNetwork(arg)
    ipList=list(ipNet)
    Len = len(ipList)
    target = []
    for ip in ipList[1:Len-1]:
        target.append(str(ip))
    hosts = multiping(target, count=3)
    return hosts

# Function for click OK
def ok_clk(frm, arg):
    ip = frm.entry1.get()
    if arg == 0:
        num = frm.entry2.get()
        out = ''
        out = ExecNmap(ip, num, '-sS', out)
        out = ExecNmap(ip, num, '-sA', out)
        out = ExecNmap(ip, num, '-sN', out)
        out = ExecNmap(ip, num, '-sU', out)
    else:
        hosts = ExecPing(ip)
        out = 'ping to ' + ip + '\n'
        for host in hosts:
            if host.is_alive:
                out = out + ' ' + host.address + '\tis up' + '\n'
    frm.text.config(state='normal')   # editable
    frm.text.insert(tk.END, out)
    frm.text.config(state='disabled') # not editable
    frm.text.see('end')
    return

# Create content of tab
def create_content(frm, arg):
    frm1 = tk.Frame(frm)
    frm2 = tk.Frame(frm)
    frm1.pack()
    frm2.pack()
    frm.entry1 = ttk.Entry(frm1, width=20)
    frm.entry1.grid(row=0, column=1)
    if arg == 0:
        label = ttk.Label(frm1, text='Enter IP address and Port Number')
        frm.entry2 = ttk.Entry(frm1, width=10)
        frm.entry2.grid(row=0, column=2)
    else:
        label = ttk.Label(frm1, text='Enter Network (ex 192.168.1.0/24)')
    label.grid(row=0, column=0)
    okBtn = ttk.Button(frm1, text='OK', command=lambda:ok_clk(frm, arg))
    okBtn.grid(row=0, column=3)
    frm.text = tk.Text(frm2, width=80, height=40)
    ysc = tk.Scrollbar(frm2, orient=tk.VERTICAL, command=frm.text.yview)
    frm.text["yscrollcommand"] = ysc.set
    ysc.pack(side=tk.RIGHT, fill="y")
    frm.text.config(state='disabled') # not editable
    frm.text.pack()
    return

# Start of main program
# root main window
root = tk.Tk()
root.title("Port Check & Multi Ping")
root.geometry("600x400")

# Create an instance of ttk style
fgcolor = "lightskyblue2"
bgcolor = "gray80"
style = ttk.Style()
style.theme_create("style1", parent="alt", settings={
        "TNotebook.Tab": {
            "configure": {"background": bgcolor },
            "map":       {"background": [("selected", fgcolor)],
                          } } } )
style.theme_use("style1")

# Create Notebook Widget
note = ttk.Notebook(root)

# Create tab
tab0 = tk.Frame(note)
tab1 = tk.Frame(note)

# Add tab
note.add(tab0, text=tab_list[0])
note.add(tab1, text=tab_list[1])

# Create content of tab
create_content(tab0, 0)
create_content(tab1, 1)

# Locate tab
note.pack(expand=True, fill='both')

# main loop
root.mainloop()

EOF

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1