Skip to content

Commit

Permalink
1. Renamed Listeners as Handlers
Browse files Browse the repository at this point in the history
2. Standardized Handlers as having 4 async queues
3. Renamed get_ip to get_IP in helpers
4. Redefined dictionaries with ip protocols to include all protocols. These are defined with a function reading from a csv provided by IANA
5. Modified async example to fit new model
6. Fixed numerous errors in handler classes
7. Fixed error in TCP protocol related to parse_options
8. Fixed error in TCP's __str__
9. Modified IPv4's __str__ to uppercase protocol names
  • Loading branch information
mbaker-97 committed Aug 18, 2020
1 parent 2ddbb07 commit 3d9b079
Show file tree
Hide file tree
Showing 40 changed files with 646 additions and 246 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Provides easy access to forming and sending custom Ethernet frame, ARP messages,

To Install use pip:
```
pip install sendit==1.0.7
pip install sendit
```
Check out the docs:
[Read the Docs](https://sendit-docs.readthedocs.io/en/latest/)
Expand Down
34 changes: 25 additions & 9 deletions sendit/applications/arp_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,40 @@
__author__ = "Matt Baker"
__credits__ = ["Matt Baker"]
__license__ = "GPL"
__version__ = "1.0.7"
__version__ = "1.0.8"
__maintainer__ = "Matt Baker"
__email__ = "mbakervtech@gmail.com"
__status__ = "Development"
from sendit.helper_functions.helper import *
from sendit.handlers.ethernet_handler import Ethernet_Listener
from sendit.handlers.arp_handler import ARP_Listener
from sendit.helper_functions.helper import BROADCAST_MAC, get_ip, get_MAC
from sendit.handlers.ethernet_handler import Ethernet_Handler
from sendit.handlers.arp_handler import ARP_Handler
from sendit.helper_functions.helper import BROADCAST_MAC, get_IP, get_MAC
from sendit.handlers.raw_nic import Async_Raw_NIC
from sendit.handlers.bytes_handler import Bytes_Handler
from asyncio import Queue

if __name__ == "__main__":
interface = "wlan0"

interface = "wlp1s0"
my_mac = get_MAC(interface)
mappings = {get_ip(interface): my_mac, "192.168.1.154": my_mac}

arp_listener = ARP_Listener(interface=interface, mappings=mappings)
#ARP Listener stuff
mappings = {get_IP(interface): my_mac, "192.168.1.154": my_mac}
arp_ethernet_down_queue = Queue()
arp_handler = ARP_Handler(interface=interface, mappings=mappings, send_queue=arp_ethernet_down_queue)

#Ethernet Listener stuff
protocols = {my_mac + "_arp" : arp_listener.recv_queue, BROADCAST_MAC + "_arp" : arp_listener.recv_queue}

ethernet_bytes_down_queue = Queue()
ehandler = Ethernet_Handler(queue_mappings=protocols, send_queue=ethernet_bytes_down_queue, incoming_higher_queue=arp_ethernet_queue)

#Bytes Listener stuff
bytes_raw_nic_down_queue
bytes_handler = Bytes_Handler(send_queue=


protocols = {my_mac: [arp_listener], BROADCAST_MAC: [arp_listener]}
listener = Ethernet_Listener(interface, protocols)
araw_nic = Async_Raw_NIC(interface, elistener.recv_queue, incoming_higher_queue )
listener.listen()


6 changes: 3 additions & 3 deletions sendit/applications/arpmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
__author__ = "Matt Baker"
__credits__ = ["Matt Baker"]
__license__ = "GPL"
__version__ = "1.0.7"
__version__ = "1.0.8"
__maintainer__ = "Matt Baker"
__email__ = "mbakervtech@gmail.com"
__status__ = "Development"
Expand All @@ -13,7 +13,7 @@
import time
from sendit.protocols.arp import ARP
from sendit.protocols.etherframe import EtherFrame
from sendit.helper_functions.helper import MAC_to_manufacturer,is_valid_ipv4, is_valid_MAC, ip_to_int, get_MAC, get_ip, BROADCAST_MAC
from sendit.helper_functions.helper import MAC_to_manufacturer,is_valid_ipv4, is_valid_MAC, ip_to_int, get_MAC, get_IP, BROADCAST_MAC
from sendit.handlers.raw_nic import Raw_NIC
from socket import inet_ntoa
from threading import Thread
Expand Down Expand Up @@ -164,6 +164,6 @@ def print_banner():
rand_bool = rand.lower() == 'y'

mac = get_MAC(interface)
ip = get_ip(interface)
ip = get_IP(interface)

ARP_map(network, prefix, interface, mac, ip, rand=rand_bool, delay=delay)
87 changes: 66 additions & 21 deletions sendit/applications/async_demo.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,83 @@
import asyncio

from asyncio import Queue
from sendit.handlers.raw_nic import Async_Raw_NIC
from sendit.handlers.bytes_handler import Bytes_Listener
from sendit.handlers.ethernet_handler import EtherFrame_Listener
from sendit.handlers.arp_handler import ARP_Listener
from sendit.handlers.ipv4_handler import IPv4_Listener
from sendit.helper_functions.helper import get_MAC, get_ip
from sendit.handlers.bytes_handler import Bytes_Handler
from sendit.handlers.ethernet_handler import EtherFrame_Handler
from sendit.handlers.arp_handler import ARP_Handler
from sendit.handlers.ipv4_handler import IPv4_Handler
from sendit.handlers.ipv6_handler import IPv6_Handler
from sendit.handlers.udp_handler import UDP_Handler
from sendit.handlers.tcp_handler import TCP_Handler
from sendit.helper_functions.helper import get_MAC, get_IP

async def main():
loop = asyncio.get_event_loop()

###############################Create Queues Here###########################
# Used as nic.send_up and byte.recv_down
nic_to_bytes = asyncio.Queue()
# Used as nic.recv_up and byte.send_down
bytes_to_nic = asyncio.Queue()

IPv4Listen = IPv4_Listener()
ipv4_queue = IPv4Listen.recv_queue
# Used as bytes.send_up and ether.recv_down
bytes_to_ether = asyncio.Queue()
# Used as bytes.recv_up and ether.send_down
ether_to_bytes = asyncio.Queue()

# Used as ether.send_up and ipv4.recv_down
ether_to_ipv4 = asyncio.Queue()
# Used as ether.recv_up and ipv4.send_down
ipv4_to_ether = asyncio.Queue()

# Used as ether.send_up and ipv6.recv_down
ether_to_ipv6 = asyncio.Queue()
# Used as ether.recv_up and ipv6.send_down
ipv6_to_ether = ipv4_to_ether

arp_to_ether = ipv4_to_ether
ether_to_arp = asyncio.Queue()

mappings = {get_ip("wlan0"): get_MAC("wlan0")}
ARPListen = ARP_Listener(mappings=mappings, reply=False)
aqueue = ARPListen.recv_queue
udp_to_ipv4 = asyncio.Queue()
ipv4_to_udp = asyncio.Queue()


tcp_to_ipv4 = udp_to_ipv4
ipv4_to_tcp = asyncio.Queue()


############################################################################

# Create EtherFrame_Listner and grab its queue
queue_mappings = {"arp": [aqueue], "ipv4": [ipv4_queue]}

EListen = EtherFrame_Listener(queue_mappings = queue_mappings )
equeue = EListen.recv_queue
interface = "wlp1s0"
ip = get_IP(interface)
mac = get_MAC(interface)

TCP_handler = TCP_Handler(ports=[22,80,443], send_down = tcp_to_ipv4, recv_down = ipv4_to_tcp)
UDP_handler = UDP_Handler(ports=[53], send_down = udp_to_ipv4, recv_down = ipv4_to_udp)

ipv4_mappings = {ip + "_udp": [ipv4_to_udp], ip + "_tcp": [ipv4_to_tcp]}

IPv4_handler = IPv4_Handler(send_down=ipv4_to_ether, recv_down=ether_to_ipv4, send_up=ipv4_mappings)
IPv6_handler = IPv6_Handler(send_down=ipv6_to_ether, recv_down=ether_to_ipv6)

mappings = {ip: mac}
ARP_handler = ARP_Handler(mappings=mappings, reply=False, recv_up=ether_to_arp, send_down = arp_to_ether)

# Create EtherFrame_Listner and grab its queue mappings
queue_mappings = {"arp": [ether_to_arp], "ipv4": [ether_to_ipv4], "ipv6": [ether_to_ipv6]}

E_Handler = EtherFrame_Handler(send_up=queue_mappings, recv_down=bytes_to_ether, send_down=ether_to_bytes )

# Create Bytes_Listener and grab its queue
bmapping = {"FF:FF:FF:FF:FF:FF": [equeue], get_MAC("wlan0"): [equeue]}
BytesListen = Bytes_Listener(queue_mappings = bmapping)
bqueue = BytesListen.recv_queue
bmapping = {"FF:FF:FF:FF:FF:FF": [bytes_to_ether], mac:[bytes_to_ether]}
B_Handler = Bytes_Handler(send_up = bmapping, send_down = bytes_to_nic, recv_up = ether_to_bytes, recv_down = nic_to_bytes)

# Create Async_Raw_NIC
nic = Async_Raw_NIC("wlan0", bqueue)
await asyncio.gather(IPv4Listen.listen(), ARPListen.listen(), EListen.listen(), BytesListen.listen(), nic.a_recv(1518))
nic = Async_Raw_NIC(interface, send_up=nic_to_bytes, recv_up=bytes_to_nic)

await asyncio.gather(TCP_handler.listen(), UDP_handler.listen(), IPv4_handler.listen(), IPv6_handler.listen(), ARP_handler.listen(), E_Handler.listen(), B_Handler.listen(), nic.a_recv(1518))

if __name__ == "__main__":

asyncio.run(main())


6 changes: 3 additions & 3 deletions sendit/applications/basic_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
__author__ = "Matt Baker"
__credits__ = ["Matt Baker"]
__license__ = "GPL"
__version__ = "1.0.7"
__version__ = "1.0.8"
__maintainer__ = "Matt Baker"
__email__ = "mbakervtech@gmail.com"
__status__ = "Development"
Expand All @@ -21,9 +21,9 @@
# ethernet interfaces often in format of eth0
# wireless interfaces often in format of wlan0
# To find your MAC: sudo ifconfig <interface> | grep -Eo ..\(\:..\){5}
# Or call provided method get_mac(interface)
# Or call provided method get_MAC(interface)
# To find your IP: sudo ifconfig eth0 | grep -w inet | awk '{print $2}'
# Or call provided method get_ip(interface)
# Or call provided method get_IP(interface)
# To find your interface name use sudo ifconfig or sudo ip addr show

# Example 1: Standard Usage
Expand Down
Binary file added sendit/handlers/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
20 changes: 11 additions & 9 deletions sendit/handlers/arp_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
__author__ = "Matt Baker"
__credits__ = ["Matt Baker"]
__license__ = "GPL"
__version__ = "1.0.7"
__version__ = "1.0.8"
__maintainer__ = "Matt Baker"
__email__ = "mbakervtech@gmail.com"
__status__ = "Development"
from sendit.handlers.listener import Listener
from sendit.handlers.handler import Handler
from sendit.protocols.arp import ARP
from sendit.protocols.etherframe import EtherFrame
from sendit.helper_functions.helper import is_valid_MAC
from ipaddress import ip_address, AddressValueError

class ARP_Listener(Listener):
class ARP_Handler(Handler):

"""
Creates class that listens and responds to ARP messages. Child class of Listener
Creates class that listens and responds to ARP messages. Child class of Handler
:param reply: boolean of whether to answer ARP requests, defaults to True
:type reply: Boolean
Expand All @@ -30,9 +30,9 @@ class ARP_Listener(Listener):
or when values in mappings are not valid MAC addresses
"""

def __init__(self, reply=True, mappings=None, send_queue=None):
"""Constructor for ARP_Listener """
super().__init__(send_queue=send_queue)
def __init__(self, reply=True, mappings=None, send_down=None, recv_up=None):
"""Constructor for ARP_Handler"""
super().__init__(send_down=send_down, recv_up=recv_up)
if reply and mappings is None:
raise ValueError("When reply is set to True, mappings must be provided")
if reply and send_queue is None:
Expand All @@ -59,14 +59,16 @@ async def listen(self):
an ethernet_handler
"""
recv_queue = self.recv_up
send_queue = self.send_down
while True:
frame = await self.recv_queue.get()
frame = await recv_queue.get()
arp = ARP.arp_parser(frame.payload)
print(arp)
if self.reply:
mac = self.mappings.get(arp.tpa)
if mac is not None and arp.op == 1:
reply = ARP(mac, arp.tpa, arp.sha, arp.spa, op=2)
reply_frame = EtherFrame(frame.src, mac, reply, ethertype = "arp")
frame.payload = reply
await self.send_queue.put(reply_frame)

63 changes: 39 additions & 24 deletions sendit/handlers/bytes_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,34 @@
__author__ = "Matt Baker"
__credits__ = ["Matt Baker"]
__license__ = "GPL"
__version__ = "1.0.7"
__version__ = "1.0.8"
__maintainer__ = "Matt Baker"
__email__ = "mbakervtech@gmail.com"
__status__ = "Development"
from sendit.protocols.etherframe import EtherFrame
from sendit.handlers.listener import Listener
from sendit.handlers.handler import Handler
import asyncio

class Bytes_Listener(Listener):
class Bytes_Handler(Handler):
"""
Asynchronously listens for bytes in own queue placed there by Async_Raw_NIC
Creates EtherFrames from raw bytes, places those in async queues based on
MAC mappings in queue_mappings
:param send_queue: asyncio.Queue that will be used to put frames in to send
:type send_queue: asyncio.Queue
:param queue_mappings: Dictionary mapping async queues to MAC addresses, defaults to None
:type queue_mappings: Dictionary where keys are strings of MACs, values are lists of asyncio.queue
:param send_up: Dictionary where keys are strings of MACs, values are \
lists of asyncio.queues where items are put to go to higher layers
:type send_up: Dictionary
:param send_down : asyncio.Queue to put items in to go to lower layers
:type send_down: asyncio.Queue
:param recv_up: asyncio.Queue to receive items from higher layers
:type recv_up: asyncio.Queue
:param recv_down: asyncio.Queue to receive items from lower layers
:type recv_down: asyncio.Queue
"""

def __init__(self, send_queue=None, queue_mappings=None):
"""Constructor for Bytes_Listener"""
# this creates queue to listen on
super().__init__(send_queue=send_queue)
# Keys contain MACs to send on, values contain list of async queues to place those bytes in
self.queue_mappings = queue_mappings
def __init__(self, send_up=None, send_down=None, recv_up=None, recv_down=None):
"""Constructor for Bytes_Handler"""
super().__init__(send_up=send_up, send_down=send_down, recv_up=recv_up, recv_down=recv_down)

async def listen(self):
"""
Expand All @@ -39,16 +41,16 @@ async def listen(self):
corresponding value in dict
"""
# Grab this into local scope to reduce dictionary lookups
mappings = self.queue_mappings
recv_queue = self.recv_down
send_queues = self.send_up
while True:
# Wait for bytes to show up in queue
byte = await self.recv_queue.get()
print("Got bytes in byte receiver")
# Wait for bytes to show up in recv_down queue
byte = await recv_queue.get()
frame = EtherFrame.etherframe_parser(byte, recursive=False)

# Check if queue_mappings was provided
if mappings is not None:
queues = mappings.get(frame.dst)
# Check if send_queues was provided
if send_queues is not None:
queues = send_queues.get(frame.dst)
# Check if destination address is a MAC to be listening for
if queues is not None:

Expand All @@ -70,7 +72,7 @@ def remove_MAC(self, mac):
mac = mac.upper()
# Try to remove that mac from the dictionary
try:
self.queue_mappings.pop(mac)
self.send_up.pop(mac)
# If that key does not exist, raise Value Error
except KeyError:
raise ValueError("That MAC address was not in the current list")
Expand All @@ -95,7 +97,7 @@ def remove_queue(self, mac, queue):
# Check if mac is valid
mac = mac.upper()
if helper.is_valid_mac(mac):
queues = self.queue_mappings.get(mac)
queues = self.send_up.get(mac)

# Check if there is entry for that mac in self.queues_mapping
if queues is None:
Expand All @@ -108,7 +110,7 @@ def remove_queue(self, mac, queue):
# If we removed the last queue for that mac address, remove
# MAC in self.queues_mapping
if len(queues) == 0:
self.queue_mappings.pop(mac)
self.send_up.pop(mac)

# If this queue was not in list, raise ValueError
except ValueError:
Expand All @@ -131,7 +133,7 @@ def add_queue(self, mac, queue):
# Check if mac is valid
mac = mac.upper()
if helper.is_valid_mac(mac):
queues = self.queue_mappings.get(mac)
queues = self.send_up.get(mac)

# Check if there is entry for that mac in self.queues_mapping
if queues is None:
Expand All @@ -142,3 +144,16 @@ def add_queue(self, mac, queue):
queues.append(queue)
else:
raise ValueError("Provided MAC address is not valid")

async def recv_incoming_higher(self):
recv_queue = self.recv_up
send_queue = self.send_down
#TODO - raise error if recv_up, send_down None
while True:
frame = await self.recv_up.get()
try:
payload_bytes = frame.as_bytes()
except AttributeError:
payload_bytes = str.encode(frame)

await self.send_queue.put(payload_bytes)

0 comments on commit 3d9b079

Please sign in to comment.