可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am new to python and learning some network programming, I wish to send an DHCP Packet through my tap interface to my DHCP server and expecting some response from it. I tried with several packet building techniques such a structs and ctypes and ended up with using scapy. Here I am able to send DHCP Packet but unable to get any response from the DHCP server(Analyzed using wireshark and tcpdump)..My packet looked like same as original DHCP packet but failed to get response. Here is my code
import socket from scapy.all import * def main(): if len(sys.argv)<3: print " fewer arguments." sys.exit(1) else: tap_interface = sys.argv[1] src_mac_address = sys.argv[2] ethernet = Ether(dst='ff:ff:ff:ff:ff:ff',src=src_mac_address,type=0x800) ip = IP(src ='0.0.0.0',dst='255.255.255.255') udp =UDP (sport=68,dport=67) fam,hw = get_if_raw_hwaddr(tap_interface) bootp = BOOTP(chaddr = hw, ciaddr = '0.0.0.0',xid = 0x01020304,flags= 1) dhcp = DHCP(options=[("message-type","discover"),"end"]) packet = ethernet / ip / udp / bootp / dhcp fd = open('/dev/net/tun','r+') TUNSETIFF = 0x400454ca IFF_TAP = 0x0002 IFF_NO_PI = 0x1000 mode = IFF_TAP | IFF_NO_PI ifr = struct.pack('16sH', tap_interface, IFF_TAP | IFF_NO_PI) fcntl.ioctl(fd,TUNSETIFF,ifr) while True: sendp(packet, iface = tap_interface) time.sleep(10) if __name__ == '__main__': main()
Is there any other ways of achieving this? If so please do mention them as well. Thanks in Advance.
回答1:
Solved ! I had the same problem,
The problem I think was on the srp() function, it can't receive packets on port 68, but I've created a new function with a new thread that sniffs BOOTP messages and displays the packet fields. you can simulate it :
sniff(iface=myiface, filter="port 68 and port 67")
then send the packet using srp() or sendp() func :)
NOTE: I have used multithreading mechanism cause my program sends messages and sniffs if a rogue DHCP Server is on the network
回答2:
I am not sure if this would qualify as an answer, but we use scapy to simulate DHCP server/client exchange, and the following does the job for us:
discover = Ether(dst='ff:ff:ff:ff:ff:ff', src=cliMAC, type=0x0800) / IP(src='0.0.0.0', dst='255.255.255.255') / UDP(dport=67,sport=68) / BOOTP(op=1, chaddr=cliMACchaddr) / DHCP(options=[('message-type','discover'), ('end')])
The main difference between my code and yours seem to be how the BOOTP header is defined. Maybe you could try my packet definition and see if it works?
回答3:
Here is an example that I did that gets a dhcp address and assigns it to an ip interface:
My rough POC, while creating code for my project:
#!/usr/bin/python from scapy.all import Ether,IP,UDP,DHCP,BOOTP,get_if_raw_hwaddr,get_if_hwaddr,conf,sniff,sendp from pyroute2 import IPDB from Queue import Empty from multiprocessing import Process, Queue, Manager from wpa_supplicant.core import WpaSupplicantDriver from twisted.internet.selectreactor import SelectReactor import threading import time import errno import sys import types import netifaces import dbus import json import re class PythonDHCPScanner: def change_ip(self,ipObject,netInterface): ipdb = IPDB() ips= ipdb.interfaces[self.get_interface(netInterface)] ipAddrs = ips.ipaddr.ipv4[0] ips.del_ip(ipAddrs['address'],ipAddrs['prefixlen']) ips.add_ip(ipObject['ipAddr'],24) ipdb.commit() ipdb.routes.add(dst="default",gateway=ipObject['router']) ipdb.commit() def queue_get_all(self): items = [] maxItems = 50 for numOfItemsRetrieved in range(0, maxItems): try: items.append(self.q.get_nowait()) except Empty, e: break return items def __init__(self): self.net_iface = netifaces.interfaces() def dhcp_print(self,pkt): self.q.put(str(pkt)) def get_interface(self,number): return str(self.net_iface[number].decode()) def get_interfaces(self): return self.net_iface def get_dhcp_object(self,interfaceNumber): self.q = Manager().Queue() c = Process(target=self.callSniffer,args=(interfaceNumber,)).start() time.sleep(0.1) p = Process(target=self.callPacket(interfaceNumber)).start() time.sleep(5) if c is not None: c.join() dhcp = {} for strPkt in self.queue_get_all(): try: pkt = Ether(strPkt) pkt.show() if pkt[Ether].dst == get_if_hwaddr(self.get_interface(interfaceNumber)): if pkt[DHCP]: if pkt.getlayer(DHCP).fields['options'][0][1] == 2: if pkt[IP]: dhcp['ipAddr'] = pkt[IP].dst for option in pkt.getlayer(DHCP).fields['options']: if option == 'end': break dhcp[option[0]] = option[1] print dhcp['router'] print dhcp['subnet_mask'] break except: continue return dhcp def callSniffer(self,interfaceNumber): inter = self.get_interface(interfaceNumber) conf.iface = inter print inter sniff(iface=inter,filter="udp",prn=self.dhcp_print, timeout=10) def callPacket(self,interfaceNumber): inter = self.get_interface(interfaceNumber) print inter fam,hw = get_if_raw_hwaddr(inter) macaddress= get_if_hwaddr(inter) conf.iface = inter ethernet = Ether(dst="ff:ff:ff:ff:ff:ff",src=macaddress,type=0x800) ip = IP(src="0.0.0.0",dst="255.255.255.255") udp = UDP(sport=68,dport=67) bootp = BOOTP(chaddr =hw,xid=0x10000000) dhcp = DHCP(options=[("message-type","discover"),("end")]) packet=ethernet/ip/udp/bootp/dhcp sendp(packet,iface=inter) # get dhcp object dave = PythonDHCPScanner() dhcpObject = dave.get_dhcp_object(3) # Pick interface number 3 on my box time.sleep(1) for dhcpKey in dhcpObject.keys(): print str(dhcpKey) + ":" + str(dhcpObject[dhcpKey]) time.sleep(1) dave.change_ip(dhcpObject,3)