Once a protocol modified or a new layer created changes must be applied to a network stack. There is two solution. The first solution is to modify directly the class PyStack located in pystack.pystack. The second solution is to recreate as small stack by hand according to our needs.
Rebuilding a stack by hand for a connection which is fairly simple. The following piece of code shows how to do it in the most easiest manner.
from pystack.layers.ethernet import EthernetProtocol
from pystack.layers.ip import IPProtocol
from pystack.layers.arp import ARPProtocol
from pystack.layers.tcp import TCPProtocol
from pystack.layers.tcp_session import TCPSession
from pystack.layers.tcp_application import TCPApplication
interface = "eth0"
eth = EthernetProtocol(interface)
ip = IPProtocol()
eth.register_layer(ip)
arp = ARPProtocol(interface)
eth.register_layer(arp)
tcp = TCPProtocol()
ip.register_layer(tcp)
Caution
The DNS layer has not been added, it not useful unless you intent to perfom name resolutions.
Then you can create a create for instance a tcp_application that will listen on port 7777. To do such, we should create a TCPSession a TCPApplication register them each other and then link the TCPSession to the TCP layer.
tcpsession = TCPSession(interface)
tcp.register_layer(tcpsession)
conn = TCPApplication()
tcpsession.register_layer(conn)
conn.bind(7777)
Finally we should start listening on the given interface using a reactor(True) or a thread(False)
eth.start_listening(doreactor=True)
This section will show how to create a small TCP client using pystack. The usage of the PyStack class makes the client creation easy. The following program create a TCP client which connnect to a web server. What is sent is not really important.
import time
from pystack.pystack import PyStack
from pystack.layers.tcp_application import TCPApplication
stack = PyStack() #Create a stack
conn = TCPApplication() #Create a TCPApplication
stack.register_tcp_application(conn) #Register the application to the stack which will manage to create the TCPSession etc.
stack.run(doreactor=False) #Run the stack to start listening using a thread to make it non-blocking
if conn.connect("myserver.com", 80): #Connect to the given server
conn.send_packet("GET / HTTP/1.0\r\n.......\r\n\r\n") #Send the request to the server
time.sleep(10) #Sleep to wait for an answer.
conn.close() #Close the connection
stack.stop() #Stop the stack
Important
In order to make a server the bind method should be discussed because it differ from the socket bind approach.
Call the bind method of the TCPSession with the given attributes.
Parameters: |
|
---|
The following schema summarize all the parameters combinations and the effect it produce when a client connect. We consider in this schema conn = TCPApplication(), and conn is the application that will be bind.
In the end to make a server the code is similar to client. The only thing to modify is to change conn.connect(“myserver.com”, 80) by:
conn.bind(8888) #Without argument the TCPApplication use for new client is conn and the application is not forked
conn.listen(2)
s = conn.accept()
There is no predefined way to modify the stack behavior. It depends of your needs of the protocols involved and of the requirements. Letting the user free of modifying anything in the code is the best solution.
The following example will override the _send_SYNACK method to modify the packet sent in response to a SYN. In this scenario we modify the sequence number to put it at an arbitrary value 5555.
class tcpsession_modified(TCPSession):
def _send_SYNACK(self, packet):
self.seqNo = 5555 #Change the sequence number
self.nextAck = self.seqNo #Does not change the ack value
self.send_packet(None, SYN+ACK) #Call send_packet without modifying flags
Then to make our clients and server to use this TCP session class instead of the classic one, either we recreate the stack by hand Stack crafting (above) or we modify the PyStack class to make it uses tcpsession_modified.