Python检查UDP端口是否打开

5

我正在尝试使用Python 3.6检查远程DNS服务器是否在53端口上监听UDP。

这是我尝试过的方法:

def check_port(host, port):
    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(1)
    try:
        result = s.connect_ex((host, port))
    except socket.gaierror:
        s.close()
        return 1
    s.close()
    return result  # 0 == Port is open

即使端口关闭,我总是得到0。尝试使用SOCK_STREAM进行TCP通信非常顺畅。

我还尝试了:

def check_port_udp(host, port):
    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(1)
    try:
        s.sendto('ping'.encode(), (host, port))
        s.recvfrom(1024)
    except socket.timeout:
        s.close()
        print(1)
        return 1
    s.close()
    print(0)
    return 0  # 0 == Port is open

即使端口已经打开,我仍然一直收到 1 的响应。


1
你尝试了什么,有哪些错误? - klutt
1
你尝试了哪些选项? - Max
1
您可能希望阅读此文以了解 UDP 扫描完全失败的原因:https://community.qualys.com/docs/DOC-1185 - Max
谢谢Max,那篇文章解释了我所缺少的内容。 - Adrian Gherasim
如果在Linux上运行Python脚本,您需要知道访问TCP/UDP端口<1024的权限被Linux内核拒绝,除非所有应用程序都以root特权运行。在Linux上以root身份运行Python脚本是否有所不同? - Mofi
4个回答

3

我尝试使用套接字实现这个目的,但是没有成功。端口响应基于目标应用程序,不像TCP那样标准化。我总是使用netcat来完成这个任务:

import os
ip = "127.0.0.1"
port = "<some_udp_port>"
''' send to /dev/null 2>&1 to suppress terminal output '''
res = os.system("nc -vnzu "+ip+" "+port+" > /dev/null 2>&1")
if res == 0:
    print("port alive")
else:
    print("port dead")

显然,这需要在Linux系统上运行。但是如果您在Windows系统上安装了nmap,则可以尝试以下操作:
import os
ip = "127.0.0.1"
port = "<some_udp_port>"
res = os.system("ncat -vnzu "+ip+" "+port)
if res == 0:
    print("port alive")
else:
    print("port dead")

3
基本思路:向该端口发送DNS查询。如果有响应,则该端口是开放的。
import random
import socket
import struct


class SendDNSPkt:
    def __init__(self,url,serverIP,port=53):
        self.url=url
        self.serverIP = serverIP
        self.port=port
    def sendPkt(self):
        pkt=self._build_packet()
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(1)
        sock.sendto(bytes(pkt), (self.serverIP, self.port))
        data, addr = sock.recvfrom(1024)
        sock.close()
        return data

    def _build_packet(self):
        randint = random.randint(0, 65535)
        packet = struct.pack(">H", randint)  # Query Ids (Just 1 for now)
        packet += struct.pack(">H", 0x0100)  # Flags
        packet += struct.pack(">H", 1)  # Questions
        packet += struct.pack(">H", 0)  # Answers
        packet += struct.pack(">H", 0)  # Authorities
        packet += struct.pack(">H", 0)  # Additional
        split_url = self.url.split(".")
        for part in split_url:
            packet += struct.pack("B", len(part))
            for s in part:
                packet += struct.pack('c',s.encode())
        packet += struct.pack("B", 0)  # End of String
        packet += struct.pack(">H", 1)  # Query Type
        packet += struct.pack(">H", 1)  # Query Class
        return packet

def checkDNSPortOpen():
    # replace 8.8.8.8 with your server IP!
    s = SendDNSPkt('www.google.com', '8.8.8.8')
    portOpen = False
    for _ in range(5): # udp is unreliable.Packet loss may occur
        try:
            s.sendPkt()
            portOpen = True
            break
        except socket.timeout:
            pass
    if portOpen:
        print('port open!')
    else:
        print('port closed!')

if __name__ == '__main__':
    checkDNSPortOpen()

受这个帖子的启发


0

首先

yum安装 -y nmap-ncat

然后

import os
ip = "127.0.0.1"
port = "<some_udp_port>"
''' send to /dev/null 2>&1 to suppress terminal output '''
res = os.system("nc -vnzu "+ip+" "+port+" > /dev/null 2>&1")
if res == 0:
    print("port alive")
else:
    print("port dead")

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0
以下代码可以帮助您扫描53/udp端口:
from socket import *
import sys, time
from datetime import datetime

host = ''
ports = [53]

def scan_host(host, port, r_code = 1) : 
    try : 
        s = socket(AF_INET, SOCK_DGRAM)
        code = s.connect_ex((host, port))
        if code == 0 : 
            r_code = code
        s.close()
    except Exception, e : 
        pass
    return r_code

try : 
    host = raw_input("[*] Enter Target Host Address :  ")
except KeyBoardInterrupt : 
    sys.exit(1)

hostip = gethostbyname(host)

for port in ports : 
    try : 
        response = scan_host(host, port)
        if response == 0 : 
            print("[*] Port %d: Open" % (port))
    except Exception, e : 
        pass

您可以参考此示例来进一步探索端口扫描。


我已经尝试过这个了,即使端口没有打开,你始终会得到“0”。 - Adrian Gherasim
请问您能否解释一下代码的哪个部分使它成为UDP连接而不是TCP连接? - Uddhav Mishra
@UddhavMishra - 这是 SOCK_DGRAM 参数。它发送用户数据报(因此是UDProtocol);) - Janusz 'Ivellios' Kamieński

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接