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 ------------------------------------ */
PrefixParser()51 PrefixParser::PrefixParser() {
52     mLastErr = "No Err";
53 } /* PrefixParser */
54 
add(vector<string> in)55 bool PrefixParser::add(vector<string> in) {
56     return add(in, IP_FAM::INVALID);
57 } /* add */
58 
add(string in)59 bool PrefixParser::add(string in) {
60     return add(in, IP_FAM::INVALID);
61 } /* add */
62 
addV4(string in)63 bool PrefixParser::addV4(string in) {
64     return add(in, IP_FAM::V4);
65 } /* addV4 */
66 
addV4(vector<string> in)67 bool PrefixParser::addV4(vector<string> in) {
68     return add(in, IP_FAM::V4);
69 } /* addV4 */
70 
addV6(string in)71 bool PrefixParser::addV6(string in) {
72     return add(in, IP_FAM::V6);
73 } /* addV6 */
74 
addV6(vector<string> in)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 
size()83 int PrefixParser::size() {
84     return mPrefixes.size();
85 } /* size */
86 
allAreFullyQualified()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 
getFirstPrefix()108 Prefix PrefixParser::getFirstPrefix() {
109     if (size() >= 1)
110         return mPrefixes[0];
111     return makeBlankPrefix(IP_FAM::INVALID);
112 } /* getFirstPrefix */
113 
getFirstPrefix(IP_FAM famHint)114 Prefix PrefixParser::getFirstPrefix(IP_FAM famHint) {
115     if (size() >= 1)
116         return mPrefixes[0];
117     return makeBlankPrefix(famHint);
118 } /* getFirstPrefix */
119 
getLastErrAsStr()120 string PrefixParser::getLastErrAsStr() {
121     return mLastErr;
122 } /* getLastErrAsStr */
123 
124 
125 /* ------------------------------ PRIVATE ----------------------------------- */
add(vector<string> in,IP_FAM famHint)126 bool PrefixParser::add(vector<string> in, IP_FAM famHint) {
127     if (in.size() == 0)
128         return false;
129 
130     for (size_t i = 0; i < in.size(); i++) {
131         if (!add(in[i], famHint))
132             return false;
133     }
134     return true;
135 } /* add */
136 
add(string in,IP_FAM famHint)137 bool PrefixParser::add(string in, IP_FAM famHint) {
138     if (in.length() == 0) {
139         mLastErr = "Failed to parse string, length = 0...";
140         return false;
141     }
142 
143     if (famHint == IP_FAM::INVALID)
144         famHint = guessIPFamily(in);
145 
146     string subnet;
147     string addr;
148 
149     if (!splitIntoAddrAndMask(in, addr, subnet)) {
150         mLastErr = "Failed to split into Address and Mask(" + in + ")";
151         return false;
152     }
153 
154     int mask = parseSubnetMask(subnet, famHint);
155     if (!isMaskValid(mask, famHint)) {
156         mLastErr = "Invalid mask";
157         return false;
158     }
159 
160     Prefix pre = makeBlankPrefix(famHint);
161 
162     if (famHint == IP_FAM::V4) {
163         if (!parseV4Addr(addr, pre)) {
164             mLastErr = "Failed to parse V4 Address(" + addr + ")";
165             return false;
166         }
167     } else if (!parseV6Addr(addr, pre)) {
168         mLastErr = "Failed to parse V6 Address(" + addr + ")";
169         return false;
170     }
171 
172     if (famHint == IP_FAM::V4 && !populateV4Mask(mask, pre)) {
173         mLastErr = "Failed to populate IPv4 Mask(" + std::to_string(mask)
174                 + ", " + addr + ")";
175         return false;
176     } else if (!populateV6Mask(mask, pre)) {
177         mLastErr = "Failed to populate IPv6 Mask(" + std::to_string(mask)
178                 + ", " + addr + ")";
179         return false;
180     }
181 
182     mPrefixes.push_back(pre);
183     return true;
184 } /* add */
185 
186 /* Assumption (based on man inet_pton)
187  *
188  * X represents a hex character
189  * d represents a base 10 digit
190  * / represents the start of the subnet mask
191  *              (assume that it can be left off of all below combinations)
192  *
193  * IPv4 Addresses always look like the following:
194  *      ddd.ddd.ddd.ddd/dd
195  *
196  * IPv6 Addresses can look a few different ways:
197  *      x:x:x:x:x:x:x:x/ddd
198  *      x::x/ddd
199  *      x:x:x:x:x:x:d.d.d.d/ddd
200  *
201  * Therefore, if a presentation of an IP Address contains a colon, then it
202  * may not be a valid IPv6, but, it is definitely not valid IPv4.  If a
203  * presentation of an IP Address does not contain a colon, then it may not be
204  * a valid IPv4, but, it is definitely not IPv6.
205  */
guessIPFamily(string in)206 IP_FAM PrefixParser::guessIPFamily(string in) {
207     size_t found = in.find(":");
208     if (found != string::npos)
209         return IP_FAM::V6;
210     return IP_FAM::V4;
211 } /* guessIPFamily */
212 
splitIntoAddrAndMask(string in,string & addr,string & mask)213 bool PrefixParser::splitIntoAddrAndMask(string in, string &addr, string &mask) {
214     size_t pos = in.find("/");
215 
216     if (pos != string::npos && pos >= 1) {
217         /* addr is now everything up until the first / */
218         addr = in.substr(0, pos);
219     } else if (pos == string::npos) {
220         /* There is no /, so the entire input is an address */
221         addr = in;
222     } else {
223         /* There was nothing before the /, not recoverable */
224         return false;
225     }
226 
227     if (pos != string::npos && pos < in.size()) {
228         /* There is a / and it is not the last character.  Everything after /
229          * must be the subnet.
230          */
231         mask = in.substr(pos + 1);
232     } else if (pos != string::npos && pos == in.size()) {
233         /* There is a /, but it is the last character.  This is garbage, but,
234          * we may still be able to interpret the address so we will throw it
235          * out.
236          */
237         mask = "";
238     } else if (pos == string::npos) {
239         /* There is no /, therefore, there is no subnet */
240         mask = "";
241     } else {
242         /* This really shouldn't be possible because it would imply that find
243          * returned a position larger than the size of the input.  Just
244          * preserving sanity that mask is always initialized.
245          */
246         mask = "";
247     }
248 
249     return true;
250 } /* splitIntoAddrAndMask */
251 
parseSubnetMask(string in,IP_FAM famHint)252 int PrefixParser::parseSubnetMask(string in, IP_FAM famHint) {
253     if (in.empty())
254         /* Treat no subnet mask as fully qualified */
255         return (famHint == IP_FAM::V6) ? 128 : 32;
256     return atoi(in.c_str());
257 } /* parseSubnetMask */
258 
parseV4Addr(string in,Prefix & out)259 bool PrefixParser::parseV4Addr(string in, Prefix &out) {
260     struct sockaddr_in sa;
261 
262     int ret = inet_pton(AF_INET, in.c_str(), &(sa.sin_addr));
263 
264     if (ret < 0) {
265         /* errno would be valid */
266         return false;
267     } else if (ret == 0) {
268         /* input was not a valid IP address */
269         return false;
270     }
271 
272     /* Address in network byte order */
273     out.v4Addr = htonl(sa.sin_addr.s_addr);
274     return true;
275 } /* parseV4Addr */
276 
parseV6Addr(string in,Prefix & out)277 bool PrefixParser::parseV6Addr(string in, Prefix &out) {
278     struct sockaddr_in6 sa;
279 
280     int ret = inet_pton(AF_INET6, in.c_str(), &(sa.sin6_addr));
281 
282     if (ret < 0) {
283         /* errno would be valid */
284         return false;
285     } else if (ret == 0) {
286         /* input was not a valid IP address */
287         return false;
288     }
289 
290     /* Translate unsigned chars to unsigned ints to match IPA
291      *
292      * TODO there must be a better way to do this beyond bit fiddling
293      * Maybe a Union since we've already made the assumption that the data
294      * structures match?
295      */
296     out.v6Addr[0] = (sa.sin6_addr.s6_addr[0] << 24) |
297                     (sa.sin6_addr.s6_addr[1] << 16) |
298                     (sa.sin6_addr.s6_addr[2] << 8) |
299                     (sa.sin6_addr.s6_addr[3]);
300     out.v6Addr[1] = (sa.sin6_addr.s6_addr[4] << 24) |
301                     (sa.sin6_addr.s6_addr[5] << 16) |
302                     (sa.sin6_addr.s6_addr[6] << 8) |
303                     (sa.sin6_addr.s6_addr[7]);
304     out.v6Addr[2] = (sa.sin6_addr.s6_addr[8] << 24) |
305                     (sa.sin6_addr.s6_addr[9] << 16) |
306                     (sa.sin6_addr.s6_addr[10] << 8) |
307                     (sa.sin6_addr.s6_addr[11]);
308     out.v6Addr[3] = (sa.sin6_addr.s6_addr[12] << 24) |
309                     (sa.sin6_addr.s6_addr[13] << 16) |
310                     (sa.sin6_addr.s6_addr[14] << 8) |
311                     (sa.sin6_addr.s6_addr[15]);
312     return true;
313 } /* parseV6Addr */
314 
populateV4Mask(int mask,Prefix & out)315 bool PrefixParser::populateV4Mask(int mask, Prefix &out) {
316     if (mask < 0 || mask > 32)
317         return false;
318     out.v4Mask = createMask(mask);
319     return true;
320 } /* populateV4Mask */
321 
populateV6Mask(int mask,Prefix & out)322 bool PrefixParser::populateV6Mask(int mask, Prefix &out) {
323     if (mask < 0 || mask > 128)
324         return false;
325 
326     for (int i = 0; i < 4; i++) {
327         out.v6Mask[i] = createMask(mask);
328         mask = (mask > 32) ? mask - 32 : 0;
329     }
330 
331     return true;
332 } /* populateV6Mask */
333 
createMask(int mask)334 uint32_t PrefixParser::createMask(int mask) {
335     uint32_t ret = 0;
336 
337     if (mask >= 32) {
338         ret = ~ret;
339         return ret;
340     }
341 
342     for (int i = 0; i < 32; i++) {
343         if (i < mask)
344             ret = (ret << 1) | 1;
345         else
346             ret = (ret << 1);
347     }
348 
349     return ret;
350 } /* createMask */
351 
makeBlankPrefix(IP_FAM famHint)352 Prefix PrefixParser::makeBlankPrefix(IP_FAM famHint) {
353     Prefix ret;
354 
355     ret.fam = famHint;
356 
357     ret.v4Addr = 0;
358     ret.v4Mask = 0;
359 
360     ret.v6Addr[0] = 0;
361     ret.v6Addr[1] = 0;
362     ret.v6Addr[2] = 0;
363     ret.v6Addr[3] = 0;
364 
365     ret.v6Mask[0] = 0;
366     ret.v6Mask[1] = 0;
367     ret.v6Mask[2] = 0;
368     ret.v6Mask[3] = 0;
369 
370     return ret;
371 } /* makeBlankPrefix */
372 
isMaskValid(int mask,IP_FAM fam)373 bool PrefixParser::isMaskValid(int mask, IP_FAM fam) {
374     if (mask < 0) {
375         mLastErr = "Failed parse subnet mask(" + std::to_string(mask) + ")";
376         return false;
377     } else if (mask == 0) {
378         mLastErr = "Subnet mask cannot be 0(" + std::to_string(mask) + ")";
379         return false;
380     } else if (fam == IP_FAM::V4 && mask > 32) {
381         mLastErr = "Interpreted address as V4 but mask was too large("
382                 + std::to_string(mask) + ")";
383         return false;
384     } else if (fam == IP_FAM::V6 && mask > 128) {
385         mLastErr = "Interpreted address as V6 but mask was too large("
386                 + std::to_string(mask) + ")";
387         return false;
388     }
389 
390     return true;
391 } /* isMaskValid */
392