Skip to content

Commit

Permalink
add hybrid internet examples and byoi example
Browse files Browse the repository at this point in the history
  • Loading branch information
wonkr committed Jul 13, 2022
1 parent 49382ba commit e3b4162
Show file tree
Hide file tree
Showing 29 changed files with 752 additions and 0 deletions.
31 changes: 31 additions & 0 deletions examples/C00-hybrid-internet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Hybrid Internet

This is a example that can connect to the realworld. It creates 6 Internet exchanges,
5 transit ASes, and 12 stub ASes same as mini-internet example.
One of the ASes (`AS-99999`) is a hybrid autonomous system,
which announces these prefixes; [`0.0.0.0/1`, `128.0.0.0/1`]
to the emulator. Packets to these prefixes will be routed out to the
real Internet.

The emulator generated from this example is saved to a component file,
and be used by several other examples as the basis.

## Hybrid Autonomous System

The example creates a real-world AS (`AS-99999`), which is
a hybrid autonomous system for the emulator. The prefixes of the AS
are configured as [`0.0.0.0/1`, `128.0.0.0/1`] and announce
them inside the emulator. Packets (from inside the emulator)
going to these networks will be routed to this AS, and
then be forwarded to the real world. Returning packets
will come back from the outside, enter the emulator at
this AS, and be routed to its final destination inside
the emulator.

```
# Create hybrid AS.
# AS99999 is the emulator's autonomous system that routes the traffics to the real-world internet
as99999 = base.createAutonomousSystem(99999)
as99999.createRealWorldRouter('rw-real-world', prefixes=['0.0.0.0/1', '128.0.0.0/1']).joinNetwork('ix100', '10.100.0.99')
```

144 changes: 144 additions & 0 deletions examples/C00-hybrid-internet/hybrid-internet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/usr/bin/env python3
# encoding: utf-8

from seedemu import *


###############################################################################
emu = Emulator()
base = Base()
routing = Routing()
ebgp = Ebgp()
ibgp = Ibgp()
ospf = Ospf()
web = WebService()
ovpn = OpenVpnRemoteAccessProvider()


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

ix100 = base.createInternetExchange(100)
ix101 = base.createInternetExchange(101)
ix102 = base.createInternetExchange(102)
ix103 = base.createInternetExchange(103)
ix104 = base.createInternetExchange(104)
ix105 = base.createInternetExchange(105)

# Customize names (for visualization purpose)
ix100.getPeeringLan().setDisplayName('NYC-100')
ix101.getPeeringLan().setDisplayName('San Jose-101')
ix102.getPeeringLan().setDisplayName('Chicago-102')
ix103.getPeeringLan().setDisplayName('Miami-103')
ix104.getPeeringLan().setDisplayName('Boston-104')
ix105.getPeeringLan().setDisplayName('Huston-105')


###############################################################################
# Create Transit Autonomous Systems

## Tier 1 ASes
Makers.makeTransitAs(base, 2, [100, 101, 102, 105],
[(100, 101), (101, 102), (100, 105)]
)

Makers.makeTransitAs(base, 3, [100, 103, 104, 105],
[(100, 103), (100, 105), (103, 105), (103, 104)]
)

Makers.makeTransitAs(base, 4, [100, 102, 104],
[(100, 104), (102, 104)]
)

## Tier 2 ASes
Makers.makeTransitAs(base, 11, [102, 105], [(102, 105)])
Makers.makeTransitAs(base, 12, [101, 104], [(101, 104)])


###############################################################################
# Create single-homed stub ASes. "None" means create a host only

Makers.makeStubAs(emu, base, 150, 100, [web, None])
Makers.makeStubAs(emu, base, 151, 100, [web, None])

Makers.makeStubAs(emu, base, 152, 101, [None, None])
Makers.makeStubAs(emu, base, 153, 101, [web, None, None])

Makers.makeStubAs(emu, base, 154, 102, [None, web])

Makers.makeStubAs(emu, base, 160, 103, [web, None])
Makers.makeStubAs(emu, base, 161, 103, [web, None])
Makers.makeStubAs(emu, base, 162, 103, [web, None])

Makers.makeStubAs(emu, base, 163, 104, [web, None])
Makers.makeStubAs(emu, base, 164, 104, [None, None])

Makers.makeStubAs(emu, base, 170, 105, [web, None])
Makers.makeStubAs(emu, base, 171, 105, [None])

# Create real-world AS.
# AS11872 is the Syracuse University's autonomous system

as11872 = base.createAutonomousSystem(11872)
as11872.createRealWorldRouter('rw-11872-syr').joinNetwork('ix102', '10.102.0.118')


