我想在python上编写简单的udp端口扫描程序,但我遇到了一些问题。
首先,我理解有3个选项:
发送UDP - 什么都没得 - >端口被过滤|打开
发送UDP - get icmp port unreachable - >港口已关闭
发送UDP - 获取UDP - 端口已打开
我创建了raw socket,create ip header和udp header。在udp头中写入dest端口并添加一些数据。
然后我将它发送到服务器并与select
等待回复。但在开放的港口和封闭的港口都没有。只有超时。
是否可以发送虚拟数据但不能更正下一级的数据包?
[Update 1]
添加了更多要在udp数据包中发送的数据。现在我从(194.226.244.126
,53)获得udp数据包但我的主机在我读取任何收到的数据之前将icmp类型3发送回194.226.244.126
。但仍然没有来自8.8.8.8
[更新2] 发现8.8.8.8仅回复正确的dns数据包。但仍然无法使用原始套接字读取udp数据包。
import socket
import time
import select
import sys
from packets_headers import iphdr, udphdr
from get_ip import Getip
timeout = 3
host = "8.8.8.8"
port = 53
my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW)
udp_header = udphdr(b"00000000000000000", port, 4242)
udp_packet = udp_header.assemble()
g = Getip()
ip_packet_header = iphdr(socket.IPPROTO_UDP, g.get_lan_ip(), host)
ip_packet_header.data = udp_packet
ip_packet = ip_packet_header.assemble()
my_socket.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
full_packet = ip_packet
while full_packet:
sent = my_socket.sendto(full_packet, (host, port))
full_packet = full_packet[sent:]
ready = select.select([my_socket], [], [], timeout)
if ready[0] == []: # Timeout
print("Timeout")
sys.exit()
rec_packet, addr = my_socket.recvfrom(1024)
print(rec_packet, addr)
另外packets_header.py
import socket
import struct
import random
class iphdr(object):
"""
This represents an IP packet header.
@assemble packages the packet
@disassemble disassembles the packet
"""
def __init__(self, proto=socket.IPPROTO_ICMP, src="0.0.0.0", dst=None):
self.version = 4
self.hlen = 5
self.tos = 0
self.length = 20
self.id = random.randint(2 ** 10, 2 ** 16)
self.frag = 0
self.ttl = 255
self.proto = proto
self.cksum = 0
self.src = src
self.saddr = socket.inet_aton(src)
self.dst = dst or "0.0.0.0"
self.daddr = socket.inet_aton(self.dst)
self.data = ""
def assemble(self):
header = struct.pack('BBHHHBB',
(self.version & 0x0f) << 4 | (self.hlen & 0x0f),
self.tos, self.length + len(self.data),
socket.htons(self.id), self.frag,
self.ttl, self.proto)
self._raw = header + b"\x00\x00" + self.saddr + self.daddr + self.data
return self._raw
@classmethod
def disassemble(self, data):
self._raw = data
ip = iphdr()
pkt = struct.unpack('!BBHHHBBH', data[:12])
ip.version = (pkt[0] >> 4 & 0x0f)
ip.hlen = (pkt[0] & 0x0f)
ip.tos, ip.length, ip.id, ip.frag, ip.ttl, ip.proto, ip.cksum = pkt[1:]
ip.saddr = data[12:16]
ip.daddr = data[16:20]
ip.src = socket.inet_ntoa(ip.saddr)
ip.dst = socket.inet_ntoa(ip.daddr)
return ip
def __repr__(self):
return "IP (tos %s, ttl %s, id %s, frag %s, proto %s, length %s) " \
"%s -> %s" % \
(self.tos, self.ttl, self.id, self.frag, self.proto,
self.length, self.src, self.dst)
class udphdr(object):
def __init__(self, data="", dport=4242, sport=4242):
self.dport = dport
self.sport = sport
self.cksum = 0
self.length = 0
self.data = data
def assemble(self):
self.length = len(self.data) + 8
part1 = struct.pack("!HHH", self.sport, self.dport, self.length)
cksum = self.checksum(self.data)
cksum = struct.pack("!H", cksum)
self._raw = part1 + cksum + self.data
return self._raw
@classmethod
def checksum(self, data):
# XXX implement proper checksum
cksum = 0
return cksum
def disassemble(self, data):
self._raw = data
udp = udphdr()
pkt = struct.unpack("!HHHH", data)
udp.src_port, udp.dst_port, udp.length, udp.cksum = pkt
return udp