layers Package

layers Package

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

arp Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.arp.ARPProtocol(iface)[source]

Bases: pystack.layers.layer.Layer

Provides the basic functionalities provided by the ARP Protocol. It implements Layer. It keeps an ARP cache which is updated when an ARP reply is received. It also provides methods to do ARP request.

get_mac(ip)[source]

Return the MAC address associated with the given IP if present. Otherwise it returns None.

name = 'ARP'
packet_received(packet, **kwargs)[source]

Deal with an ARP packet received. If this is a reply (is_at) update the cache and call route_update that will flush potential packet waiting for MAC resolution. If the packet is a request (who_has) and for our MAC reply.

send_arp_request(ip)[source]

Send an ARP request on the broadcast for the requested IP

update_cache(ip, addr)[source]

Update the cache with the given IP and MAC.

dns Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.dns.DNSProtocol(iface=None)[source]

Bases: pystack.layers.udp_application.UDPApplication

Provide basic DNS implementation. It can send DNS request to resolve an hostname, and process replies sent by the server. The server used is a server of OpenDNS

forge_packet(packet=None, **fields)[source]

Just forge the DNS packet with arguments sent in **field

name = 'DNS'
nslookup(name)[source]

Make a DNS request to resolve a domain name

packet_received(packet, **kwargs)[source]

Process DNS packets. But process only incoming answers for which we made a request

send_dns_request(name)[source]

Craft and send a DNS request for the given name

ethernet Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.ethernet.EthernetProtocol(interface=None)[source]

Bases: pystack.layers.layer.Layer

This class provides all the functionalities to accomplish the layer 2 routing. When a packet is received from an upper layer this class basically look up in the host routing table to get the ip to send the packet to and if the mac address is not found trigger an ARP request. It also maintain a pool of packet for which the destination MAC address is unknown until an ARP reply is received.

forge_packet(packet, **kwargs)[source]

Forge the Ethernet packet using the given kwargs and the given packet

name = 'Ether'
packet_received(packet, **kwargs)[source]

Decapsulate the packet as the Layer would have done except that if the packet is an IP packet this method update the ARP cache with ip and mac

route_update(ip)[source]

Method called by arp layer when receive an arp reply (is_at) Loop through all packets if the newly resolved MAC match dst of on of them complete the packet and send it.

send_packet(packet, **kwargs)[source]

When a packet is received from an upper layer try to route it. If the method return something call forge and transfert it (to scapyio)

start_listening(doreactor=True)[source]

Because Ethernet have directly the ScapyIO as a class attribute it should interface ScapyIO methods. This method should be called to start listening on the socket using the appropriate method (twisted reactor or threads)

stop()[source]

Call the stop method of ScapyIO

transfer_packet(packet)[source]

Rewrite transfer to use scapy_io because ethernet is the lowest layer. So in this case call the send method of Scapy

ip Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.ip.IPProtocol(method='last')[source]

Bases: pystack.layers.layer.Layer

IPProtocol assure the routing at the layer 3 IP.

forge_packet(packet, **kwargs)[source]

Just forge the packet id the associated arguments

name = 'IP'
packet_received(packet, **kwargs)[source]

Call the right handler but also add the source and destination IP as kwargs otherwise after decapsulation it will be lost and upper layers need to get it

send_packet(packet, **kwargs)[source]

If the destination is an IP just transfert it. If this is an DN try to get the IP otherwise put the packet in the pool and trigger a DNS request for the given DN

layer Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.layer.Default[source]

Default implements Layer. It just override packet_received to do nothing. Class called when there is not handler for the packet

packet_received(packet, **kwargs)[source]

Does nothing. Is called for every packet that does not have any handler

class pystack.layers.layer.Layer[source]

Bases: object

Mother class for all the layers(protocols) of the stack. It provides many methods to register an upper or lower layer. Moreover it provides methods that should be overriden by children layers according to theirs behavior. By the way Layer is an “abstract” class it should not be instanciated

forge_packet(packet, **kwargs)[source]

By default does nothing but should be overriden by child class

name = ''
packet_received(packet, **kwargs)[source]

Define the default behavior when a packet is received. By default decapsulate the packet and send the payload to the upperlayer referenced by the payload name (TCP, IP ..)

