Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : #include <assert.h> 18 : #include <strings.h> 19 : 20 : #include "QName.h" 21 : 22 : namespace mdns { 23 : namespace Minimal { 24 : 25 60405 : bool SerializedQNameIterator::Next() 26 : { 27 60405 : return mIsValid && Next(true); 28 : } 29 : 30 61909 : bool SerializedQNameIterator::Next(bool followIndirectPointers) 31 : { 32 61909 : if (!mIsValid) 33 : { 34 0 : return false; 35 : } 36 : 37 : while (true) 38 : { 39 72606 : assert(mValidData.Contains(mCurrentPosition)); 40 : 41 72606 : const uint8_t length = *mCurrentPosition; 42 72606 : if (*mCurrentPosition == 0) 43 : { 44 : // Done with all items 45 12229 : return false; 46 : } 47 : 48 60377 : if ((length & kPtrMask) == kPtrMask) 49 : { 50 11307 : if (!followIndirectPointers) 51 : { 52 : // Stop at first indirect pointer 53 607 : return false; 54 : } 55 : 56 : // PTR contains 2 bytes 57 10700 : if (!mValidData.Contains(mCurrentPosition + 1)) 58 : { 59 2 : mIsValid = false; 60 2 : return false; 61 : } 62 : 63 10698 : size_t offset = static_cast<size_t>(((*mCurrentPosition & 0x3F) << 8) | *(mCurrentPosition + 1)); 64 10698 : if (offset > mLookBehindMax) 65 : { 66 : // Potential infinite recursion. 67 0 : mIsValid = false; 68 0 : return false; 69 : } 70 10698 : if (offset > mValidData.Size()) 71 : { 72 : // offset too large 73 0 : mIsValid = false; 74 0 : return false; 75 : } 76 : 77 : // Look behind has to keep going backwards, otherwise we may 78 : // get into an infinite list 79 10698 : if (offset >= static_cast<size_t>(mCurrentPosition - mValidData.Start())) 80 : { 81 1 : mIsValid = false; 82 1 : return false; 83 : } 84 : 85 10697 : mLookBehindMax = offset; 86 10697 : mCurrentPosition = mValidData.Start() + offset; 87 : } 88 : else 89 : { 90 : // This branch handles non-pointer data. This will be string of size [length]. 91 49070 : if (length > kMaxValueSize) 92 : { 93 : // value is too large (larger than RFC limit) 94 3 : mIsValid = false; 95 3 : return false; 96 : } 97 : 98 49067 : if (!mValidData.Contains(mCurrentPosition + 1 + length)) 99 : { 100 : // string outside valid data 101 7 : mIsValid = false; 102 7 : return false; 103 : } 104 : 105 49060 : memcpy(mValue, mCurrentPosition + 1, length); 106 49060 : mValue[length] = '\0'; 107 49060 : mCurrentPosition = mCurrentPosition + length + 1; 108 49060 : return true; 109 : } 110 10697 : } 111 : } 112 : 113 744 : const uint8_t * SerializedQNameIterator::FindDataEnd() 114 : { 115 1504 : while (Next(false)) 116 : { 117 : // nothing to do, just advance 118 : } 119 : 120 744 : if (!IsValid()) 121 : { 122 0 : return nullptr; 123 : } 124 : 125 : // normal end 126 744 : if (*mCurrentPosition == 0) 127 : { 128 : // mCurrentPosition MUST already be valid 129 137 : return mCurrentPosition + 1; 130 : } 131 : 132 : // ends with a dataptr 133 607 : if ((*mCurrentPosition & kPtrMask) == kPtrMask) 134 : { 135 607 : if (!mValidData.Contains(mCurrentPosition + 1)) 136 : { 137 0 : return nullptr; 138 : } 139 607 : return mCurrentPosition + 2; 140 : } 141 : 142 : // invalid data 143 0 : return nullptr; 144 : } 145 : 146 27252 : bool SerializedQNameIterator::operator==(const FullQName & other) const 147 : { 148 27252 : SerializedQNameIterator self = *this; // allow iteration 149 27252 : size_t idx = 0; 150 : 151 33189 : while ((idx < other.nameCount) && self.Next()) 152 : { 153 26429 : if (strcasecmp(self.Value(), other.names[idx]) != 0) 154 : { 155 20492 : return false; 156 : } 157 5937 : idx++; 158 : } 159 : 160 6760 : return ((idx == other.nameCount) && !self.Next()); 161 : } 162 : 163 146 : bool SerializedQNameIterator::operator==(const SerializedQNameIterator & other) const 164 : { 165 146 : SerializedQNameIterator a = *this; // allow iteration 166 146 : SerializedQNameIterator b = other; 167 : 168 : while (true) 169 : { 170 504 : bool hasA = a.Next(); 171 504 : bool hasB = b.Next(); 172 : 173 504 : if (hasA ^ hasB) 174 : { 175 6 : return false; /// one is longer than the other 176 : } 177 : 178 498 : if (!a.IsValid() || !b.IsValid()) 179 : { 180 0 : return false; // invalid data 181 : } 182 : 183 498 : if (!hasA || !hasB) 184 : { 185 : break; 186 : } 187 : 188 375 : if (strcasecmp(a.Value(), b.Value()) != 0) 189 : { 190 17 : return false; 191 : } 192 358 : } 193 : 194 123 : return a.IsValid() && b.IsValid(); 195 : } 196 : 197 6027 : bool FullQName::operator==(const FullQName & other) const 198 : { 199 6027 : if (nameCount != other.nameCount) 200 : { 201 4641 : return false; 202 : } 203 4338 : for (size_t i = 0; i < nameCount; i++) 204 : { 205 3443 : if (strcasecmp(names[i], other.names[i]) != 0) 206 : { 207 491 : return false; 208 : } 209 : } 210 895 : return true; 211 : } 212 : 213 : } // namespace Minimal 214 : } // namespace mdns