Skip to content

Commit

Permalink
Added ability to track routing loops
Browse files Browse the repository at this point in the history
  • Loading branch information
jfuruness committed Dec 13, 2024
1 parent 8a081af commit d92b809
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 10 deletions.
1 change: 1 addition & 0 deletions bgpy/shared/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Outcomes(YamlAbleEnum):
VICTIM_SUCCESS: int = 1
DISCONNECTED: int = 2
UNDETERMINED: int = 3
DATA_PLANE_LOOP: int = 4


class Relationships(YamlAbleEnum):
Expand Down
17 changes: 13 additions & 4 deletions bgpy/simulation_framework/as_graph_analyzers/as_graph_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,17 @@ def analyze(self) -> dict[int, dict[int, int]]:
# Data plane funcs #
####################

def _get_as_outcome_data_plane(self, as_obj: AS) -> int:
def _get_as_outcome_data_plane(
self, as_obj: AS, visited_asns: set[int] | None = None
) -> int:
"""Recursively returns the as outcome"""

if as_obj.asn in self._data_plane_outcomes:
return self._data_plane_outcomes[as_obj.asn]
else:
most_specific_ann = self._most_specific_ann_dict[as_obj]
outcome_int = self._determine_as_outcome_data_plane(
as_obj, most_specific_ann
as_obj, most_specific_ann, visited_asns
)
# We haven't traced back all the way on the AS path
if outcome_int == Outcomes.UNDETERMINED.value:
Expand All @@ -106,14 +108,19 @@ def _get_as_outcome_data_plane(self, as_obj: AS) -> int:
# advanced types of hijacks such as origin spoofing hijacks
most_specific_ann.next_hop_asn
]
outcome_int = self._get_as_outcome_data_plane(next_as)
visited_asns = visited_asns if visited_asns is not None else set()
visited_asns.add(as_obj.asn)
outcome_int = self._get_as_outcome_data_plane(next_as, visited_asns)
assert outcome_int != Outcomes.UNDETERMINED.value, "Shouldn't be possible"

self._data_plane_outcomes[as_obj.asn] = outcome_int
return outcome_int

def _determine_as_outcome_data_plane(
self, as_obj: AS, most_specific_ann: Optional["Ann"]
self,
as_obj: AS,
most_specific_ann: Optional["Ann"],
visited_asns: set[int] | None = None,
) -> int:
"""Determines the outcome at an AS
Expand All @@ -134,6 +141,8 @@ def _determine_as_outcome_data_plane(
or most_specific_ann.next_hop_asn == as_obj.asn
):
return Outcomes.DISCONNECTED.value
elif visited_asns and as_obj.asn in visited_asns:
return Outcomes.DATA_PLANE_LOOP.value
else:
return Outcomes.UNDETERMINED.value

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ class InterceptionASGraphAnalyzer(ASGraphAnalyzer):
the original connection alive
"""

def _get_as_outcome_data_plane(self, as_obj: AS) -> int:
def _get_as_outcome_data_plane(
self, as_obj: AS, visited_asns: set[int] | None = None
) -> int:
"""Recursively returns the as outcome"""

if as_obj.asn in self._data_plane_outcomes:
return self._data_plane_outcomes[as_obj.asn]
else:
most_specific_ann = self._most_specific_ann_dict[as_obj]
outcome_int = self._determine_as_outcome_data_plane(
as_obj, most_specific_ann
as_obj, most_specific_ann, visited_asns
)
visited_asns = visited_asns if visited_asns is not None else set()
visited_asns.add(as_obj.asn)

# Continue tracing back. Only succeed if it goes back to the victim
if outcome_int == Outcomes.ATTACKER_SUCCESS.value:
assert most_specific_ann, "If outcome==attacker, ann must exist"
Expand All @@ -47,7 +52,10 @@ def _get_as_outcome_data_plane(self, as_obj: AS) -> int:
self._data_plane_outcomes[as_obj.asn] = Outcomes.DISCONNECTED.value
return Outcomes.DISCONNECTED.value
else:
next_as_outcome_int = self._get_as_outcome_data_plane(next_as)
next_as_outcome_int = self._get_as_outcome_data_plane(
next_as,
visited_asns,
)
# Next AS tunnels back to victim, return attacker success
if next_as_outcome_int in (
Outcomes.ATTACKER_SUCCESS.value,
Expand All @@ -74,7 +82,7 @@ def _get_as_outcome_data_plane(self, as_obj: AS) -> int:
# advanced types of hijacks such as origin spoofing hijacks
most_specific_ann.next_hop_asn
]
outcome_int = self._get_as_outcome_data_plane(next_as)
outcome_int = self._get_as_outcome_data_plane(next_as, visited_asns)
assert outcome_int != Outcomes.UNDETERMINED.value, "not possible"
self._data_plane_outcomes[as_obj.asn] = outcome_int
return outcome_int
Expand All @@ -85,7 +93,10 @@ def _get_as_outcome_data_plane(self, as_obj: AS) -> int:
raise NotImplementedError("Shouldn't be possible")

def _determine_as_outcome_data_plane(
self, as_obj: AS, most_specific_ann: Optional["Ann"]
self,
as_obj: AS,
most_specific_ann: Optional["Ann"],
visited_asns: set[int] | None = None,
) -> int:
"""Determines the outcome at an AS
Expand All @@ -103,5 +114,7 @@ def _determine_as_outcome_data_plane(
or most_specific_ann.next_hop_asn == as_obj.asn
):
return Outcomes.DISCONNECTED.value
elif visited_asns and as_obj.asn in visited_asns:
return Outcomes.DATA_PLANE_LOOP.value
else:
return Outcomes.UNDETERMINED.value
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "bgpy_pkg"
version = "12.0.5"
version = "12.1.0"
requires-python = ">=3.10"
description = "Simulates BGP, ROV, ASPA, etc in an extensible manner"
readme = "README.md"
Expand Down

0 comments on commit d92b809

Please sign in to comment.