def generate_host(zc, host_name, type_): name = '.'.join((host_name, type_)) out = r.DNSOutgoing(r._FLAGS_QR_RESPONSE | r._FLAGS_AA) out.add_answer_at_time(r.DNSPointer(type_, r._TYPE_PTR, r._CLASS_IN, r._DNS_OTHER_TTL, name), 0) out.add_answer_at_time( r.DNSService(type_, r._TYPE_SRV, r._CLASS_IN, r._DNS_HOST_TTL, 0, 0, 80, name), 0 ) zc.send(out)
def mock_incoming_msg( service_state_change: r.ServiceStateChange, service_type: str, service_name: str, ttl: int ) -> r.DNSIncoming: generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE) generated.add_answer_at_time( r.DNSPointer(service_type, const._TYPE_PTR, const._CLASS_IN, ttl, service_name), 0 ) return r.DNSIncoming(generated.packets()[0])
def test_dns_pointer_record_hashablity(): """Test DNSPointer are hashable.""" ptr1 = r.DNSPointer('irrelevant', const._TYPE_PTR, const._CLASS_IN, const._DNS_OTHER_TTL, '123') ptr2 = r.DNSPointer('irrelevant', const._TYPE_PTR, const._CLASS_IN, const._DNS_OTHER_TTL, '456') record_set = set([ptr1, ptr2]) assert len(record_set) == 2 record_set.add(ptr1) assert len(record_set) == 2 ptr2_dupe = r.DNSPointer('irrelevant', const._TYPE_PTR, const._CLASS_IN, const._DNS_OTHER_TTL, '456') assert ptr2 == ptr2 assert ptr2.__hash__() == ptr2_dupe.__hash__() record_set.add(ptr2_dupe) assert len(record_set) == 2
def mock_incoming_msg( service_state_change: r.ServiceStateChange) -> r.DNSIncoming: ttl = 120 generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE) if service_state_change == r.ServiceStateChange.Updated: generated.add_answer_at_time( r.DNSText( service_name, const._TYPE_TXT, const._CLASS_IN | const._CLASS_UNIQUE, ttl, service_text, ), 0, ) return r.DNSIncoming(generated.packets()[0]) if service_state_change == r.ServiceStateChange.Removed: ttl = 0 generated.add_answer_at_time( r.DNSPointer(service_type, const._TYPE_PTR, const._CLASS_IN, ttl, service_name), 0) generated.add_answer_at_time( r.DNSService( service_name, const._TYPE_SRV, const._CLASS_IN | const._CLASS_UNIQUE, ttl, 0, 0, 80, service_server, ), 0, ) generated.add_answer_at_time( r.DNSText(service_name, const._TYPE_TXT, const._CLASS_IN | const._CLASS_UNIQUE, ttl, service_text), 0, ) generated.add_answer_at_time( r.DNSAddress( service_server, const._TYPE_A, const._CLASS_IN | const._CLASS_UNIQUE, ttl, socket.inet_aton(service_address), ), 0, ) return r.DNSIncoming(generated.packets()[0])
def test_massive_probe_packet_split(self): """Test probe with many authorative answers.""" generated = r.DNSOutgoing(const._FLAGS_QR_QUERY | const._FLAGS_AA) questions = [] for _ in range(30): question = r.DNSQuestion(f"_hap._tcp.local.", const._TYPE_PTR, const._CLASS_IN | const._CLASS_UNIQUE) generated.add_question(question) questions.append(question) assert len(generated.questions) == 30 now = current_time_millis() for _ in range(200): authorative_answer = r.DNSPointer( "myservice{i}_tcp._tcp.local.", const._TYPE_PTR, const._CLASS_IN | const._CLASS_UNIQUE, const._DNS_OTHER_TTL, '123.local.', ) generated.add_authorative_answer(authorative_answer) packets = generated.packets() assert len(packets) == 3 assert len(packets[0]) <= const._MAX_MSG_TYPICAL assert len(packets[1]) <= const._MAX_MSG_TYPICAL assert len(packets[2]) <= const._MAX_MSG_TYPICAL parsed1 = r.DNSIncoming(packets[0]) assert parsed1.questions[0].unicast is True assert len(parsed1.questions) == 30 assert parsed1.num_authorities == 88 assert parsed1.flags & const._FLAGS_TC == const._FLAGS_TC parsed2 = r.DNSIncoming(packets[1]) assert len(parsed2.questions) == 0 assert parsed2.num_authorities == 101 assert parsed2.flags & const._FLAGS_TC == const._FLAGS_TC parsed3 = r.DNSIncoming(packets[2]) assert len(parsed3.questions) == 0 assert parsed3.num_authorities == 11 assert parsed3.flags & const._FLAGS_TC == 0
def test_many_questions_with_many_known_answers(self): """Test many questions and known answers get seperated into multiple packets.""" generated = r.DNSOutgoing(const._FLAGS_QR_QUERY) questions = [] for _ in range(30): question = r.DNSQuestion(f"_hap._tcp.local.", const._TYPE_PTR, const._CLASS_IN) generated.add_question(question) questions.append(question) assert len(generated.questions) == 30 now = current_time_millis() for _ in range(200): known_answer = r.DNSPointer( "myservice{i}_tcp._tcp.local.", const._TYPE_PTR, const._CLASS_IN | const._CLASS_UNIQUE, const._DNS_OTHER_TTL, '123.local.', ) generated.add_answer_at_time(known_answer, now) packets = generated.packets() assert len(packets) == 3 assert len(packets[0]) <= const._MAX_MSG_TYPICAL assert len(packets[1]) <= const._MAX_MSG_TYPICAL assert len(packets[2]) <= const._MAX_MSG_TYPICAL parsed1 = r.DNSIncoming(packets[0]) assert len(parsed1.questions) == 30 assert len(parsed1.answers) == 88 assert parsed1.flags & const._FLAGS_TC == const._FLAGS_TC parsed2 = r.DNSIncoming(packets[1]) assert len(parsed2.questions) == 0 assert len(parsed2.answers) == 101 assert parsed2.flags & const._FLAGS_TC == const._FLAGS_TC parsed3 = r.DNSIncoming(packets[2]) assert len(parsed3.questions) == 0 assert len(parsed3.answers) == 11 assert parsed3.flags & const._FLAGS_TC == 0
def test_dns_pointer_repr(self): pointer = r.DNSPointer("irrelevant", r._TYPE_PTR, r._CLASS_IN, r._DNS_TTL, "123") repr(pointer)
def test_dns_pointer_repr(self): pointer = r.DNSPointer('irrelevant', r._TYPE_PTR, r._CLASS_IN, r._DNS_OTHER_TTL, '123') repr(pointer)
def mock_incoming_msg(service_state_change: r.ServiceStateChange) -> r.DNSIncoming: generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE) assert generated.is_response() is True if service_state_change == r.ServiceStateChange.Removed: ttl = 0 else: ttl = 120 generated.add_answer_at_time( r.DNSText( service_name, const._TYPE_TXT, const._CLASS_IN | const._CLASS_UNIQUE, ttl, service_text ), 0, ) generated.add_answer_at_time( r.DNSService( service_name, const._TYPE_SRV, const._CLASS_IN | const._CLASS_UNIQUE, ttl, 0, 0, 80, service_server, ), 0, ) # Send the IPv6 address first since we previously # had a bug where the IPv4 would be missing if the # IPv6 was seen first if enable_ipv6: generated.add_answer_at_time( r.DNSAddress( service_server, const._TYPE_AAAA, const._CLASS_IN | const._CLASS_UNIQUE, ttl, socket.inet_pton(socket.AF_INET6, service_v6_address), ), 0, ) generated.add_answer_at_time( r.DNSAddress( service_server, const._TYPE_AAAA, const._CLASS_IN | const._CLASS_UNIQUE, ttl, socket.inet_pton(socket.AF_INET6, service_v6_second_address), ), 0, ) generated.add_answer_at_time( r.DNSAddress( service_server, const._TYPE_A, const._CLASS_IN | const._CLASS_UNIQUE, ttl, socket.inet_aton(service_address), ), 0, ) generated.add_answer_at_time( r.DNSPointer(service_type, const._TYPE_PTR, const._CLASS_IN, ttl, service_name), 0 ) return r.DNSIncoming(generated.packets()[0])
def test_known_answer_supression_service_type_enumeration_query(): zc = Zeroconf(interfaces=['127.0.0.1']) type_ = "_knownservice._tcp.local." name = "knownname" registration_name = "%s.%s" % (name, type_) desc = {'path': '/~paulsm/'} server_name = "ash-2.local." info = ServiceInfo(type_, registration_name, 80, 0, 0, desc, server_name, addresses=[socket.inet_aton("10.0.1.2")]) zc.register_service(info) type_2 = "_knownservice2._tcp.local." name = "knownname" registration_name2 = "%s.%s" % (name, type_2) desc = {'path': '/~paulsm/'} server_name2 = "ash-3.local." info = ServiceInfo(type_2, registration_name2, 80, 0, 0, desc, server_name2, addresses=[socket.inet_aton("10.0.1.2")]) zc.register_service(info) now = current_time_millis() _clear_cache(zc) # Test PTR supression generated = r.DNSOutgoing(const._FLAGS_QR_QUERY) question = r.DNSQuestion(const._SERVICE_TYPE_ENUMERATION_NAME, const._TYPE_PTR, const._CLASS_IN) generated.add_question(question) packets = generated.packets() unicast_out, multicast_out = zc.query_handler.response( r.DNSIncoming(packets[0]), "1.2.3.4", const._MDNS_PORT) assert unicast_out is None assert multicast_out is not None and multicast_out.answers generated = r.DNSOutgoing(const._FLAGS_QR_QUERY) question = r.DNSQuestion(const._SERVICE_TYPE_ENUMERATION_NAME, const._TYPE_PTR, const._CLASS_IN) generated.add_question(question) generated.add_answer_at_time( r.DNSPointer( const._SERVICE_TYPE_ENUMERATION_NAME, const._TYPE_PTR, const._CLASS_IN, const._DNS_OTHER_TTL, type_, ), now, ) generated.add_answer_at_time( r.DNSPointer( const._SERVICE_TYPE_ENUMERATION_NAME, const._TYPE_PTR, const._CLASS_IN, const._DNS_OTHER_TTL, type_2, ), now, ) packets = generated.packets() unicast_out, multicast_out = zc.query_handler.response( r.DNSIncoming(packets[0]), "1.2.3.4", const._MDNS_PORT) assert unicast_out is None assert not multicast_out or not multicast_out.answers # unregister zc.unregister_service(info) zc.close()