示例#1
0
    def __init__(
        self,
        files: Iterable[Union[str, Path]],
        checksum_module: str = None,
        skip_model_verification: bool = False,
        skip_message_verification: bool = False,
        split_disjunctions: bool = False,
    ):
        model = self._create_model([Path(f) for f in files],
                                   skip_model_verification, split_disjunctions)
        checksum_functions = self._parse_checksum_module(checksum_module)
        missing_checksum_definitions = {
            (str(message.identifier), str(field_identifier))
            for message in model.messages
            for field_identifier in message.checksums
        } - {(str(message_name), field_name)
             for message_name, checksum_mapping in checksum_functions.items()
             for field_name in checksum_mapping}

        if len(missing_checksum_definitions) != 0:
            raise ValidationError(
                "missing checksum definition for " + ", ".join([
                    f'field "{field_name}" of "{message_name}"' for
                    message_name, field_name in missing_checksum_definitions
                ]))

        try:
            self._pyrflx = PyRFLX(model, checksum_functions,
                                  skip_message_verification)
        except PyRFLXError as e:
            raise ValidationError(f"invalid checksum definition: {e}") from e
示例#2
0
def test_tlv_message_with_not_operator_exhausting() -> None:
    message = Message(
        "TLV::Message_With_Not_Operator_Exhausting",
        [
            Link(INITIAL, Field("Tag")),
            Link(
                Field("Tag"),
                Field("Length"),
                Not(Not(Not(NotEqual(Variable("Tag"), Variable("Msg_Data"))))),
            ),
            Link(
                Field("Tag"),
                FINAL,
                reduce(
                    lambda acc, f: f(acc),
                    [Not, Not] * 16,
                    Not(
                        Or(
                            Not(
                                Not(
                                    Equal(Variable("Tag"),
                                          Variable("Msg_Data")))),
                            Not(Equal(Variable("Tag"), Variable("Msg_Error"))),
                        )),
                ),
            ),
            Link(Field("Length"),
                 Field("Value"),
                 size=Mul(Variable("Length"), Number(8))),
            Link(Field("Value"), FINAL),
        ],
        {
            Field("Tag"): TLV_TAG,
            Field("Length"): TLV_LENGTH,
            Field("Value"): OPAQUE
        },
    )

    with pytest.raises(
            FatalError,
            match=re.escape(
                "failed to simplify complex expression `not (not (not (not "
                "(not (not (not (not (not (not (not (not (not (not (not (not "
                "(not (not (not (not (not (not (not (not (not (not (not (not "
                "(not (not (not (not (not (not (not (Tag = TLV::Msg_Data))\n"
                "                                 "
                "or not (Tag = TLV::Msg_Error))))))))))))))))))))))))))))))))))` "
                "after `16` iterations, best effort: "
                "`not (not (not (not (not (not (not (not (not (not (not (not (not "
                "(not (not (not (not (Tag = TLV::Msg_Data\n"
                "                 or Tag /= TLV::Msg_Error)))))))))))))))))`"),
    ):
        model = PyRFLX(model=Model([TLV_TAG, TLV_LENGTH, message]))
        pkg = model.package("TLV")
        msg = pkg.new_message("Message_With_Not_Operator_Exhausting")
        test_bytes = b"\x01\x00\x04\x00\x00\x00\x00"
        msg.parse(test_bytes)
