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