1 /* 2 * Copyright (c) 2017, The Linux Foundation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided 12 * with the distribution. 13 * * Neither the name of The Linux Foundation nor the names of its 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 /* External Includes */ 30 #include <arpa/inet.h> 31 #include <netinet/in.h> 32 #include <netinet/ip.h> 33 #include <string.h> 34 #include <sys/socket.h> 35 #include <sys/types.h> 36 #include <vector> 37 38 /* Internal Includes */ 39 #include "IOffloadManager.h" 40 #include "PrefixParser.h" 41 42 /* Avoiding namespace pollution */ 43 using IP_FAM = ::IOffloadManager::IP_FAM; 44 using Prefix = ::IOffloadManager::Prefix; 45 46 using ::std::string; 47 using ::std::vector; 48 49 50 /* ------------------------------ PUBLIC ------------------------------------ */ 51 PrefixParser::PrefixParser() { 52 mLastErr = "No Err"; 53 } /* PrefixParser */ 54 55 bool PrefixParser::add(vector<string> in) { 56 return add(in, IP_FAM::INVALID); 57 } /* add */ 58 59 bool PrefixParser::add(string in) { 60 return add(in, IP_FAM::INVALID); 61 } /* add */ 62 63 bool PrefixParser::addV4(string in) { 64 return add(in, IP_FAM::V4); 65 } /* addV4 */ 66 67 bool PrefixParser::addV4(vector<string> in) { 68 return add(in, IP_FAM::V4); 69 } /* addV4 */ 70 71 bool PrefixParser::addV6(string in) { 72 return add(in, IP_FAM::V6); 73 } /* addV6 */ 74 75 bool PrefixParser::addV6(vector<string> in) { 76 for (size_t i = 0; i < in.size(); i++) { 77 if (!addV6(in[i])) 78 return false; 79 } 80 return true; 81 } /* addV6 */ 82 83 int PrefixParser::size() { 84 return mPrefixes.size(); 85 } /* size */ 86 87 bool PrefixParser::allAreFullyQualified() { 88 for (size_t i = 0; i < mPrefixes.size(); i++) { 89 if (mPrefixes[i].fam == IP_FAM::V4) { 90 uint32_t masked = mPrefixes[i].v4Addr & mPrefixes[i].v4Mask; 91 if (masked != mPrefixes[i].v4Addr) 92 return false; 93 } else { 94 uint32_t masked[4]; 95 masked[0] = mPrefixes[i].v6Addr[0] & mPrefixes[i].v6Mask[0]; 96 masked[1] = mPrefixes[i].v6Addr[1] & mPrefixes[i].v6Mask[1]; 97 masked[2] = mPrefixes[i].v6Addr[2] & mPrefixes[i].v6Mask[2]; 98 masked[3] = mPrefixes[i].v6Addr[3] & mPrefixes[i].v6Mask[3]; 99 for (int j = 0; j < 4; j++) { 100 if (masked[j] != mPrefixes[i].v6Addr[j]) 101 return false; 102 } 103 } 104 } 105 return true; 106 } /* allAreFullyQualified */ 107 108 Prefix PrefixParser::getFirstPrefix() { 109 if (size() >= 1) 110 return mPrefixes[0]; 111 return makeBlankPrefix(IP_FAM::INVALID); 112 } /* getFirstPrefix */ 113 114 string PrefixParser::getLastErrAsStr() { 115 return mLastErr; 116 } /* getLastErrAsStr */ 117 118 119 /* ------------------------------ PRIVATE ----------------------------------- */ 120 bool PrefixParser::add(vector<string> in, IP_FAM famHint) { 121 if (in.size() == 0) 122 return false; 123 124 for (size_t i = 0; i < in.size(); i++) { 125 if (!add(in[i], famHint)) 126 return false; 127 } 128 return true; 129 } /* add */ 130 131 bool PrefixParser::add(string in, IP_FAM famHint) { 132 if (in.length() == 0) { 133 mLastErr = "Failed to parse string, length = 0..."; 134 return false; 135 } 136 137 if (famHint == IP_FAM::INVALID) 138 famHint = guessIPFamily(in); 139 140 string subnet; 141 string addr; 142 143 if (!splitIntoAddrAndMask(in, addr, subnet)) { 144 mLastErr = "Failed to split into Address and Mask(" + in + ")"; 145 return false; 146 } 147 148 int mask = parseSubnetMask(subnet, famHint); 149 if (!isMaskValid(mask, famHint)) { 150 mLastErr = "Invalid mask"; 151 return false; 152 } 153 154 Prefix pre = makeBlankPrefix(famHint); 155 156 if (famHint == IP_FAM::V4) { 157 if (!parseV4Addr(addr, pre)) { 158 mLastErr = "Failed to parse V4 Address(" + addr + ")"; 159 return false; 160 } 161 } else if (!parseV6Addr(addr, pre)) { 162 mLastErr = "Failed to parse V6 Address(" + addr + ")"; 163 return false; 164 } 165 166 if (famHint == IP_FAM::V4 && !populateV4Mask(mask, pre)) { 167 mLastErr = "Failed to populate IPv4 Mask(" + std::to_string(mask) 168 + ", " + addr + ")"; 169 return false; 170 } else if (!populateV6Mask(mask, pre)) { 171 mLastErr = "Failed to populate IPv6 Mask(" + std::to_string(mask) 172 + ", " + addr + ")"; 173 return false; 174 } 175 176 mPrefixes.push_back(pre); 177 return true; 178 } /* add */ 179 180 /* Assumption (based on man inet_pton) 181 * 182 * X represents a hex character 183 * d represents a base 10 digit 184 * / represents the start of the subnet mask 185 * (assume that it can be left off of all below combinations) 186 * 187 * IPv4 Addresses always look like the following: 188 * ddd.ddd.ddd.ddd/dd 189 * 190 * IPv6 Addresses can look a few different ways: 191 * x:x:x:x:x:x:x:x/ddd 192 * x::x/ddd 193 * x:x:x:x:x:x:d.d.d.d/ddd 194 * 195 * Therefore, if a presentation of an IP Address contains a colon, then it 196 * may not be a valid IPv6, but, it is definitely not valid IPv4. If a 197 * presentation of an IP Address does not contain a colon, then it may not be 198 * a valid IPv4, but, it is definitely not IPv6. 199 */ 200 IP_FAM PrefixParser::guessIPFamily(string in) { 201 size_t found = in.find(":"); 202 if (found != string::npos) 203 return IP_FAM::V6; 204 return IP_FAM::V4; 205 } /* guessIPFamily */ 206 207 bool PrefixParser::splitIntoAddrAndMask(string in, string &addr, string &mask) { 208 size_t pos = in.find("/"); 209 210 if (pos != string::npos && pos >= 1) { 211 /* addr is now everything up until the first / */ 212 addr = in.substr(0, pos); 213 } else if (pos == string::npos) { 214 /* There is no /, so the entire input is an address */ 215 addr = in; 216 } else { 217 /* There was nothing before the /, not recoverable */ 218 return false; 219 } 220 221 if (pos != string::npos && pos < in.size()) { 222 /* There is a / and it is not the last character. Everything after / 223 * must be the subnet. 224 */ 225 mask = in.substr(pos + 1); 226 } else if (pos != string::npos && pos == in.size()) { 227 /* There is a /, but it is the last character. This is garbage, but, 228 * we may still be able to interpret the address so we will throw it 229 * out. 230 */ 231 mask = ""; 232 } else if (pos == string::npos) { 233 /* There is no /, therefore, there is no subnet */ 234 mask = ""; 235 } else { 236 /* This really shouldn't be possible because it would imply that find 237 * returned a position larger than the size of the input. Just 238 * preserving sanity that mask is always initialized. 239 */ 240 mask = ""; 241 } 242 243 return true; 244 } /* splitIntoAddrAndMask */ 245 246 int PrefixParser::parseSubnetMask(string in, IP_FAM famHint) { 247 if (in.empty()) 248 /* Treat no subnet mask as fully qualified */ 249 return (famHint == IP_FAM::V6) ? 128 : 32; 250 return atoi(in.c_str()); 251 } /* parseSubnetMask */ 252 253 bool PrefixParser::parseV4Addr(string in, Prefix &out) { 254 struct sockaddr_in sa; 255 256 int ret = inet_pton(AF_INET, in.c_str(), &(sa.sin_addr)); 257 258 if (ret < 0) { 259 /* errno would be valid */ 260 return false; 261 } else if (ret == 0) { 262 /* input was not a valid IP address */ 263 return false; 264 } 265 266 /* Address in network byte order */ 267 out.v4Addr = htonl(sa.sin_addr.s_addr); 268 return true; 269 } /* parseV4Addr */ 270 271 bool PrefixParser::parseV6Addr(string in, Prefix &out) { 272 struct sockaddr_in6 sa; 273 274 int ret = inet_pton(AF_INET6, in.c_str(), &(sa.sin6_addr)); 275 276 if (ret < 0) { 277 /* errno would be valid */ 278 return false; 279 } else if (ret == 0) { 280 /* input was not a valid IP address */ 281 return false; 282 } 283 284 /* Translate unsigned chars to unsigned ints to match IPA 285 * 286 * TODO there must be a better way to do this beyond bit fiddling 287 * Maybe a Union since we've already made the assumption that the data 288 * structures match? 289 */ 290 out.v6Addr[0] = (sa.sin6_addr.s6_addr[0] << 24) | 291 (sa.sin6_addr.s6_addr[1] << 16) | 292 (sa.sin6_addr.s6_addr[2] << 8) | 293 (sa.sin6_addr.s6_addr[3]); 294 out.v6Addr[1] = (sa.sin6_addr.s6_addr[4] << 24) | 295 (sa.sin6_addr.s6_addr[5] << 16) | 296 (sa.sin6_addr.s6_addr[6] << 8) | 297 (sa.sin6_addr.s6_addr[7]); 298 out.v6Addr[2] = (sa.sin6_addr.s6_addr[8] << 24) | 299 (sa.sin6_addr.s6_addr[9] << 16) | 300 (sa.sin6_addr.s6_addr[10] << 8) | 301 (sa.sin6_addr.s6_addr[11]); 302 out.v6Addr[3] = (sa.sin6_addr.s6_addr[12] << 24) | 303 (sa.sin6_addr.s6_addr[13] << 16) | 304 (sa.sin6_addr.s6_addr[14] << 8) | 305 (sa.sin6_addr.s6_addr[15]); 306 return true; 307 } /* parseV6Addr */ 308 309 bool PrefixParser::populateV4Mask(int mask, Prefix &out) { 310 if (mask < 0 || mask > 32) 311 return false; 312 out.v4Mask = createMask(mask); 313 return true; 314 } /* populateV4Mask */ 315 316 bool PrefixParser::populateV6Mask(int mask, Prefix &out) { 317 if (mask < 0 || mask > 128) 318 return false; 319 320 for (int i = 0; i < 4; i++) { 321 out.v6Mask[i] = createMask(mask); 322 mask = (mask > 32) ? mask - 32 : 0; 323 } 324 325 return true; 326 } /* populateV6Mask */ 327 328 uint32_t PrefixParser::createMask(int mask) { 329 uint32_t ret = 0; 330 331 if (mask >= 32) { 332 ret = ~ret; 333 return ret; 334 } 335 336 for (int i = 0; i < 32; i++) { 337 if (i < mask) 338 ret = (ret << 1) | 1; 339 else 340 ret = (ret << 1); 341 } 342 343 return ret; 344 } /* createMask */ 345 346 Prefix PrefixParser::makeBlankPrefix(IP_FAM famHint) { 347 Prefix ret; 348 349 ret.fam = famHint; 350 351 ret.v4Addr = 0; 352 ret.v4Mask = 0; 353 354 ret.v6Addr[0] = 0; 355 ret.v6Addr[1] = 0; 356 ret.v6Addr[2] = 0; 357 ret.v6Addr[3] = 0; 358 359 ret.v6Mask[0] = 0; 360 ret.v6Mask[1] = 0; 361 ret.v6Mask[2] = 0; 362 ret.v6Mask[3] = 0; 363 364 return ret; 365 } /* makeBlankPrefix */ 366 367 bool PrefixParser::isMaskValid(int mask, IP_FAM fam) { 368 if (mask < 0) { 369 mLastErr = "Failed parse subnet mask(" + std::to_string(mask) + ")"; 370 return false; 371 } else if (mask == 0) { 372 mLastErr = "Subnet mask cannot be 0(" + std::to_string(mask) + ")"; 373 return false; 374 } else if (fam == IP_FAM::V4 && mask > 32) { 375 mLastErr = "Interpreted address as V4 but mask was too large(" 376 + std::to_string(mask) + ")"; 377 return false; 378 } else if (fam == IP_FAM::V6 && mask > 128) { 379 mLastErr = "Interpreted address as V6 but mask was too large(" 380 + std::to_string(mask) + ")"; 381 return false; 382 } 383 384 return true; 385 } /* isMaskValid */ 386