示例#3
0
def test_no_verification_sequence_nested_messages(
        sequence_message_package: Package,
        message_sequence_value: MessageValue) -> None:
    sequence_message_one = sequence_message_package.new_message(
        "Sequence_Element")
    sequence_message_one.set("Byte", 5)
    sequence_message_two = sequence_message_package.new_message(
        "Sequence_Element")
    sequence_message_two.set("Byte", 6)
    sequence: List[TypeValue] = [sequence_message_one, sequence_message_two]
    message_sequence_value.set("Length", 2)
    message_sequence_value.set("Sequence_Field", sequence)
    assert message_sequence_value.valid_message

    pyrflx_ = PyRFLX.from_specs(
        [SPEC_DIR / "sequence_message.rflx"],
        skip_model_verification=True,
        skip_message_verification=True,
    )
    sequence_message_package_unv = pyrflx_.package("Sequence_Message")
    sequence_message_unv = sequence_message_package_unv.new_message(
        "Message_Sequence")
    sequence_element_one_unv = sequence_message_package_unv.new_message(
        "Sequence_Element")
    sequence_element_one_unv.set("Byte", 5)
    sequence_element_two_unv = sequence_message_package_unv.new_message(
        "Sequence_Element")
    sequence_element_two_unv.set("Byte", 6)
    sequence_unv: List[TypeValue] = [
        sequence_element_one_unv, sequence_element_two_unv
    ]
    sequence_message_unv.set("Length", 2)
    sequence_message_unv.set("Sequence_Field", sequence_unv)
    assert sequence_message_unv.valid_message
    assert sequence_message_unv.bytestring == message_sequence_value.bytestring
示例#4
0
 def __init__(self) -> None:
     pyrflx = PyRFLX(["specs/icmp.rflx"])
     self.package_icmp = pyrflx["ICMP"]
     self.icmp_data = (
         b"\x4a\xfc\x0d\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17"
         b"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27"
         b"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37"
     )
示例#5
0
def test_tlv_message_with_not_operator() -> None:
    message = Message(
        "TLV::Message_With_Not_Operator",
        [
            Link(INITIAL, Field("Tag")),
            Link(
                Field("Tag"),
                Field("Length"),
                Not(Not(Not(NotEqual(Variable("Tag"), Variable("Msg_Data"))))),
            ),
            Link(
                Field("Tag"),
                FINAL,
                Not(
                    Not(
                        Not(
                            Or(
                                Not(
                                    Not(
                                        Equal(Variable("Tag"),
                                              Variable("Msg_Data")))),
                                Not(
                                    Equal(Variable("Tag"),
                                          Variable("Msg_Error"))),
                            )))),
            ),
            Link(Field("Length"),
                 Field("Value"),
                 size=Mul(Variable("Length"), Number(8))),
            Link(Field("Value"), FINAL),
        ],
        {
            Field("Tag"): TLV_TAG,
            Field("Length"): TLV_LENGTH,
            Field("Value"): OPAQUE
        },
    )

    model = PyRFLX(model=Model([TLV_TAG, TLV_LENGTH, message]))
    pkg = model.package("TLV")
    msg = pkg.new_message("Message_With_Not_Operator")
    test_bytes = b"\x01\x00\x04\x00\x00\x00\x00"
    msg.parse(test_bytes)
    assert msg.valid_message
    assert msg.bytestring == test_bytes
示例#6
0
def test_validate_message_parameterized_message() -> None:
    validator = Validator([], skip_model_verification=True)
    message = (PyRFLX.from_specs(["tests/data/specs/parameterized.rflx"],
                                 skip_model_verification=True).package(
                                     "Parameterized").new_message("Message"))
    validation_result = validator._validate_message(  # pylint: disable = protected-access
        Path(TEST_DIR /
             "parameterized/message/valid/parameterized_message.raw"),
        valid_original_message=True,
        message_value=message,
    )
    assert validation_result.validation_success
示例#7
0
 def __init__(self, specdir: Path) -> None:
     print("Loading...")
     start = perf_counter()
     self.__pyrflx = PyRFLX.from_specs(
         [str(specdir / "ipv4.rflx"),
          str(specdir / "icmp.rflx")],
         skip_model_verification=True,
         skip_message_verification=True,
     )
     self.__ipv4 = self.__pyrflx.package("IPv4")
     self.__icmp = self.__pyrflx.package("ICMP")
     print(f"Loaded in {perf_counter() - start} seconds")
示例#8
0
def test_validate_message_original_and_parsed_not_equal() -> None:
    validator = Validator([], skip_model_verification=True)
    ethernet_too_short_value = (PyRFLX.from_specs(
        [SPEC_DIR / "ethernet.rflx"],
        skip_model_verification=True).package("Ethernet").new_message("Frame"))
    validation_result = validator._validate_message(  # pylint: disable = protected-access
        Path(TEST_DIR /
             "ethernet/frame/invalid/ethernet_invalid_too_long.raw"),
        valid_original_message=True,
        message_value=ethernet_too_short_value,
    )
    assert (validation_result.parser_error ==
            "message parsed by PyRFLX is shorter than the original message")
