/* * Copyright (c) 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* External Includes */ #include #include #include #include #include #include #include /* Internal Includes */ #include "IOffloadManager.h" #include "PrefixParser.h" /* Avoiding namespace pollution */ using IP_FAM = ::IOffloadManager::IP_FAM; using Prefix = ::IOffloadManager::Prefix; using ::std::string; using ::std::vector; /* ------------------------------ PUBLIC ------------------------------------ */ PrefixParser::PrefixParser() { mLastErr = "No Err"; } /* PrefixParser */ bool PrefixParser::add(vector in) { return add(in, IP_FAM::INVALID); } /* add */ bool PrefixParser::add(string in) { return add(in, IP_FAM::INVALID); } /* add */ bool PrefixParser::addV4(string in) { return add(in, IP_FAM::V4); } /* addV4 */ bool PrefixParser::addV4(vector in) { return add(in, IP_FAM::V4); } /* addV4 */ bool PrefixParser::addV6(string in) { return add(in, IP_FAM::V6); } /* addV6 */ bool PrefixParser::addV6(vector in) { for (size_t i = 0; i < in.size(); i++) { if (!addV6(in[i])) return false; } return true; } /* addV6 */ int PrefixParser::size() { return mPrefixes.size(); } /* size */ bool PrefixParser::allAreFullyQualified() { for (size_t i = 0; i < mPrefixes.size(); i++) { if (mPrefixes[i].fam == IP_FAM::V4) { uint32_t masked = mPrefixes[i].v4Addr & mPrefixes[i].v4Mask; if (masked != mPrefixes[i].v4Addr) return false; } else { uint32_t masked[4]; masked[0] = mPrefixes[i].v6Addr[0] & mPrefixes[i].v6Mask[0]; masked[1] = mPrefixes[i].v6Addr[1] & mPrefixes[i].v6Mask[1]; masked[2] = mPrefixes[i].v6Addr[2] & mPrefixes[i].v6Mask[2]; masked[3] = mPrefixes[i].v6Addr[3] & mPrefixes[i].v6Mask[3]; for (int j = 0; j < 4; j++) { if (masked[j] != mPrefixes[i].v6Addr[j]) return false; } } } return true; } /* allAreFullyQualified */ Prefix PrefixParser::getFirstPrefix() { if (size() >= 1) return mPrefixes[0]; return makeBlankPrefix(IP_FAM::INVALID); } /* getFirstPrefix */ string PrefixParser::getLastErrAsStr() { return mLastErr; } /* getLastErrAsStr */ /* ------------------------------ PRIVATE ----------------------------------- */ bool PrefixParser::add(vector in, IP_FAM famHint) { if (in.size() == 0) return false; for (size_t i = 0; i < in.size(); i++) { if (!add(in[i], famHint)) return false; } return true; } /* add */ bool PrefixParser::add(string in, IP_FAM famHint) { if (in.length() == 0) { mLastErr = "Failed to parse string, length = 0..."; return false; } if (famHint == IP_FAM::INVALID) famHint = guessIPFamily(in); string subnet; string addr; if (!splitIntoAddrAndMask(in, addr, subnet)) { mLastErr = "Failed to split into Address and Mask(" + in + ")"; return false; } int mask = parseSubnetMask(subnet, famHint); if (!isMaskValid(mask, famHint)) { mLastErr = "Invalid mask"; return false; } Prefix pre = makeBlankPrefix(famHint); if (famHint == IP_FAM::V4) { if (!parseV4Addr(addr, pre)) { mLastErr = "Failed to parse V4 Address(" + addr + ")"; return false; } } else if (!parseV6Addr(addr, pre)) { mLastErr = "Failed to parse V6 Address(" + addr + ")"; return false; } if (famHint == IP_FAM::V4 && !populateV4Mask(mask, pre)) { mLastErr = "Failed to populate IPv4 Mask(" + std::to_string(mask) + ", " + addr + ")"; return false; } else if (!populateV6Mask(mask, pre)) { mLastErr = "Failed to populate IPv6 Mask(" + std::to_string(mask) + ", " + addr + ")"; return false; } mPrefixes.push_back(pre); return true; } /* add */ /* Assumption (based on man inet_pton) * * X represents a hex character * d represents a base 10 digit * / represents the start of the subnet mask * (assume that it can be left off of all below combinations) * * IPv4 Addresses always look like the following: * ddd.ddd.ddd.ddd/dd * * IPv6 Addresses can look a few different ways: * x:x:x:x:x:x:x:x/ddd * x::x/ddd * x:x:x:x:x:x:d.d.d.d/ddd * * Therefore, if a presentation of an IP Address contains a colon, then it * may not be a valid IPv6, but, it is definitely not valid IPv4. If a * presentation of an IP Address does not contain a colon, then it may not be * a valid IPv4, but, it is definitely not IPv6. */ IP_FAM PrefixParser::guessIPFamily(string in) { size_t found = in.find(":"); if (found != string::npos) return IP_FAM::V6; return IP_FAM::V4; } /* guessIPFamily */ bool PrefixParser::splitIntoAddrAndMask(string in, string &addr, string &mask) { size_t pos = in.find("/"); if (pos != string::npos && pos >= 1) { /* addr is now everything up until the first / */ addr = in.substr(0, pos); } else if (pos == string::npos) { /* There is no /, so the entire input is an address */ addr = in; } else { /* There was nothing before the /, not recoverable */ return false; } if (pos != string::npos && pos < in.size()) { /* There is a / and it is not the last character. Everything after / * must be the subnet. */ mask = in.substr(pos + 1); } else if (pos != string::npos && pos == in.size()) { /* There is a /, but it is the last character. This is garbage, but, * we may still be able to interpret the address so we will throw it * out. */ mask = ""; } else if (pos == string::npos) { /* There is no /, therefore, there is no subnet */ mask = ""; } else { /* This really shouldn't be possible because it would imply that find * returned a position larger than the size of the input. Just * preserving sanity that mask is always initialized. */ mask = ""; } return true; } /* splitIntoAddrAndMask */ int PrefixParser::parseSubnetMask(string in, IP_FAM famHint) { if (in.empty()) /* Treat no subnet mask as fully qualified */ return (famHint == IP_FAM::V6) ? 128 : 32; return atoi(in.c_str()); } /* parseSubnetMask */ bool PrefixParser::parseV4Addr(string in, Prefix &out) { struct sockaddr_in sa; int ret = inet_pton(AF_INET, in.c_str(), &(sa.sin_addr)); if (ret < 0) { /* errno would be valid */ return false; } else if (ret == 0) { /* input was not a valid IP address */ return false; } /* Address in network byte order */ out.v4Addr = htonl(sa.sin_addr.s_addr); return true; } /* parseV4Addr */ bool PrefixParser::parseV6Addr(string in, Prefix &out) { struct sockaddr_in6 sa; int ret = inet_pton(AF_INET6, in.c_str(), &(sa.sin6_addr)); if (ret < 0) { /* errno would be valid */ return false; } else if (ret == 0) { /* input was not a valid IP address */ return false; } /* Translate unsigned chars to unsigned ints to match IPA * * TODO there must be a better way to do this beyond bit fiddling * Maybe a Union since we've already made the assumption that the data * structures match? */ out.v6Addr[0] = (sa.sin6_addr.s6_addr[0] << 24) | (sa.sin6_addr.s6_addr[1] << 16) | (sa.sin6_addr.s6_addr[2] << 8) | (sa.sin6_addr.s6_addr[3]); out.v6Addr[1] = (sa.sin6_addr.s6_addr[4] << 24) | (sa.sin6_addr.s6_addr[5] << 16) | (sa.sin6_addr.s6_addr[6] << 8) | (sa.sin6_addr.s6_addr[7]); out.v6Addr[2] = (sa.sin6_addr.s6_addr[8] << 24) | (sa.sin6_addr.s6_addr[9] << 16) | (sa.sin6_addr.s6_addr[10] << 8) | (sa.sin6_addr.s6_addr[11]); out.v6Addr[3] = (sa.sin6_addr.s6_addr[12] << 24) | (sa.sin6_addr.s6_addr[13] << 16) | (sa.sin6_addr.s6_addr[14] << 8) | (sa.sin6_addr.s6_addr[15]); return true; } /* parseV6Addr */ bool PrefixParser::populateV4Mask(int mask, Prefix &out) { if (mask < 0 || mask > 32) return false; out.v4Mask = createMask(mask); return true; } /* populateV4Mask */ bool PrefixParser::populateV6Mask(int mask, Prefix &out) { if (mask < 0 || mask > 128) return false; for (int i = 0; i < 4; i++) { out.v6Mask[i] = createMask(mask); mask = (mask > 32) ? mask - 32 : 0; } return true; } /* populateV6Mask */ uint32_t PrefixParser::createMask(int mask) { uint32_t ret = 0; if (mask >= 32) { ret = ~ret; return ret; } for (int i = 0; i < 32; i++) { if (i < mask) ret = (ret << 1) | 1; else ret = (ret << 1); } return ret; } /* createMask */ Prefix PrefixParser::makeBlankPrefix(IP_FAM famHint) { Prefix ret; ret.fam = famHint; ret.v4Addr = 0; ret.v4Mask = 0; ret.v6Addr[0] = 0; ret.v6Addr[1] = 0; ret.v6Addr[2] = 0; ret.v6Addr[3] = 0; ret.v6Mask[0] = 0; ret.v6Mask[1] = 0; ret.v6Mask[2] = 0; ret.v6Mask[3] = 0; return ret; } /* makeBlankPrefix */ bool PrefixParser::isMaskValid(int mask, IP_FAM fam) { if (mask < 0) { mLastErr = "Failed parse subnet mask(" + std::to_string(mask) + ")"; return false; } else if (mask == 0) { mLastErr = "Subnet mask cannot be 0(" + std::to_string(mask) + ")"; return false; } else if (fam == IP_FAM::V4 && mask > 32) { mLastErr = "Interpreted address as V4 but mask was too large(" + std::to_string(mask) + ")"; return false; } else if (fam == IP_FAM::V6 && mask > 128) { mLastErr = "Interpreted address as V6 but mask was too large(" + std::to_string(mask) + ")"; return false; } return true; } /* isMaskValid */