###############################################################################
# Create hybrid AS.
# AS99999 is the emulator's autonomous system that routes the traffics to the real-world internet
as99999 = base.createAutonomousSystem(99999)
as99999.createRealWorldRouter('rw-real-world', prefixes=['0.0.0.0/1', '128.0.0.0/1']).joinNetwork('ix100', '10.100.0.99')
###############################################################################


###############################################################################
# Peering via RS (route server). The default peering mode for RS is PeerRelationship.Peer,
# which means each AS will only export its customers and their own prefixes.
# We will use this peering relationship to peer all the ASes in an IX.
# None of them will provide transit service for others.

ebgp.addRsPeers(100, [2, 3, 4])
ebgp.addRsPeers(102, [2, 4])
ebgp.addRsPeers(104, [3, 4])
ebgp.addRsPeers(105, [2, 3])

# To buy transit services from another autonomous system,
# we will use private peering

ebgp.addPrivatePeerings(100, [2], [150, 151], PeerRelationship.Provider)
ebgp.addPrivatePeerings(100, [3], [150, 99999], PeerRelationship.Provider)

ebgp.addPrivatePeerings(101, [2], [12], PeerRelationship.Provider)
ebgp.addPrivatePeerings(101, [12], [152, 153], PeerRelationship.Provider)

ebgp.addPrivatePeerings(102, [2, 4], [11, 154], PeerRelationship.Provider)
ebgp.addPrivatePeerings(102, [11], [154, 11872], PeerRelationship.Provider)

ebgp.addPrivatePeerings(103, [3], [160, 161, 162 ], PeerRelationship.Provider)

ebgp.addPrivatePeerings(104, [3, 4], [12], PeerRelationship.Provider)
ebgp.addPrivatePeerings(104, [4], [163], PeerRelationship.Provider)
ebgp.addPrivatePeerings(104, [12], [164], PeerRelationship.Provider)

ebgp.addPrivatePeerings(105, [3], [11, 170], PeerRelationship.Provider)
ebgp.addPrivatePeerings(105, [11], [171], PeerRelationship.Provider)


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

# Add layers to the emulator
emu.addLayer(base)
emu.addLayer(routing)
emu.addLayer(ebgp)
emu.addLayer(ibgp)
emu.addLayer(ospf)
emu.addLayer(web)


# Save it to a component file, so it can be used by other emulators
emu.dump('base-component.bin')

# Uncomment the following if you want to generate the final emulation files
emu.render()
#print(dns.getZone('.').getRecords())
emu.compile(Docker(), './output', override=True)

57 changes: 57 additions & 0 deletions examples/C01-hybrid-dns-component/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Building a DNS Infrastructure Component for Hybrid Internet

This example demonstrates how we can build a DNS infrastructure as a component.
We generate a hybrid DNS infrastructure and save it into a file as
a DNS component. This component can be loaded into other emulators, which
means deploying the DNS infrastructure in those emulators.

In this hybrid DNS, we created the following nameservers:
(TLD Name server is not exist in this hybrid DNS
and the emulator only have second-level zones.)

- Root server: `a-root-server` - shadows a real root server's records
- `twitter.com` nameserver: `ns-twitter-com`
- `google.com` nameserver: `ns-google-com`


## Creating Virtual Nameserver for Root Server

We will create the DNS infrastructure at the DNS layer,
so each node created is a virtual node, which is not bound to
any physical node. The example creates a real-world Root NameServer.
Using .setRealRootNS(), we can announce the root server a real one.

```
# Create a nameserver for the root zone.
# Make it shadow the real root zone.
dns.install('a-root-server').addZone('.').setRealRootNS()
```

If it is set to the real root server, it will collect the records
from the real world root server.

```
path : seedemu/services/DomainNameService.py
def __getRealRootRecords(self):
"""!
@brief Helper tool, get real-world prefix list for the current ans by
RIPE RIS.
@throw AssertionError if API failed.
"""
rules = []
rslt = requests.get(ROOT_ZONE_URL)
assert rslt.status_code == 200, 'RIPEstat API returned non-200'
rules_byte = rslt.iter_lines()
for rule_byte in rules_byte:
line_str:str = rule_byte.decode('utf-8')
if not line_str.startswith('.'):
rules.append(line_str)
return rules
```

33 changes: 33 additions & 0 deletions examples/C01-hybrid-dns-component/hybrid-dns-component.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# encoding: utf-8

from seedemu import *

emu = Emulator()

# DNS
###########################################################
# Create a DNS layer
dns = DomainNameService()

# Create a nameserver for the root zone.
# Make it shadow the real root zone.
dns.install('a-root-server').addZone('.').setRealRootNS()

