@@ -577,5 +577,123 @@ BOOST_AUTO_TEST_CASE(pcp_ipv4_fail_unsupported_version)
577577 BOOST_CHECK_EQUAL (*err, MappingError::UNSUPP_VERSION);
578578}
579579
580+ // NAT-PMP IPv4 protocol error scenarii.
581+ BOOST_AUTO_TEST_CASE (natpmp_protocol_error)
582+ {
583+ // First scenario: non-0 result code when requesting external IP.
584+ std::vector<TestOp> script{
585+ {
586+ 0ms, TestOp::SEND,
587+ {
588+ 0x00 , 0x00 , // version, opcode (request external IP)
589+ }, 0
590+ },
591+ {
592+ 2ms, TestOp::RECV,
593+ {
594+ 0x00 , 0x80 , 0x00 , 0x42 , // version, opcode (external IP), result code (*NOT* success)
595+ 0x66 , 0xfd , 0xa1 , 0xee , // seconds sinds start of epoch
596+ 0x01 , 0x02 , 0x03 , 0x04 , // external IP address
597+ }, 0
598+ },
599+ };
600+ CreateSock = [this , &script](int domain, int type, int protocol) {
601+ if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
602+ return std::unique_ptr<PCPTestSock>();
603+ };
604+
605+ auto res = NATPMPRequestPortMap (default_gateway_ipv4, 1234 , 1000 , 1 , 200ms);
606+
607+ MappingError* err = std::get_if<MappingError>(&res);
608+ BOOST_REQUIRE (err);
609+ BOOST_CHECK_EQUAL (*err, MappingError::PROTOCOL_ERROR);
610+
611+ // First scenario: non-0 result code when requesting port mapping.
612+ script = {
613+ {
614+ 0ms, TestOp::SEND,
615+ {
616+ 0x00 , 0x00 , // version, opcode (request external IP)
617+ }, 0
618+ },
619+ {
620+ 2ms, TestOp::RECV,
621+ {
622+ 0x00 , 0x80 , 0x00 , 0x00 , // version, opcode (external IP), result code (success)
623+ 0x66 , 0xfd , 0xa1 , 0xee , // seconds sinds start of epoch
624+ 0x01 , 0x02 , 0x03 , 0x04 , // external IP address
625+ }, 0
626+ },
627+ {
628+ 0ms, TestOp::SEND,
629+ {
630+ 0x00 , 0x02 , 0x00 , 0x00 , // version, opcode (request map TCP)
631+ 0x04 , 0xd2 , 0x04 , 0xd2 , // internal port, suggested external port
632+ 0x00 , 0x00 , 0x03 , 0xe8 , // requested mapping lifetime in seconds
633+ }, 0
634+ },
635+ {
636+ 2ms, TestOp::RECV,
637+ {
638+ 0x00 , 0x82 , 0x00 , 0x43 , // version, opcode (mapped TCP)
639+ 0x66 , 0xfd , 0xa1 , 0xee , // seconds sinds start of epoch
640+ 0x04 , 0xd2 , 0x04 , 0xd2 , // internal port, mapped external port
641+ 0x00 , 0x00 , 0x01 , 0xf4 , // mapping lifetime in seconds
642+ }, 0
643+ },
644+ };
645+ CreateSock = [this , &script](int domain, int type, int protocol) {
646+ if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
647+ return std::unique_ptr<PCPTestSock>();
648+ };
649+
650+ res = NATPMPRequestPortMap (default_gateway_ipv4, 1234 , 1000 , 1 , 200ms);
651+
652+ err = std::get_if<MappingError>(&res);
653+ BOOST_REQUIRE (err);
654+ BOOST_CHECK_EQUAL (*err, MappingError::PROTOCOL_ERROR);
655+ }
656+
657+ // PCP IPv4 protocol error scenario.
658+ BOOST_AUTO_TEST_CASE (pcp_protocol_error)
659+ {
660+ const std::vector<TestOp> script{
661+ {
662+ 0ms, TestOp::SEND,
663+ {
664+ 0x02 , 0x01 , 0x00 , 0x00 , // version, opcode
665+ 0x00 , 0x00 , 0x03 , 0xe8 , // lifetime
666+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xff , 0xff , 0xc0 , 0xa8 , 0x00 , 0x06 , // internal IP
667+ 0x11 , 0x22 , 0x33 , 0x44 , 0x55 , 0x66 , 0x77 , 0x88 , 0x99 , 0xaa , 0xbb , 0xcc , // nonce
668+ 0x06 , 0x00 , 0x00 , 0x00 , // protocol (TCP), reserved
669+ 0x04 , 0xd2 , 0x04 , 0xd2 , // internal port, suggested external port
670+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xff , 0xff , 0x00 , 0x00 , 0x00 , 0x00 , // suggested external IP
671+ }, 0
672+ },
673+ {
674+ 250ms, TestOp::RECV, // 250ms delay before answer
675+ {
676+ 0x02 , 0x81 , 0x00 , 0x42 , // version, opcode, result error
677+ 0x00 , 0x00 , 0x01 , 0xf4 , // granted lifetime
678+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , // reserved
679+ 0x11 , 0x22 , 0x33 , 0x44 , 0x55 , 0x66 , 0x77 , 0x88 , 0x99 , 0xaa , 0xbb , 0xcc , // nonce
680+ 0x06 , 0x00 , 0x00 , 0x00 , // protocol (TCP), reserved
681+ 0x04 , 0xd2 , 0x04 , 0xd2 , // internal port, assigned external port
682+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xff , 0xff , 0x01 , 0x02 , 0x03 , 0x04 , // assigned external IP
683+ }, 0
684+ },
685+ };
686+ CreateSock = [this , &script](int domain, int type, int protocol) {
687+ if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
688+ return std::unique_ptr<PCPTestSock>();
689+ };
690+
691+ auto res = PCPRequestPortMap (TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234 , 1000 , 1 , 1000ms);
692+
693+ MappingError* err = std::get_if<MappingError>(&res);
694+ BOOST_REQUIRE (err);
695+ BOOST_CHECK_EQUAL (*err, MappingError::PROTOCOL_ERROR);
696+ }
697+
580698BOOST_AUTO_TEST_SUITE_END ()
581699
0 commit comments