in packages/multicast_dns/lib/src/packet.dart [214:382]
List<ResourceRecord>? decodeMDnsResponse(List<int> packet) {
final int length = packet.length;
if (length < _kHeaderSize) {
return null;
}
final Uint8List data =
packet is Uint8List ? packet : Uint8List.fromList(packet);
final ByteData packetBytes = ByteData.view(data.buffer);
final int answerCount = packetBytes.getUint16(_kAncountOffset);
final int authorityCount = packetBytes.getUint16(_kNscountOffset);
final int additionalCount = packetBytes.getUint16(_kArcountOffset);
final int remainingCount = answerCount + authorityCount + additionalCount;
if (remainingCount == 0) {
return null;
}
final int questionCount = packetBytes.getUint16(_kQdcountOffset);
int offset = _kHeaderSize;
void checkLength(int required) {
if (length < required) {
throw MDnsDecodeException(required);
}
}
ResourceRecord? readResourceRecord() {
// First read the FQDN.
final _FQDNReadResult result = _readFQDN(data, packetBytes, offset, length);
final String fqdn = result.fqdn;
offset += result.bytesRead;
checkLength(offset + 2);
final int type = packetBytes.getUint16(offset);
offset += 2;
// The first bit of the rrclass field is set to indicate that the answer is
// unique and the querier should flush the cached answer for this name
// (RFC 6762, Sec. 10.2). We ignore it for now since we don't cache answers.
checkLength(offset + 2);
final int resourceRecordClass = packetBytes.getUint16(offset) & 0x7fff;
if (resourceRecordClass != ResourceRecordClass.internet) {
// We do not support other classes.
return null;
}
offset += 2;
checkLength(offset + 4);
final int ttl = packetBytes.getInt32(offset);
offset += 4;
checkLength(offset + 2);
final int readDataLength = packetBytes.getUint16(offset);
offset += 2;
final int validUntil = DateTime.now().millisecondsSinceEpoch + ttl * 1000;
switch (type) {
case ResourceRecordType.addressIPv4:
checkLength(offset + readDataLength);
final StringBuffer addr = StringBuffer();
final int stop = offset + readDataLength;
addr.write(packetBytes.getUint8(offset));
offset++;
for (; offset < stop; offset++) {
addr.write('.');
addr.write(packetBytes.getUint8(offset));
}
return IPAddressResourceRecord(fqdn, validUntil,
address: InternetAddress(addr.toString()));
case ResourceRecordType.addressIPv6:
checkLength(offset + readDataLength);
final StringBuffer addr = StringBuffer();
final int stop = offset + readDataLength;
addr.write(packetBytes.getUint16(offset).toRadixString(16));
offset += 2;
for (; offset < stop; offset += 2) {
addr.write(':');
addr.write(packetBytes.getUint16(offset).toRadixString(16));
}
return IPAddressResourceRecord(
fqdn,
validUntil,
address: InternetAddress(addr.toString()),
);
case ResourceRecordType.service:
checkLength(offset + 2);
final int priority = packetBytes.getUint16(offset);
offset += 2;
checkLength(offset + 2);
final int weight = packetBytes.getUint16(offset);
offset += 2;
checkLength(offset + 2);
final int port = packetBytes.getUint16(offset);
offset += 2;
final _FQDNReadResult result =
_readFQDN(data, packetBytes, offset, length);
offset += result.bytesRead;
return SrvResourceRecord(
fqdn,
validUntil,
target: result.fqdn,
port: port,
priority: priority,
weight: weight,
);
case ResourceRecordType.serverPointer:
checkLength(offset + readDataLength);
final _FQDNReadResult result =
_readFQDN(data, packetBytes, offset, length);
offset += readDataLength;
return PtrResourceRecord(
fqdn,
validUntil,
domainName: result.fqdn,
);
case ResourceRecordType.text:
checkLength(offset + readDataLength);
// The first byte of the buffer is the length of the first string of
// the TXT record. Further length-prefixed strings may follow. We
// concatenate them with newlines.
final StringBuffer strings = StringBuffer();
int index = 0;
while (index < readDataLength) {
final int txtLength = data[offset + index];
index++;
if (txtLength == 0) {
continue;
}
final String text = utf8.decode(
Uint8List.view(data.buffer, offset + index, txtLength),
allowMalformed: true,
);
strings.writeln(text);
index += txtLength;
}
offset += readDataLength;
return TxtResourceRecord(fqdn, validUntil, text: strings.toString());
default:
checkLength(offset + readDataLength);
offset += readDataLength;
return null;
}
}
// This list can't be fixed length right now because we might get
// resource record types we don't support, and consumers expect this list
// to not have null entries.
final List<ResourceRecord> result = <ResourceRecord>[];
try {
for (int i = 0; i < questionCount; i++) {
final _FQDNReadResult result =
_readFQDN(data, packetBytes, offset, length);
offset += result.bytesRead;
checkLength(offset + 4);
offset += 4;
}
for (int i = 0; i < remainingCount; i++) {
final ResourceRecord? record = readResourceRecord();
if (record != null) {
result.add(record);
}
}
} on MDnsDecodeException {
// If decoding fails return null.
return null;
}
return result;
}