register_layer(layer)[source]

Shortcut for register_layer_full using the layer.name as key

register_layer_full(name, layer)[source]

Shortcut method to register the given layer as upperlayer and register self as the default lowerlayer for layer. This can not be used in all cases

register_lower_layer(name, layer)[source]

Register the given layer in the lowerlayers dict using the given name as key

register_upper_layer(name, layer)[source]

Add the given layer into the upperlayers dict using the given name as key

send_packet(packet, **kwargs)[source]

By default when calling send_packet it forge the packet calling forge_packet and forward it to the lower layer calling transfer_packet

transfer_packet(packet, **kwargs)[source]

Define the default behavior when a packet should be transfered to the lower layer. The default behavior is to call the send_packet of the default lowerlayer. This method can be overriden by child layers

unregister_upper_layer(name)[source]

Remove the the layer referenced by the name in upperlayer. The exception is catched to prevent to make the program crash

scapy_io Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.scapy_io.ScapyIO(interface=None)[source]

Bases: twisted.internet.base.BasePort

SacpyIO play the role of interface with Input/Output functions of Scapy. So all the packets that are received and sent pass through here. To receive packet ScapyIO use a L2ListenSocket object. Then to read packets two methods are implemented, either twisted reactor add a reader on the socket or a thread that will loop reading packet in the socket. To send packet the sendp method is called

doRead()[source]

Method called when the reader read a packet in the socket. So basically forward it to the handler(s)

fileno()[source]

Needed for the reader

register_handler(handler)[source]

Register an handler for the packet received. We can put multiples ones but in the classical case there will be one which is the Ethernet layer.

send(packet)[source]

Send the given packet without any kind of test

start_listening(doreactor=True)[source]

Start listening on the socket using the appropriate method. If reactor is choosen it adds a reader on the socket and create a callback that will be able to check with the user want to stop. Note that signalHandlers are disabled for the reactor. If not reactor is choosen then a thread is used and will be started enclosed in the _do_read_thread method.

stop_listening()[source]

Just put the boolean to True. Then the reader or the thread will have to notice it. Note that it can take a while because with threads, the thread is blocked in the recv method until a packet is received

tcp Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.tcp.TCPProtocol[source]

Bases: pystack.layers.layer.Layer

TCPProtocol assure routing functions of the TCP protocol. It basically route packets to the right tcp session.

forge_packet(packet, **kwargs)[source]

Forge the TCP packet with the given argument and the payload if present

is_port_free(p)[source]

Loop through all the connections to check that the given port is free. Note this method does not take in account real connection made by the kernel

name = 'TCP'
packet_received(packet, **kwargs)[source]

When a packet is received if upper layer contains an entry like (srcip,srcport,dstip,dstport) the packet is sent to it otherwise else check (dstip,dstport) if a server is registered.

send_packet(packet, **kwargs)[source]

Call forge and ten call transfert packet.

tcp_application Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.tcp_application.TCPApplication[source]

Bases: pystack.layers.layer.Layer

TCPApplication provides the functionnalities for layer 7 protocols. So there is just connection management and buffer reading/writing. Moreover for connection management it basically just call the ones from tcpsession which really do the stuff.

accept()[source]

Call the TCPSession accept method

bind(port, app=None, newinstance=False)[source]

Call the bind method of TCPSession with attributes. Be careful it is really important to understand what are attributes:

  • app: Should be a TCPApplication. So that all the clients that will

connect the server will be attached to this tcpapplication If no app is provided the tcpapplication used is self ! - newinstance: Define if all the clients should be linked on the same tcpapplication (attribute app) or if should be forked for each.

close()[source]

Call the close of the tcpsession

connect(ip, port)[source]

Just call the connect method of TCPSession layer

connection_made()[source]

By default does nothing, but could be important in some layer 7 implementation like SSH ..

fetch_data(size=None)[source]

Fetch_data acquire the mutex in order to pop data of the wanted size. If no size is specified return all the datas

fetch_data_from(size=None)[source]

Shortcut for the pysocket module

forge_packet(data)[source]

Forge the Raw packet using the datas given in parameter

get_conn_addr()[source]