示例#9
0
def fixture_pyrflx() -> PyRFLX:
    return PyRFLX(
        [
            f"{SPECDIR}/ethernet.rflx",
            f"{SPECDIR}/icmp.rflx",
            f"{SPECDIR}/in_ethernet.rflx",
            f"{SPECDIR}/in_ipv4.rflx",
            f"{SPECDIR}/ipv4.rflx",
            f"{SPECDIR}/tls_alert.rflx",
            f"{SPECDIR}/tls_record.rflx",
            f"{SPECDIR}/tlv.rflx",
            f"{SPECDIR}/udp.rflx",
            f"{TESTDIR}/array_message.rflx",
            f"{TESTDIR}/array_type.rflx",
            f"{TESTDIR}/message_odd_length.rflx",
            f"{TESTDIR}/null_message.rflx",
            f"{TESTDIR}/tlv_with_checksum.rflx",
        ]
    )
示例#10
0
def test_parameterized_message_excess_parameter() -> None:
    validator = Validator([], skip_model_verification=True)
    message = (PyRFLX.from_specs(["tests/data/specs/parameterized.rflx"],
                                 skip_model_verification=True).package(
                                     "Parameterized").new_message("Message"))
    with pytest.raises(
            ValidationError,
            match=
        (r"^"
         f"{TEST_DIR}/parameterized/message/invalid/parameterized_message_excess_parameter.raw:"
         r" pyrflx: error: unexpected parameter values: Excess"
         r"$"),
    ):
        validator._validate_message(  # pylint: disable = protected-access
            Path(
                TEST_DIR /
                "parameterized/message/invalid/parameterized_message_excess_parameter.raw"
            ),
            valid_original_message=True,
            message_value=message,
        )
