RecordInfo findRecord(ByteRange searchRange, ByteRange wholeRange, uint32_t fileId) { static const uint32_t magic = Header::kMagic; static const ByteRange magicRange(reinterpret_cast<const uint8_t*>(&magic), sizeof(magic)); DCHECK_GE(searchRange.begin(), wholeRange.begin()); DCHECK_LE(searchRange.end(), wholeRange.end()); const uint8_t* start = searchRange.begin(); const uint8_t* end = std::min(searchRange.end(), wholeRange.end() - sizeof(Header)); // end-1: the last place where a Header could start while (start < end) { auto p = ByteRange(start, end + sizeof(magic)).find(magicRange); if (p == ByteRange::npos) { break; } start += p; auto r = validateRecord(ByteRange(start, wholeRange.end()), fileId); if (!r.record.empty()) { return r; } // No repeated prefix in magic, so we can do better than start++ start += sizeof(magic); } return {0, {}}; }
void Normalize::normalizeQueueGetConfigReplyV1() { Header *hdr = header(); size_t length = hdr->length(); if (length < sizeof(QueueGetConfigReply)) { markInputInvalid("QueueGetConfigReply is too short"); return; } if (hdr->version() == OFP_VERSION_1) { // Convert port number to 32-bits -- only for OpenFlow 1.0. UInt8 *ptr = buf_.mutableData() + sizeof(Header); PortNumber port = PortNumber::fromV1(*Big16_cast(ptr)); std::memcpy(ptr, &port, sizeof(port)); } // Convert QueueV1 to Queue. ByteRange data = SafeByteRange(buf_.mutableData(), buf_.size(), sizeof(QueueGetConfigReply)); deprecated::QueueV1Range queues{data}; Validation context; if (!queues.validateInput(&context)) { markInputInvalid("QueueGetConfigReply has invalid queues"); return; } QueueList newQueues; for (auto &queue : queues) { QueueBuilder newQueue{queue}; newQueues.add(newQueue); } // When converting to the regular `Queue` structure, we may exceed the max // message size of 65535. if (newQueues.size() > 65535 - sizeof(QueueGetConfigReply)) { markInputTooBig("QueueGetConfigReply is too big"); return; } buf_.replace(data.begin(), data.end(), newQueues.data(), newQueues.size()); }
void Normalize::normalizeQueueGetConfigReplyV2() { // Pad all queues to a multiple of 8. You can only get a queue whose size is // not a multiple of 8 if it contains an experimenter property with an // unusual length. Header *hdr = header(); size_t length = hdr->length(); if (length < sizeof(QueueGetConfigReply)) return; ByteRange data = SafeByteRange(buf_.mutableData(), buf_.size(), sizeof(QueueGetConfigReply)); size_t remaining = data.size(); const UInt8 *ptr = data.data(); ByteList newBuf; while (remaining > 16) { // Read 16-bit queue length from a potentially mis-aligned position. UInt16 queueLen = Big16_unaligned(ptr + 8); if (queueLen > remaining || queueLen < 16) return; // Copy queue header. newBuf.add(ptr, 16); // Iterate over properties and pad out the properties whose sizes are not // multiples of 8. const UInt8 *prop = ptr + 16; size_t propLeft = queueLen - 16; while (propLeft > 4) { UInt16 propSize = Big16_unaligned(prop + 2); if (propSize > propLeft || propSize < 4) return; newBuf.add(prop, propSize); if ((propSize % 8) != 0) { newBuf.addZeros(PadLength(propSize) - propSize); } prop += propSize; propLeft -= propSize; } if (propLeft != 0) { log_debug("normalizeQueueGetConfigReplyV2: propLeft != 0"); return; } ptr += queueLen; assert(prop == ptr); remaining -= queueLen; } if (remaining != 0) { log_debug("normalizeQueueGetConfigReplyV2: remaining != 0"); return; } // When padding the regular `Queue` structure, we may exceed the max // message size of 65535. if (newBuf.size() > 65535 - sizeof(QueueGetConfigReply)) { markInputTooBig("QueueGetConfigReply is too big"); return; } buf_.replace(data.begin(), data.end(), newBuf.data(), newBuf.size()); }
bool are_identical(const ByteRange& lhs, const ByteRange& rhs) { return lhs.begin() == rhs.begin() && lhs.end() == rhs.end(); }