Return remote IP and remote Port

get_self_addr()[source]

Return our IP and the port associated

hook_incoming(packet, **kwargs)[source]

Method called by tcpsession when a packet is received. Can be overriden to apply operation on incoming packets

hook_outgoing(packet, **kwargs)[source]

Method called by tcpsession just before a tcp packet is crafted and sent

listen(nb=0)[source]

Just call the listen method of TCPSession layer

name = 'Raw'
packet_received(packet, **kwargs)[source]

At this level a packet is Raw data so bytes. This method acquire the mutex add received datas and release the mutex.

transfer_packet(packet, **kwargs)[source]

Override the transfertPacket method of Layer. Because for a server that use the same tcpapplication for every client the tcpsession to target is not the default me the right client. So check if a client was sent in kwargs if it is the case send the packet to the tcpsession of the client default otherwise

tcp_session Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

pystack.layers.tcp_session.FIN = 1

FINACK = 17 SYNACK = 18 PSHACK = 24 RSTACK = 20

class pystack.layers.tcp_session.State(session)[source]

State class is the mother class that describe a state at a given moment. A state is just characterised by a name and should implement a method called packet_received that will provide the adapted state behavior for every packets

packet_received(packet, **kwargs)[source]

By default packet_received does nothing but printing the packet

class pystack.layers.tcp_session.State_CLOSED(session)[source]

Bases: pystack.layers.tcp_session.State

Any packets received on a Closed connection is being replied with a reset packet

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_CLOSE_WAIT(session)[source]

Bases: pystack.layers.tcp_session.State

This state is not implemented in the stack. The stack always send both FIN and ACK in the same packet

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_ESTABLISHED(session)[source]

Bases: pystack.layers.tcp_session.State

When the session is in the established state it should handle a lot’s of different cases and react in consequences

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_FIN_WAIT_1(session)[source]

Bases: pystack.layers.tcp_session.State

When in FIN_WAIT expect a FIN and ACK packet. If it received a FIN_ACK packet it sends a ACK switch to closed and unregister itself from both the upper and the lower layer

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_FIN_WAIT_2(session)[source]

Bases: pystack.layers.tcp_session.State

In FIN_WAIT2 if the host send a FIN to session can be ended up sucessfully.

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_LAST_ACK(session)[source]

Bases: pystack.layers.tcp_session.State

When in Last_ACK just wait for the final ack to close the connection

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_LISTEN(session)[source]

Bases: pystack.layers.tcp_session.State

A tcp session in Listen state only process SYN packet. When a SYN packet is received it checks that the number of connection to accept is not exceeded. If this is ok it creates another TCP session specific for this connection. Then it attachs it a TCPApplication either by forking it or not depending of the config. Then it switched the newly created connection to SYN_SENT state.

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_SYN_RCVD(session)[source]

Bases: pystack.layers.tcp_session.State

When in SYN_RCVD only process ACK packets. Then switch the state to ESTABLISHED and call ConnectionMade

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_SYN_SENT(session)[source]

Bases: pystack.layers.tcp_session.State

When in SYN_SENT only process SYN_ACK packets by replying a ACK packet. It also switch the state to ESTABLISHED and call the session _call_connection_made method

packet_received(packet, **kwargs)[source]
class pystack.layers.tcp_session.State_TIME_WAIT(session)[source]

Bases: pystack.layers.tcp_session.State

Not implemented state directly deleted (normally put to closed for few sec)

class pystack.layers.tcp_session.TCPSession(interface)[source]

Bases: pystack.layers.layer.Layer

TCPSession contains the core methods to deal with a lot of cases that can be met with TCP. This class mainly implement methods to connect, bind and close a TCP session with a remote host. At every moment a TCP session have a standardised state from CLOSED, ESTABLISHED, .. This class also keeps at every moment all the variables needed in order to process TCP packets like sequence number, acknowledgement number, port ..

accept()[source]

From a server point of view every client connections are hold in the connections attribute. When accept is called the method start by flushing all CLOSED connections from the connections list. Then it waiting for a connection to be appended to the list to return it. (when the currentconnection value is changed)

bind(port, app=None, newinstance=False)[source]

