-
Notifications
You must be signed in to change notification settings - Fork 786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2004 scan target configuration #2133
Merged
Merged
Changes from 9 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
a943891
Common: Add validators for ScanTargetConfigurationSchema
VakarisZ 96af1e0
Common: Add documentation to ScanTargetConfiguration dataclass
VakarisZ a1d9118
UT: Split up ip range validation tests more
VakarisZ ce33a7b
Common: Improve network range validation (less regex)
VakarisZ a1760a8
Common: Improve hostname pattern matching in scan target configuration
VakarisZ 16ac6b2
Common: Improve documentation of ScanTargetConfiguration
VakarisZ 3a6fcd6
Common: Style improvements in ip_ranges.py
VakarisZ 2503e83
Common: Separate filename validation out of config schemas
VakarisZ 068a7e3
Common: Improve the style of filename validation
VakarisZ d2d9d4c
Common: Reformat ScanTargetConfiguration docstrings
mssalvatore 42e6039
Common: Shorten the validator import statements
VakarisZ 22b3874
Common: Do small style fixes in validators
VakarisZ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import re | ||
from pathlib import PureWindowsPath | ||
|
||
from marshmallow import ValidationError | ||
|
||
_valid_windows_filename_regex = re.compile(r"^[^<>:\"\\\/|?*]*[^<>:\"\\\/|?* \.]+$|^$") | ||
_valid_linux_filename_regex = re.compile(r"^[^\0/]*$") | ||
|
||
|
||
def validate_linux_filename(linux_filename: str): | ||
if not re.match(_valid_linux_filename_regex, linux_filename): | ||
raise ValidationError(f"Invalid Unix filename {linux_filename}: illegal characters") | ||
|
||
|
||
def validate_windows_filename(windows_filename: str): | ||
validate_windows_filename_not_reserved(windows_filename) | ||
if not re.match(_valid_windows_filename_regex, windows_filename): | ||
raise ValidationError(f"Invalid Windows filename {windows_filename}: illegal characters") | ||
|
||
|
||
def validate_windows_filename_not_reserved(windows_filename: str): | ||
# filename shouldn't start with any of these and be followed by a period | ||
if PureWindowsPath(windows_filename).is_reserved(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fantastic! |
||
raise ValidationError(f"Invalid Windows filename {windows_filename}: reserved name used") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import re | ||
from ipaddress import AddressValueError, IPv4Address, IPv4Network, NetmaskValueError | ||
|
||
from marshmallow import ValidationError | ||
|
||
|
||
def validate_subnet_range(subnet_range: str): | ||
try: | ||
return validate_ip(subnet_range) | ||
except ValidationError: | ||
pass | ||
|
||
try: | ||
return validate_ip_range(subnet_range) | ||
except ValidationError: | ||
pass | ||
|
||
try: | ||
return validate_ip_network(subnet_range) | ||
except ValidationError: | ||
pass | ||
|
||
try: | ||
return validate_hostname(subnet_range) | ||
except ValidationError: | ||
raise ValidationError(f"Invalid subnet range {subnet_range}") | ||
|
||
|
||
def validate_hostname(hostname: str): | ||
# Based on hostname syntax: https://www.rfc-editor.org/rfc/rfc1123#page-13 | ||
hostname_segments = hostname.split(".") | ||
if any((part.endswith("-") or part.startswith("-") for part in hostname_segments)): | ||
raise ValidationError(f"Hostname segment can't start or end with a hyphen: {hostname}") | ||
if not any((char.isalpha() for char in hostname_segments[-1])): | ||
raise ValidationError(f"Last segment of a hostname must contain a letter: {hostname}") | ||
|
||
valid_characters_pattern = r"^[A-Za-z0-9\-]+$" | ||
valid_characters_regex = re.compile(valid_characters_pattern) | ||
matches = ( | ||
re.match(valid_characters_regex, hostname_segment) for hostname_segment in hostname_segments | ||
) | ||
|
||
if not all(matches): | ||
raise ValidationError(f"Hostname contains invalid characters: {hostname}") | ||
|
||
|
||
def validate_ip_network(ip_network: str): | ||
try: | ||
IPv4Network(ip_network, strict=False) | ||
except (NetmaskValueError, AddressValueError): | ||
raise ValidationError(f"Invalid IPv4 network {ip_network}") | ||
|
||
|
||
def validate_ip_range(ip_range: str): | ||
try: | ||
ip_range = ip_range.replace(" ", "") | ||
ips = ip_range.split("-") | ||
if len(ips) != 2: | ||
raise ValidationError(f"Invalid IP range {ip_range}") | ||
validate_ip(ips[0]) | ||
validate_ip(ips[1]) | ||
except IndexError: | ||
raise ValidationError(f"Invalid IP range {ip_range}") | ||
mssalvatore marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
def validate_ip(ip: str): | ||
try: | ||
IPv4Address(ip) | ||
except AddressValueError: | ||
raise ValidationError(f"Invalid IP address {ip}") |
Empty file.
Empty file.
File renamed without changes.
Empty file.
70 changes: 70 additions & 0 deletions
70
monkey/tests/unit_tests/common/agent_configuration/validators/test_ip_ranges.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import pytest | ||
from marshmallow import ValidationError | ||
|
||
from common.agent_configuration.validators.ip_ranges import validate_ip, validate_subnet_range | ||
|
||
|
||
@pytest.mark.parametrize("ip", ["192.168.56.1", "0.0.0.0"]) | ||
def test_validate_ip_valid(ip): | ||
validate_ip(ip) | ||
|
||
|
||
@pytest.mark.parametrize("ip", ["1.1.1", "257.256.255.255", "1.1.1.1.1"]) | ||
def test_validate_ip_invalid(ip): | ||
with pytest.raises(ValidationError): | ||
validate_ip(ip) | ||
|
||
|
||
@pytest.mark.parametrize("ip", ["192.168.56.1", "0.0.0.0"]) | ||
def test_validate_subnet_range__ip_valid(ip): | ||
validate_subnet_range(ip) | ||
|
||
|
||
@pytest.mark.parametrize("ip", ["1.1.1", "257.256.255.255", "1.1.1.1.1"]) | ||
def test_validate_subnet_range__ip_invalid(ip): | ||
with pytest.raises(ValidationError): | ||
validate_subnet_range(ip) | ||
|
||
|
||
@pytest.mark.parametrize("ip_range", ["1.1.1.1 - 2.2.2.2", "1.1.1.255-1.1.1.1"]) | ||
def test_validate_subnet_range__ip_range_valid(ip_range): | ||
validate_subnet_range(ip_range) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"ip_range", | ||
[ | ||
"1.1.1-2.2.2.2", | ||
"0-.1.1.1-2.2.2.2", | ||
"a..1.1.1-2.2.2.2", | ||
"257.1.1.1-2.2.2.2", | ||
"1.1.1.1-2.2.2.2-3.3.3.3", | ||
], | ||
) | ||
def test_validate_subnet_range__ip_range_invalid(ip_range): | ||
with pytest.raises(ValidationError): | ||
validate_subnet_range(ip_range) | ||
|
||
|
||
@pytest.mark.parametrize("hostname", ["infection.monkey", "1nfection-Monkey", "1.1.1.1a"]) | ||
def test_validate_subnet_range__hostname_valid(hostname): | ||
validate_subnet_range(hostname) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"hostname", ["hy&!he.host", "čili-peppers.are-hot", "one.two-", "one-.two", "one@two", ""] | ||
) | ||
def test_validate_subnet_range__hostname_invalid(hostname): | ||
with pytest.raises(ValidationError): | ||
validate_subnet_range(hostname) | ||
|
||
|
||
@pytest.mark.parametrize("cidr_range", ["1.1.1.1/24", "1.1.1.1/0"]) | ||
def test_validate_subnet_range__cidr_valid(cidr_range): | ||
validate_subnet_range(cidr_range) | ||
|
||
|
||
@pytest.mark.parametrize("cidr_range", ["1.1.1/24", "1.1.1.1/-1", "1.1.1.1/33", "1.1.1.1/222"]) | ||
def test_validate_subnet_range__cidr_invalid(cidr_range): | ||
with pytest.raises(ValidationError): | ||
validate_subnet_range(cidr_range) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.