如何从 DHCP 服务器提供 IP?

问题描述 投票:0回答:1

我制作了一个 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)
python networking dhcp
1个回答
0
投票

我假设

tcpdump
会显示看起来合理的 DHCP 数据包。 显然一切都在赢,直到这一点 客户恢复
offered_ip
.

的地方

但是你想使用那个IP。 在大多数以太网媒体上,这意味着 你不仅想用那个 src 地址发送, 但您还希望 NIC 响应新 IP 的 ARP 请求。

看看你运行的启动脚本, 像

/etc/network/if-up.d/ethtool
/sbin/dhclient-script
。 你可能想要运行一个
ifconfig
子进程 在某个时候,对吧?这样使用 ifconfig 查看您的以太网界面将显示 那个闪闪发光的新 IP 地址。

© www.soinside.com 2019 - 2024. All rights reserved.