• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getLastErrAsStr()114 string PrefixParser::getLastErrAsStr() {
115     return mLastErr;
116 } /* getLastErrAsStr */
117 
118 
119 /* ------------------------------ PRIVATE ----------------------------------- */
add(vector<string> in,IP_FAM famHint)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 
add(string in,IP_FAM famHint)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  */
guessIPFamily(string in)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 
splitIntoAddrAndMask(string in,string & addr,string & mask)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 
parseSubnetMask(string in,IP_FAM famHint)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 
parseV4Addr(string in,Prefix & out)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 
parseV6Addr(string in,Prefix & out)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 
populateV4Mask(int mask,Prefix & out)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 
populateV6Mask(int mask,Prefix & out)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 
createMask(int mask)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 
makeBlankPrefix(IP_FAM famHint)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 
isMaskValid(int mask,IP_FAM fam)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