| 1461 | } |
| 1462 | |
| 1463 | static void SuppressKnownAnswers(MDNS* mdns, const uint8_t* data, uint32_t size, uint32_t* offset, uint16_t answer_count, dmArray<uint8_t>* should_announce) |
| 1464 | { |
| 1465 | // Implement known-answer suppression for PTR records only. Browsers use |
| 1466 | // the advertised PTR as the cache key for service presence, so skipping |
| 1467 | // duplicate PTRs avoids the noisiest redundant replies while keeping |
| 1468 | // the rest of the record set simple. |
| 1469 | for (uint16_t i = 0; i < answer_count && *offset < size; ++i) |
| 1470 | { |
| 1471 | char name[256]; |
| 1472 | uint16_t type = 0; |
| 1473 | uint16_t klass = 0; |
| 1474 | uint32_t ttl = 0; |
| 1475 | uint16_t rdlength = 0; |
| 1476 | if (!ReadName(data, size, offset, name, sizeof(name)) |
| 1477 | || !ReadU16(data, size, offset, &type) |
| 1478 | || !ReadU16(data, size, offset, &klass) |
| 1479 | || !ReadU32(data, size, offset, &ttl) |
| 1480 | || !ReadU16(data, size, offset, &rdlength)) |
| 1481 | { |
| 1482 | *offset = size; |
| 1483 | return; |
| 1484 | } |
| 1485 | |
| 1486 | if (*offset + rdlength > size) |
| 1487 | { |
| 1488 | *offset = size; |
| 1489 | return; |
| 1490 | } |
| 1491 | |
| 1492 | const uint32_t rdata_offset = *offset; |
| 1493 | *offset += rdlength; |
| 1494 | |
| 1495 | if (type != DNS_TYPE_PTR || ttl == 0 || (klass & ~DNS_CLASS_FLUSH) != DNS_CLASS_IN) |
| 1496 | continue; |
| 1497 | |
| 1498 | uint32_t ptr_offset = rdata_offset; |
| 1499 | char full_service_name[256]; |
| 1500 | if (!ReadName(data, size, &ptr_offset, full_service_name, sizeof(full_service_name))) |
| 1501 | continue; |
| 1502 | |
| 1503 | for (uint32_t service_index = 0; service_index < mdns->m_Services.Size(); ++service_index) |
| 1504 | { |
| 1505 | if (!(*should_announce)[service_index]) |
| 1506 | continue; |
| 1507 | |
| 1508 | const RegisteredService& service = mdns->m_Services[service_index]; |
| 1509 | if (!IsServiceActive(service)) |
| 1510 | continue; |
| 1511 | |
| 1512 | if (NameEquals(name, service.m_ServiceTypeLocal) |
| 1513 | && NameEquals(full_service_name, service.m_FullServiceName) |
| 1514 | && ttl * 2 >= service.m_Ttl) |
| 1515 | { |
| 1516 | // RFC 6762 allows suppressing an answer when the querier's |
| 1517 | // cached TTL is at least half of what we would advertise. |
| 1518 | (*should_announce)[service_index] = 0; |
| 1519 | } |
| 1520 | } |
no test coverage detected