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