我制作了一个 DHCP 服务器,可以发送带有 IP 的报价数据包。我尝试使用下面的“get router ip”获取路由器 IP,只将第四个值更改为 2 到 254。然后,我将随机 IP 作为子网 IP 发送。但是,当客户端使用此 IP 将其绑定到套接字时,我收到一条错误消息,提示“socket.error:[errno 99] 无法分配请求的地址”。我尝试将 setsockopt 与 SO_REUSEADDR 和 SO_REUSEPORT 一起使用,但问题不在于其他人已连接。请帮忙。 (我正在使用虚拟机在 Linux 上运行它。)
DHCP 服务器代码
import socket
from time import sleep
from scapy.all import *
from scapy.layers.dhcp import BOOTP, DHCP
from scapy.layers.inet import UDP, IP
from scapy.layers.l2 import Ether, ARP
import random
import ipaddress
requested_ips = {}
assigned_ips = {}
domain_ip = ""
router_ip = ""
def get_router_ip():
# Create a UDP socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80)) # connect to a remote host
return s.getsockname()[0] # get the local IP address
# Create random IP address
def get_random_ip():
global router_ip
if router_ip == "":
router_ip = get_router_ip()
router_ip = router_ip.split(".")[:-1]
router_ip = ".".join(router_ip)
return router_ip + "." + str(random.randint(2, 254))
# Function to check if an IP address is in use
def ip_in_use(ip):
arp_request = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op="who-has", pdst=ip)
arp_response = srp1(arp_request, timeout=1, verbose=0)
if arp_response is not None:
return True
else:
return False
# Define a function to handle DHCP requests
def handle_dhcp_request(pkt):
if DHCP in pkt and pkt[DHCP].options[0][1] == 1:
print("DHCP Discover received")
client_mac = pkt[Ether].src
# Generate a random IP address if no specific IP was requested
random_ip = get_random_ip()
# Check if the requested IP address is already in use on network
while ip_in_use(random_ip):
print(f"Requested IP {random_ip} is already in use, offering random IP")
random_ip = get_random_ip()
# Check if the IP address was already assigned by the DHCP server
while assigned_ips and random_ip in assigned_ips.values():
random_ip = get_random_ip()
requested_ips[client_mac] = random_ip
offer = Ether(src=get_if_hwaddr(conf.iface), dst=client_mac)/ \
IP(src="192.168.1.1", dst=random_ip)/ \
UDP(sport=67, dport=68)/ \
BOOTP(op=2, yiaddr=random_ip, siaddr="192.168.1.1", giaddr="0.0.0.0", xid=pkt[BOOTP].xid)/ \
DHCP(options=[("message-type", "offer"),
("subnet_mask", "255.255.255.0"),
("router", "192.168.1.1"),
("lease_time", 86400),
("name_server", domain_ip),
"end"])
# Send offer to client
sleep(1)
sendp(offer, iface=conf.iface)
print(f"DHCP Offer sent with IP: {random_ip}")
# Create an IP address for the DNS server
domain_ip = get_random_ip()
# Set up a sniffing filter for DHCP requests
sniff_filter = "udp and (port 67 or 68)"
# Start sniffing for DHCP requests
print("DHCP Server started.")
print(f"Domain IP: {domain_ip}")
sniff(filter=sniff_filter, prn=handle_dhcp_request)
客户代码
from scapy.all import *
from scapy.layers.dhcp import BOOTP, DHCP
from scapy.layers.inet import UDP, IP
from scapy.layers.l2 import Ether
import socket
import random
ip = ""
port = 53
def get_random_mac():
return "%02x:%02x:%02x:%02x:%02x:%02x" % (
random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255), random.randint(0, 255))
# Ask for a random IP
def send_discover(src_mac):
pkt = Ether(dst='ff:ff:ff:ff:ff:ff', src=src_mac, type=0x0800) / IP(src='0.0.0.0', dst='255.255.255.255') / \
UDP(dport=67, sport=68) / BOOTP(op=1, chaddr=src_mac) / DHCP(options=[('message-type', 'discover'), 'end'])
sendp(pkt, iface=conf.iface)
# Define a function to handle DHCP Offer packets and print the IP address
def __handle_dhcp_offer(pkt):
if DHCP in pkt and pkt[DHCP].options[0][1] == 2:
print("DHCP Offer received")
print("Server IP address: ", pkt[IP].src)
print("Offered IP address: ", pkt[BOOTP].yiaddr)
# Sniff IP from DHCP Offer packet
def receive_offer():
# Set up a sniffing filter for DHCP Offer packets
sniff_filter = "udp and (port 67 or 68)"
# Start sniffing for DHCP Offer packets
return sniff(filter=sniff_filter, prn=__handle_dhcp_offer, timeout = 3)
if __name__ == "__main__":
# Get the local DNS IP address
mac = get_random_mac()
send_discover(mac)
pkt = receive_offer()
server_ip = pkt[0][IP].src
offered_ip = pkt[0][BOOTP].yiaddr
dns_ip = pkt[0][DHCP].options[4][1]
# Start the DNS server
ip = dns_ip
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
print("DNS server started on port " + str(port) + " and IP " + ip)
我假设
tcpdump
会显示看起来合理的 DHCP 数据包。
显然一切都在赢,直到这一点
客户恢复offered_ip
.的地方
但是你想使用那个IP。 在大多数以太网媒体上,这意味着 你不仅想用那个 src 地址发送, 但您还希望 NIC 响应新 IP 的 ARP 请求。
看看你运行的启动脚本, 像
/etc/network/if-up.d/ethtool
和/sbin/dhclient-script
。
你可能想要运行一个 ifconfig
子进程
在某个时候,对吧?这样使用 ifconfig
查看您的以太网界面将显示
那个闪闪发光的新 IP 地址。