Home | History | Annotate | Download | only in src
      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