示例#11
0
def test_no_verification_ethernet(ethernet_frame_value: MessageValue) -> None:
    payload = (b"\x45\x00\x00\x2e\x00\x01\x00\x00\x40\x11\x7c\xbc"
               b"\x7f\x00\x00\x01\x7f\x00\x00\x01\x00\x35\x00\x35"
               b"\x00\x1a\x01\x4e\x00\x00\x00\x00\x00\x00\x00\x00"
               b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
    ethernet_frame_value.set("Destination", int("FFFFFFFFFFFF", 16))
    ethernet_frame_value.set("Source", int("0", 16))
    ethernet_frame_value.set("Type_Length_TPID", int("0800", 16))
    ethernet_frame_value.set("Type_Length", int("0800", 16))
    ethernet_frame_value.set("Payload", payload)
    assert ethernet_frame_value.valid_message
    pyrflx_ = PyRFLX.from_specs(
        [SPEC_DIR / "ethernet.rflx"],
        skip_model_verification=True,
        skip_message_verification=True,
    )
    frame_unv = pyrflx_.package("Ethernet").new_message("Frame")
    frame_unv.set("Destination", int("FFFFFFFFFFFF", 16))
    frame_unv.set("Source", int("0", 16))
    frame_unv.set("Type_Length_TPID", int("0800", 16))
    frame_unv.set("Type_Length", int("0800", 16))
    frame_unv.set("Payload", payload)
    assert frame_unv.valid_message
    assert frame_unv.bytestring == ethernet_frame_value.bytestring
示例#12
0
def fixture_parameterized_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Parameterized")
示例#13
0
def fixture_endianness_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Endianness")
示例#14
0
def fixture_message_type_size(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Message_Type_Size_Condition")
示例#15
0
def fixture_always_valid_aspect_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Always_Valid_Aspect")
示例#16
0
def fixture_sequence_message_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Sequence_Message")
示例#17
0
def fixture_message_size_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Message_Size")
示例#18
0
def fixture_udp_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("UDP")
示例#19
0
def test_file_not_found(tmp_path: Path) -> None:
    with pytest.raises(FileNotFoundError):
        PyRFLX([f"{tmp_path}/test.rflx"])
示例#20
0
def fixture_tls_record_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("TLS_Record")
示例#21
0
def fixture_tls_alert_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("TLS_Alert")
示例#22
0
def test_imported_literals(tmp_path: Path) -> None:
    with open(tmp_path / "test.rflx", "x") as f:
        f.write(
            """
            with Foo;

            package Test is

               type T is (E1 => 1, E2 => 2) with Size => 8;

               type Message is
                  message
                     A : Foo.T
                        then null
                           if A = Foo.E1;
                  end message;

            end Test;
            """
        )

    with open(tmp_path / "foo.rflx", "x") as f:
        f.write(
            """
            package Foo is

               type T is (E1 => 11, E2 => 12) with Size => 8;

            end Foo;
            """
        )

    pyrflx = PyRFLX([str(tmp_path / "test.rflx")])
    m = pyrflx["Test"]["Message"]

    m.set("A", "E1")
    assert m.valid_message

    m.set("A", "Foo.E1")
    assert m.valid_message

    m.parse(b"\x0B")
    assert m.valid_message
    assert m.get("A") == "Foo.E1"

    with pytest.raises(
        ValueError,
        match=r"^none of the field conditions \['A = Foo.E1'\] for field A have been met"
        " by the assigned value: 00001100$",
    ):
        m.parse(b"\x0C")
        assert not m.valid_message

    with pytest.raises(
        ValueError,
        match=r"^none of the field conditions \['A = Foo.E1'\] for field A have been met"
        " by the assigned value: E2$",
    ):
        m.set("A", "E2")
        assert not m.valid_message

    with pytest.raises(
        ValueError,
        match=r"^none of the field conditions \['A = Foo.E1'\] for field A have been met"
        " by the assigned value: Foo.E2$",
    ):
        m.set("A", "Foo.E2")
        assert not m.valid_message
示例#23
0
def fixture_ethernet_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Ethernet")
示例#24
0
    assert tag_first == 0 and checksum_first_minus_one == 15
    second_arg = kwargs.get("Checksum'Last + 1 .. Message'Last")
    assert isinstance(second_arg, tuple)
    checksum_last_plus_one, data_last = second_arg
    assert checksum_last_plus_one == 32 and data_last == 511
    checksum_size = kwargs.get("Checksum'Size")
    assert isinstance(checksum_size, int)
    assert checksum_size == 16

    checksum_bytes = message[tag_first : (checksum_first_minus_one + 1) // 8]
    checksum_bytes += b"\x00" * (checksum_size // 8)
    checksum_bytes += message[(checksum_last_plus_one // 8) : (data_last + 1) // 8]
    return utils.internet_checksum(checksum_bytes)


PYRFLX = PyRFLX.from_specs(["specs/ipv4.rflx"], skip_model_verification=True)
ICMP = PYRFLX.package("ICMP")
ICMP.set_checksum_functions({"Message": {"Checksum": icmp_checksum}})
IP = PYRFLX.package("IPv4")

ICMP_DATA = bytes(list(range(0, 56)))


def ping(target: str) -> None:
    target_ip = socket.gethostbyname(target)

    print(f"PING {target} ({target_ip})")

    sock_out = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
    sock_in = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
    fcntl.fcntl(sock_in, fcntl.F_SETFL, os.O_NONBLOCK)
示例#25
0
def fixture_low_order_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Low_Order")
示例#26
0
def fixture_tlv_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("TLV")
示例#27
0
def fixture_aggregate_in_relation_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("Aggregate_In_Relation")
示例#28
0
def test_attributes(pyrflx: PyRFLX) -> None:
    pyrflx = PyRFLX([f"{TESTDIR}/tlv_with_checksum.rflx"])
    assert isinstance(pyrflx["TLV_With_Checksum"], Package)
    tlv_package = pyrflx["TLV_With_Checksum"]
    assert isinstance(tlv_package["Message"], MessageValue)
示例#29
0
def fixture_icmp_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("ICMP")
示例#30
0
def fixture_ipv4_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
    return pyrflx_.package("IPv4")