The bind method is quite ligthweight. It justs register itself to the TCP protocol as a handler and an entry is added to iptables to prevent the Hosting host to reply with RST. Note app and newinstance define on which TCPApplication client connections should be redirected and if the TCPApplication should be forked for every client or not.

close()[source]

For a client will send a FIN packet and switch to FIN_WAIT1. For a server will send a FIN packet for every clients in order to unregister itself from the TCP layer

connect(ip, port)[source]

This method try to connect to the given ip and port. If the TCP session is not CLOSED the operations are aborted. Else a local port is generated, an entry is added in iptables to preven the kernel to disturbe our connection and then a SYN packet is sent. Then the connection state is switched to SYN_SENT. The method will then loop for 20 seconds checking if the state has changed to ESTABLISHED. If not it means that a problem occured and everything is rolled back.

listen(nb=0)[source]

This method basically just switch the current state from CLOSED to LISTEN so that SYN request will be handled.

packet_received(packet, **kwargs)[source]

The more important thing with this method is that for each packet this method can be called twice. The first time by the lower layer and the packet is TCP. Then the packet is processed and packet_received is possibly called once again with the packet decapsulated (in Raw). When a TCP packet is received seq and ack value are updated when the packet_received method of the current state of the connection is called to know what to do with the current packet.

sendRST(packet, **kwargs)[source]

Just send a reset packet to the remote host

send_data(packet, push=True, **kwargs)[source]

Just call send_packet with datas. The nextAck indicator is also updated to the excpected value.

send_packet(packet, flags=16, **kwargs)[source]

This method is one of the most critical. Every TCP packet are sent through this method. This method basically deal with all the flags and is in charge to incremente sequence number. In addition it sets all the TCP fields in order to generate the packet. It increment the ack value of the data size of the previously received packet.

switch_state(state)[source]

Switch to the given state. State should implement State

transfer_packet(packet, **kwargs)[source]

Override the layer transfer_packet just to add the hook.

unregister_upper_layer(name)[source]

Used to remove himself from the lower layer

udp Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.udp.UDPProtocol[source]

Bases: pystack.layers.layer.Layer

UDP Protocol provides basic functions of UDP. It allow to send and receive UDP packet

forge_packet(packet, **kwargs)[source]

Forge the packet with or without payload

is_port_free(p)[source]

Return either or not a port the given port is free

name = 'UDP'
packet_received(packet, **kwargs)[source]

When an UDP packet is received it is directly forwarded to the associated application if it exists.

send_packet(packet, **kwargs)[source]

Like in TCP send_packet call forge but without src and dst which are IP123 fields.

udp_application Module

Author: Robin David License: GNU GPLv3 Repo: https://github.com/RobinDavid

Copyright (c) 2012 Robin David

PyStack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version http://www.gnu.org/licenses/.

class pystack.layers.udp_application.UDPApplication(iface=None)[source]

Bases: pystack.layers.layer.Layer

UDP Application provides input output functionalities above the UDP layer. An UDP application is directly linked to the UDP layer (not like in TCP) because UDP is stateless

bind(port, app=None, fork=None)[source]

Bind like connect will register a handler in the UDP layer. But it will also prevent the host to send ICMP host port unreachable

close()[source]

Close just unregister himself from the lower layer and remove rules from iptables

connect(ip, port)[source]

In UDP connect is not really meaningfull. In this case it just means register an handler for the connection in the UDP layer

fetch_data(size=None)[source]

fetch_data return the given number of bytes

fetch_data_from(size=None)[source]

fetch_data_from use the socket syntax and arguments. It returns the datas associated to the given host. Because data in UDP is not a string this a list of string identified by the remote IP.

get_conn_addr()[source]

Return tuple of the remote IP remote port

get_self_addr()[source]

Return the tuple of the local ip local port

name = 'Raw'
packet_received(packet, **kwargs)[source]

Add the received datas to the buffer data. The mutex prevent any improper read/write

send_packet(packet, **kwargs)[source]

Sending a packet to an host does not require any connection or any call to connect. So if a packet is the first for a destination host. Associated rules are added in iptables. Then every fields are setup in order to call the transfer it to the lowest layer

Table Of Contents

This Page