Skip to content

L4 networking framework for testing arbitrary topologies

License

Notifications You must be signed in to change notification settings

MyNameIsCalvinDavis/Routing

Repository files navigation

Routing

The purpose of this project is to provide a network simulation framework up to Layer 4. Several classes are provided, mimicking their hardware equivalents.

  • Switch
  • Host
  • Router

At this point, supported protocols include:

  • ARP
  • DHCP
  • ICMP

In our simulation, we are able to connect a topology together in an intuitive way. Here we form a basic 4 device LAN:

.

We can initialize it as such:

A = Host(["1.1.1.2/24"])
B = Host(["1.1.1.3/24"])
C = Host(["1.1.1.4/24"])
S1 = Switch([A, B, C])
A.sendARP(B.getIP())

Optionally, Devices don't need an initial IP:

A = Host()
D1 = DHCPServer("1.1.1.2/24", gateway="1.1.1.1/24", debug=1)
S1 = Switch([A, D1], debug=0)

A.sendDHCP("init", timeout=5)
pprint("As IP: ", A.getIP())

We can construct an arbitrary toplogy without much fuss:

A = Host(["1.1.1.2/24"])
B = Host(["2.2.2.2/24"])
C = Host(["3.3.3.2/24"])
D = Host(["4.4.4.2/24"])

A.interfaces[0].gateway = "1.1.1.1/24"
B.interfaces[0].gateway = "2.2.2.1/24" # Bs default gateway is R1!

S1 = Switch([B], debug=0)
R1 = Router(["1.1.1.1/24", "2.2.2.1/24"], [A, S1])

S3 = Switch([D], debug=0)
S2 = Switch([S3], debug=0)
R2 = Router(["2.2.2.10/24", "3.3.3.1/24", "4.4.4.1/24"], [S1, C, S2])

Devices communicate to each other with a frame, although this project uses a dict representation instead of packed byte data. Each layer must be built separately, though we wrap this functionality with functions like sendARP() or sendDHCP() for example, as seen above. Under the hood, a frame might look like:

>>> p = makePacket_L2(ethertype="ARP", fr=A.id, to=MAC_BROADCAST, data={"ID":B.id})
>>> p
{
  "EtherType":"ARP",
  "From":<A MAC>,
  "To":<MAC BROADCAST ADDR>,
  "FromLink":<LINK ID> # Used identify which interface a frame comes from, in lieu of an actual hardware port
  "Data": {"ID": <B MAC>}
}

Where the Data field would then store L3 information, whose Data field would contain L4 information...

When we send() data, we don't send TO a host, rather we output on an interface. Every Device has a list of Interfaces. We then rely on the frame and other hardware to get it where it needs to go.

Here, we send p on A's only interface.

>>> A.send(p) # onlink param default value is self.interfaces[0]. Fine for a host with only one interface

We can also specify a specific interface, good for devices with several interfaces, like a Router or Switch:

>>> A.send(p, A.interfaces[0])

About

L4 networking framework for testing arbitrary topologies

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages