- Make the below programs easier to run
- pass in "owner" and "modifier" accounts in command line
- I should be able to toggle between any of the three accounts across all python scripts instead of having to go in and change the account we're reading from in the env file. it's confusing lol
- Implement The following
- Remove ASN
- Remove Prefix
- Validate Prefix
- Add Advertisement
- Valdiate Advertisement
- Partial Deployment Support - P -> NP -> P
- BGP Code integration
- Add Origin Validation into BGP code
- Add Path Validation to BGP code
- Ensure Origin/Path validation working together
- compile contract
- deploy contract
- add/remove ASN
- add/remove prefix
- validate prefix
- get ASN owner
- get prefix owner
- get prefixes owned by ASN
- add advertisement
- validate advertisement
Implementation done with cryptographic signings
python -m pip install -r requirements.txt
The following accounts/addresses must be stored in .env
- ACCOUNT0_ADDRESS, ACCOUNT0_PRIVATE_KEY
- The IANA account. Owner of the smart contract
- ACCOUNT1_ADDRESS, ACCOUNT1_PRIVATE_KEY
- An AS Account (1)
- ACCOUNT2_ADDRESS, ACCOUNT2_PRIVATE_KEY
- Another AS Account (2)
For path validation, each AS must have the contract address of all other AS's Path Validation Contracts
- Need asn_address_mapping.yaml
python compile.py <contract-name>
# e.g.
python compile.py IANA
# or
python compile.py PATH_VALIDATION
python deploy.py <accountN> <contract-name>
# e.g.
python deploy.py ACCOUNT0 PATH_VALIDATION
Next: For IANA contract deploy,
- Copy address printed out from deploy.py into .env file
For PATH_VALIDATION contract deploy,
- Copy address printed out into the asn_address_mapping.yaml file under the apprpriate ASN
If use ACCOUNT0
- Note: these two commands will deploy from ACCOUNT0_ADDRESS in .env
- ACCOUNT0_ADDRESS becomes the owner of the contract.
- ACCOUNT0_ADDRESS is the owner/IANA
- this gives an ASN the ability to get assigned IP prefixes
- But an AS first needs to get added to the AS map by IANA
python add_asn.py <account0> <account1> <ASN1> <account1_address>
e.g.
python add_asn.py ACCOUNT0 ACCOUNT1 100 0x79bb7739B28ab9D6a846012156f5eadD0dE67361
- Note ensure account1_address passed in is equivalent to account1 in the .env file. (You can change this but they way it's set up now, you have make sure they are equivalent)
- Now update add_prefix.py. And read in account2 data instead of account 1. This will allow us to add an ASN for account2
python add_asn.py <account0> <account2> <ASN2> <account2_address>
e.g.
python add_asn.py ACCOUNT0 ACCOUNT2 200 0xcF0A72EFd623c7aC7f9886213daFd93a2D62832
-Note: IANA initially owns all IP space. And only IANA can allocate that space to someone else. unless that space is owned by someone else
python add_prefix.py <account0> <account1> <ASN1> <ip1> <subnet1> <account1_address>
Example:
python add_prefix.py ACCOUNT0 ACCOUNT1 100 100.0.100.0 24 0x79bb7739B28ab9D6a846012156f5eadD0dE67361
- Note same issue as above, acct1 in .env == <account1_address>
- Now update add_prefix.py. And read in account2 data instead of account 1. This will allow us to add a prefix for account2
python add_prefix.py <ASN2> <ip2> <subnet> <account2_address>
Example:
python add_prefix.py ACCOUNT0 ACCOUNT2 200 200.0.200.0 24 0xcF0A72EFd623c7aC7f9886213daFd93a2D628327
- Note same issue as above, acct2 in .env == <account2_address>
- These should all fail
python add_prefix.py <account0> <account2> <ASN2> <ip2> <subnet> <account1_address>
python add_prefix.py <account0> <account2> <ASN1> <ip2> <subnet> <account1_address>
- These should succeed
python add_prefix.py <account0> <account2> <ASN2> <ip3> <subnet3> <account2_address>
python add_prefix.py <account0> <account2> <ASN2> <ip3> <subnet5> <account2_address>
- Now, let's give ASN2 ASN1's IP/mask
- this may occur if ASN2 is a customer of ASN1 and ASN1 needs to give IP space to ASN2
- we're going to use
add_prefix.py
here - this will transfer ASN1's IP/mask to ASN2.
python add_prefix.py <account1> <account2> <ASN2> <ip1> <subnet1> <account2_address>
Example:
python add_prefix.py ACCOUNT1 ACCOUNT2 200 100.0.100.0 24 0xcF0A72EFd623c7aC7f9886213daFd93a2D628327
- Flow: ASN2 says they want to now own ip1/subnet1, so they hash and sign the data and "send" it to acct1.
- Not really sent here. It's just passed to acct1 in the python file
- ASN1 takes the signed message from ASN2, generates the sigV, sigR, sigS, and then calls
prefix_addPrefix()
in the smart contract. - the smart contract will
- validate that ASN2 signed the message saying it want ASN1's IP/subnet.
- ensure ASN1 is the one calling
prefix_addPrefix()
.- This is important because we don't want someone else to be able to call
prefix_addPrefix()
and transfer ASN1's IP/subnet away to someone else.
- This is important because we don't want someone else to be able to call
python validate_prefix.py <account1> <ip2> <subnet2> <ASN2>
Example:
python validate_prefix.py ACCOUNT1 100.0.100.0 24 200
- BGPSEC implementation without all the heavyweight signing
- Each AS has its own advertisement contract!
- Owner of contract can write to it but anybody can read from it
- Contract contains:
- Prefix and the ASN of the next Hop
GANACHE_RPC_URL=http://127.0.0.1:7545
CHAIN_ID = 1337
ACCOUNT0_ADDRESS=<pubkey>
ACCOUNT0_PRIVATE_KEY=<private-key>
ACCOUNT1_ADDRESS=<pubkey>
ACCOUNT1_PRIVATE_KEY=<private-key>
ACCOUNT2_ADDRESS=<pubkey>
ACCOUNT2_PRIVATE_KEY=<private-key>
ACCOUNT3_ADDRESS=<pubkey>
ACCOUNT3_PRIVATE_KEY=<private-key>
ACCOUNT4_ADDRESS=<pubkey>
ACCOUNT4_PRIVATE_KEY=<private-key>
ACCOUNT5_ADDRESS=<pubkey>
ACCOUNT5_PRIVATE_KEY=<private-key>
ACCOUNT6_ADDRESS=<pubkey>
ACCOUNT6_PRIVATE_KEY=<private-key>
IANA_CONTRACT_ADDRESS=<IANA-contract-address>
ACCOUNT1_PATH_VALIDATION_CONTRACT=<account1-path-validation-contract-address>
ACCOUNT2_PATH_VALIDATION_CONTRACT=<account2-path-validation-contract-address>
ACCOUNT3_PATH_VALIDATION_CONTRACT=<account3-path-validation-contract-address>
ACCOUNT4_PATH_VALIDATION_CONTRACT=<account4-path-validation-contract-address>
ACCOUNT5_PATH_VALIDATION_CONTRACT=<account5-path-validation-contract-address>
ACCOUNT6_PATH_VALIDATION_CONTRACT=<account6-path-validation-contract-address>
---
asn_0:
validation_contract: <account0-path-validation-contract-address>
asn_100:
validation_contract: <account1-path-validation-contract-address>
asn_200:
validation_contract: <account2-path-validation-contract-address>
asn_300:
validation_contract: <account3-path-validation-contract-address>
asn_400:
validation_contract: <account4-path-validation-contract-address>
asn_500:
validation_contract: <account5-path-validation-contract-address>
asn_600:
validation_contract: <account6-path-validation-contract-address>
ASNs in order sending an update message for 10.0.20.0/24
- Path: 100 -> 200 -> 300 -> 400 -> 500 -> 600
A1: 10.0.20.0/24 : 100
- writes to 100's own advertisement contract {10.0.20.0/24, nextHop = 200}
- sends A1 to 200
A2: 10.0.20.0/24 : 200, 100
- checks there is a 10.0.20.0/24 with next hop 200 in 100's advertisement contract
- writes to 200's own advertisement contract {10.0.20.0/2, nextHop = 300}
- sends A2 to 300
A3: 10.0.20.0/24 : 300, 200, 100
- checks there is a 10.0.20.0/24 with next hop 300 in 200's advertisement contract
- checks there is a 10.0.20.0/24 with next hop 200 in 100's advertisement contract
- writes to 300's own advertisement contract {10.0.20.0/2, nextHop = 400}
- sends A3 to 400...
Path of advertisements for example:
- Path: 100 -> 200 -> 300 -> 400 -> 500 -> 600
Format:
python add_advertisement.py <account> <ip> <subnet> <nextHopASN>
Example:
python add_advertisement.py ACCOUNT1 10.0.20.0 24 200
python add_advertisement.py ACCOUNT2 10.0.20.0 24 300
python add_advertisement.py ACCOUNT3 10.0.20.0 24 400
python add_advertisement.py ACCOUNT4 10.0.20.0 24 500
python add_advertisement.py ACCOUNT5 10.0.20.0 24 600
python validate_advertisement.py <account2> <ip> <subnet> <myASN> <Received advertisement's AS_PATH>
Example - Account 2 (ASN200) needs to validate that ASN100 has said for this ip/prefix it is sending it to ASN200
python validate_advertisement.py ACCOUNT2 10.0.20.0 24 200 100
Example - Account 3 (ASN300) needs to check down path that path 2->3 exists and 1->2 exists
python validate_advertisement.py ACCOUNT3 10.0.20.0 24 300 200 100
Example - Account 4 (ASN 400) checks down path that paths 3->4, 2->3, and 1->2 exist
python validate_advertisement.py ACCOUNT4 10.0.20.0 24 400 300 200 100
Example output for the last command:
AS_PATH Validation Results for: "10.0.20.0/24 : 300, 200, 100"
ASN 300 -> ASN 400 hop in AS_PATH is: valdiateAdvertisementResult.advertisementVALID
ASN 200 -> ASN 300 hop in AS_PATH is: valdiateAdvertisementResult.advertisementVALID
ASN 100 -> ASN 200 hop in AS_PATH is: valdiateAdvertisementResult.advertisementVALID
Example of a bad path:
- Account 5 (ASN 500) gets an advertisement:
10.0.20.0/24 : 300 200 100
- Note that ASN300 never said they were sending to ASN500! So this should fail. Let's try:
python validate_advertisement.py ACCOUNT5 10.0.20.0 24 500 300 200 100
Result:
AS_PATH Validation Results for: "10.0.20.0/24 : 300, 200, 100"
ASN 300 -> ASN 500 hop in AS_PATH is: valdiateAdvertisementResult.advertisementINVALID
ASN 200 -> ASN 300 hop in AS_PATH is: valdiateAdvertisementResult.advertisementVALID
ASN 100 -> ASN 200 hop in AS_PATH is: valdiateAdvertisementResult.advertisementVALID
^ so this path 100 -> 200 -> 300 -> 500 is invalid!
Path of advertisements for example:
- Path: 100 -> 200 -> 300 -> 400 -> 500 -> 600
Format:
python add_advertisement.py <account> <ip> <subnet> <nextHopASN>
Example:
python add_advertisement.py ACCOUNT1 10.0.20.0 24 200
python add_advertisement.py ACCOUNT2 10.0.20.0 24 300
python add_advertisement.py ACCOUNT3 10.0.20.0 24 400
# skip announcement from 400 to 500.
python add_advertisement.py ACCOUNT5 10.0.20.0 24 600
python validate_advertisement.py <account2> <ip> <subnet> <myASN> <Received advertisement's AS_PATH>
Account 6 (ASN600) needs to validate that the entire 100 -> 200 -> 300 -> 400 -> 500 -> 600 is valid
python validate_advertisement.py ACCOUNT6 10.0.20.0 24 600 500 400 300 200 10
Output:
All ASNs in AS_PATH are participants
AS_PATH Validation Results for: "10.0.20.0/24 : 500, 400, 300, 200, 100"
ASN 500 -> ASN 600 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
ASN 400 -> ASN 500 hop in AS_PATH is: validateAdvertisementResult.advertisementINVALID
ASN 300 -> ASN 400 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
ASN 200 -> ASN 300 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
ASN 100 -> ASN 200 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
Entire Path is: validatePathResult.pathINVALID
Invalid advertisements: ['400->500']
Here ^ we have an invalid path. since ACCOUNT4 (ASN400) never said it was announcing to ASN500
Account 6 (ASN600) needs to validate that the entire 100 -> 200 -> 300 -> 400 -> 500 -> 600 is valid
- In this case, ASN400 will not participate. To simulate this, comment out the folling lines in
asn_address_mapping.yaml
:
asn_400:
validation_contract: <account4-path-validation-contract-address>
- Now, when we look for ASN 400's contract, it won't exist, indicating we don't know it or ASN400 is a non participant
Run:
python validate_advertisement.py ACCOUNT6 10.0.20.0 24 600 500 400 300 200 100
Output:
P -> NP -> P found for: (300,400,500)
AS_PATH Validation Results for: "10.0.20.0/24 : 500, 400, 300, 200, 100"
ASN 500 -> ASN 600 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
ASN 400 -> ASN 500 hop in AS_PATH is: validateAdvertisementResult.nonParticipantSource
ASN 300 -> ASN 400 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
ASN 200 -> ASN 300 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
ASN 100 -> ASN 200 hop in AS_PATH is: validateAdvertisementResult.advertisementVALID
Entire Path is: validatePathResult.pathPnpVALID
Non participants: [400]
Result:
- Here ^ we have a non partipant (NP) surrounded by 2 participating ASNs (P).
- If we assume no two ASNs are scheming together, this should be a valid advertisement.
- ASN500 checks that ASN300 sent to ASN400. And ASN500 got the message from ASN400.
Note: if there are two or more non participants in a row, then the path validation should fail.
prefix_validatePrefix(addvertisedIp, advertisedMask, advertisedASN)
- all we're checking here is that an ASN and IP/subnet are matched together in the contract.
- we do not check that the advertisement received was actually sent by the ASN.
- this would require signing BGP updates/announcements. and adding signature in the BGP payload or something.
Check
- who owns this.
- if ASN<=>IP/mask binding returns 0, then IANA owns it. in that case, caller of this function must be IANA? (let's start here)
- if ASN<=>IP/mask binding returns some address, we need to figure out who that is.
- we may need to make this a transfer_prefix() function or something. Need both current owner and new owner to sign and approve.
- in fact, we could just ensure that the caller of this function (msg.sender) is the current owner of the IP/mask.
- so it would just need to be an if statement.
- if current owner is 0,
- Then this function must be called by someone in the owner's list (aka iana)
- if current owner is 0xAFD14...A398F, then they must be the ones calling this function.
- if current owner is 0,
- essentially enforced a top down approach. current owner must delegate to new owner.
- but then new owner and current owner must both agree or something when to give up the space. or something. idk