# Create nameservers for second-level zones
dns.install('ns-twitter-com').addZone('twitter.com.')
dns.install('ns-google-com').addZone('google.com.')

# Add records to zones
dns.getZone('twitter.com.').addRecord('@ A 1.1.1.1')
dns.getZone('google.com.').addRecord('@ A 2.2.2.2')

# Customize the display names (for visualization purpose)
emu.getVirtualNode('a-root-server').setDisplayName('Root-A')
emu.getVirtualNode('b-root-server').setDisplayName('Root-B')
emu.getVirtualNode('ns-twitter-com').setDisplayName('twitter.com')
emu.getVirtualNode('ns-google-com').setDisplayName('google.com')

###########################################################
emu.addLayer(dns)
emu.dump('hybrid-dns-component.bin')
24 changes: 24 additions & 0 deletions examples/C02-hybrid-internet-with-dns/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Deploying DNS Infrastructure in Emulator

This example demonstrates how we can build a DNS infrastructure as a
component, and then deploy this infrastructure onto a pre-built
emulator. This is based on the B02-mini-internet-with-dns.
You can refer to the examples/B02-mini-internet-with-dns/Readme.md for detailed explain.
The change from the mini-internet-with-dns to hybrid-internet-with-dns is
the configuration of ldns.

## Creating Local DNS Server for Hybrid Internet

Creating a local DNS server is similar to creating
other types of services. The local dns in hybrid internet emulator should
add the emulator's zones to its forward zone.
By doing this, the query can be forward to the
name servers inside the emulator.

```
#####################################################################################
# Create a local DNS servers (virtual nodes).
# Add forward zone so that the DNS queries from emulator can be forwarded to the emulator's Nameserver not the real ones.
ldns = DomainNameCachingService()
ldns.install('global-dns-1').addForwardZone('google.com.', 'ns-google-com').addForwardZone('twitter.com.', 'ns-twitter-com')
```
66 changes: 66 additions & 0 deletions examples/C02-hybrid-internet-with-dns/hybrid-internet-with-dns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
# encoding: utf-8

from seedemu.core import Emulator, Binding, Filter, Action
from seedemu.mergers import DEFAULT_MERGERS
from seedemu.hooks import ResolvConfHook
from seedemu.compiler import Docker
from seedemu.services import DomainNameService, DomainNameCachingService, DomainNameCachingServer
from seedemu.layers import Base

emuA = Emulator()
emuB = Emulator()

# Load the pre-built components and merge them
emuA.load('../00-hybrid-internet/base-component.bin')
emuB.load('../01-hybrid-dns-component/hybrid-dns-component.bin')
emu = emuA.merge(emuB, DEFAULT_MERGERS)


#####################################################################################
# Bind the virtual nodes in the DNS infrastructure layer to physical nodes.
# Action.FIRST will look for the first acceptable node that satisfies the filter rule.
# There are several other filters types that are not shown in this example.

emu.addBinding(Binding('a-root-server', filter=Filter(asn=171), action=Action.FIRST))
emu.addBinding(Binding('ns-google-com', filter=Filter(asn=153), action=Action.FIRST))
emu.addBinding(Binding('ns-twitter-com', filter=Filter(asn=161), action=Action.FIRST))
#####################################################################################

#####################################################################################
# Create a local DNS servers (virtual nodes).
# Add forward zone so that the DNS queries from emulator can be forwarded to the emulator's Nameserver not the real ones.
ldns = DomainNameCachingService()
ldns.install('global-dns-1').addForwardZone('google.com.', 'ns-google-com').addForwardZone('twitter.com.', 'ns-twitter-com')

# Customize the display name (for visualization purpose)
emu.getVirtualNode('global-dns-1').setDisplayName('Global DNS-1')

# Create a new host in AS-153, use it to host the local DNS server.
# We can also host it on an existing node.
base: Base = emu.getLayer('Base')
as153 = base.getAutonomousSystem(153)
as153.createHost('local-dns-1').joinNetwork('net0', address = '10.153.0.53')

# Bind the Local DNS virtual nodes to physical nodes
emu.addBinding(Binding('global-dns-1', filter = Filter(asn=153, nodeName="local-dns-1")))

# Add 10.153.0.53 as the local DNS server for all the other nodes
base.setNameServers(['10.153.0.53'])

# Add the ldns layer
emu.addLayer(ldns)

# Dump to a file
emu.dump('hybrid_base_with_dns.bin')


###############################################
# Render the emulation and further customization
emu.render()

###############################################
# Render the emulation

emu.compile(Docker(), './output', override=True)

Loading

0 comments on commit e3b4162

Please sign in to comment.