1582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/*
2582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *
4582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * Redistribution and use in source and binary forms, with or without
5582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * modification, are permitted provided that the following conditions are
6582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * met:
7582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *    * Redistributions of source code must retain the above copyright
8582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      notice, this list of conditions and the following disclaimer.
9582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *    * Redistributions in binary form must reproduce the above
10582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      copyright notice, this list of conditions and the following
11582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      disclaimer in the documentation and/or other materials provided
12582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      with the distribution.
13582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *    * Neither the name of The Linux Foundation nor the names of its
14582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      contributors may be used to endorse or promote products derived
15582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      from this software without specific prior written permission.
16582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *
17582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel */
29582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/* External Includes */
30582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <arpa/inet.h>
31582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <netinet/in.h>
32582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <netinet/ip.h>
33582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <string.h>
34582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <sys/socket.h>
35582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <sys/types.h>
36582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include <vector>
37582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
38582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/* Internal Includes */
39582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include "IOffloadManager.h"
40582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel#include "PrefixParser.h"
41582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
42582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/* Avoiding namespace pollution */
43582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelusing IP_FAM = ::IOffloadManager::IP_FAM;
44582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelusing Prefix = ::IOffloadManager::Prefix;
45582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
46582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelusing ::std::string;
47582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelusing ::std::vector;
48582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
49582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
50582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/* ------------------------------ PUBLIC ------------------------------------ */
51582b9e5c388f74eeafad876c81492c81bf1f3945Thierry StrudelPrefixParser::PrefixParser() {
52582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    mLastErr = "No Err";
53582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* PrefixParser */
54582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
55582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::add(vector<string> in) {
56582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return add(in, IP_FAM::INVALID);
57582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* add */
58582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
59582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::add(string in) {
60582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return add(in, IP_FAM::INVALID);
61582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* add */
62582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
63582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::addV4(string in) {
64582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return add(in, IP_FAM::V4);
65582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* addV4 */
66582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
67582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::addV4(vector<string> in) {
68582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return add(in, IP_FAM::V4);
69582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* addV4 */
70582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
71582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::addV6(string in) {
72582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return add(in, IP_FAM::V6);
73582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* addV6 */
74582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
75582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::addV6(vector<string> in) {
76582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    for (size_t i = 0; i < in.size(); i++) {
77582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        if (!addV6(in[i]))
78582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            return false;
79582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
80582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
81582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* addV6 */
82582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
83582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelint PrefixParser::size() {
84582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return mPrefixes.size();
85582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* size */
86582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
87582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::allAreFullyQualified() {
88582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    for (size_t i = 0; i < mPrefixes.size(); i++) {
89582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        if (mPrefixes[i].fam == IP_FAM::V4) {
90582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            uint32_t masked = mPrefixes[i].v4Addr & mPrefixes[i].v4Mask;
91582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            if (masked != mPrefixes[i].v4Addr)
92582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                return false;
93582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        } else {
94582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            uint32_t masked[4];
95582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            masked[0] = mPrefixes[i].v6Addr[0] & mPrefixes[i].v6Mask[0];
96582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            masked[1] = mPrefixes[i].v6Addr[1] & mPrefixes[i].v6Mask[1];
97582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            masked[2] = mPrefixes[i].v6Addr[2] & mPrefixes[i].v6Mask[2];
98582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            masked[3] = mPrefixes[i].v6Addr[3] & mPrefixes[i].v6Mask[3];
99582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            for (int j = 0; j < 4; j++) {
100582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                if (masked[j] != mPrefixes[i].v6Addr[j])
101582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    return false;
102582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            }
103582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        }
104582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
105582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
106582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* allAreFullyQualified */
107582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
108582b9e5c388f74eeafad876c81492c81bf1f3945Thierry StrudelPrefix PrefixParser::getFirstPrefix() {
109582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (size() >= 1)
110582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return mPrefixes[0];
111582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return makeBlankPrefix(IP_FAM::INVALID);
112582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* getFirstPrefix */
113582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
114582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelstring PrefixParser::getLastErrAsStr() {
115582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return mLastErr;
116582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* getLastErrAsStr */
117582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
118582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
119582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/* ------------------------------ PRIVATE ----------------------------------- */
120582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::add(vector<string> in, IP_FAM famHint) {
121e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar    if (in.size() == 0)
122e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar        return false;
123e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar
124582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    for (size_t i = 0; i < in.size(); i++) {
125582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        if (!add(in[i], famHint))
126582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            return false;
127582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
128582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
129582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* add */
130582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
131582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::add(string in, IP_FAM famHint) {
132e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar    if (in.length() == 0) {
133e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar        mLastErr = "Failed to parse string, length = 0...";
134e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar        return false;
135e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar    }
136e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar
137582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (famHint == IP_FAM::INVALID)
138582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        famHint = guessIPFamily(in);
139582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
140582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    string subnet;
141582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    string addr;
142582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
143582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (!splitIntoAddrAndMask(in, addr, subnet)) {
144582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Failed to split into Address and Mask(" + in + ")";
145582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
146582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
147582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
148582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    int mask = parseSubnetMask(subnet, famHint);
149e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar    if (!isMaskValid(mask, famHint)) {
150e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar        mLastErr = "Invalid mask";
151582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
152e549f669e0b541e30de78dc8b3db78b07407955eNiranjan Pendharkar    }
153582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
154582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    Prefix pre = makeBlankPrefix(famHint);
155582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
156582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (famHint == IP_FAM::V4) {
157582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        if (!parseV4Addr(addr, pre)) {
158582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            mLastErr = "Failed to parse V4 Address(" + addr + ")";
159582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            return false;
160582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        }
161582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (!parseV6Addr(addr, pre)) {
162582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Failed to parse V6 Address(" + addr + ")";
163582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
164582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
165582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
166582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (famHint == IP_FAM::V4 && !populateV4Mask(mask, pre)) {
167582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Failed to populate IPv4 Mask(" + std::to_string(mask)
168582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                + ", " + addr + ")";
169582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
170582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (!populateV6Mask(mask, pre)) {
171582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Failed to populate IPv6 Mask(" + std::to_string(mask)
172582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                + ", " + addr + ")";
173582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
174582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
175582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
176582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    mPrefixes.push_back(pre);
177582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
178582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* add */
179582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
180582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel/* Assumption (based on man inet_pton)
181582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *
182582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * X represents a hex character
183582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * d represents a base 10 digit
184582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * / represents the start of the subnet mask
185582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *              (assume that it can be left off of all below combinations)
186582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *
187582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * IPv4 Addresses always look like the following:
188582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      ddd.ddd.ddd.ddd/dd
189582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *
190582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * IPv6 Addresses can look a few different ways:
191582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      x:x:x:x:x:x:x:x/ddd
192582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      x::x/ddd
193582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *      x:x:x:x:x:x:d.d.d.d/ddd
194582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel *
195582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * Therefore, if a presentation of an IP Address contains a colon, then it
196582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * may not be a valid IPv6, but, it is definitely not valid IPv4.  If a
197582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * presentation of an IP Address does not contain a colon, then it may not be
198582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel * a valid IPv4, but, it is definitely not IPv6.
199582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel */
200582b9e5c388f74eeafad876c81492c81bf1f3945Thierry StrudelIP_FAM PrefixParser::guessIPFamily(string in) {
201582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    size_t found = in.find(":");
202582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (found != string::npos)
203582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return IP_FAM::V6;
204582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return IP_FAM::V4;
205582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* guessIPFamily */
206582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
207582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::splitIntoAddrAndMask(string in, string &addr, string &mask) {
208582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    size_t pos = in.find("/");
209582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
210582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (pos != string::npos && pos >= 1) {
211582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* addr is now everything up until the first / */
212582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        addr = in.substr(0, pos);
213582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (pos == string::npos) {
214582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* There is no /, so the entire input is an address */
215582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        addr = in;
216582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else {
217582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* There was nothing before the /, not recoverable */
218582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
219582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
220582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
221582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (pos != string::npos && pos < in.size()) {
222582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* There is a / and it is not the last character.  Everything after /
223582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         * must be the subnet.
224582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         */
225582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mask = in.substr(pos + 1);
226582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (pos != string::npos && pos == in.size()) {
227582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* There is a /, but it is the last character.  This is garbage, but,
228582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         * we may still be able to interpret the address so we will throw it
229582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         * out.
230582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         */
231582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mask = "";
232582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (pos == string::npos) {
233582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* There is no /, therefore, there is no subnet */
234582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mask = "";
235582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else {
236582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* This really shouldn't be possible because it would imply that find
237582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         * returned a position larger than the size of the input.  Just
238582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         * preserving sanity that mask is always initialized.
239582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel         */
240582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mask = "";
241582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
242582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
243582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
244582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* splitIntoAddrAndMask */
245582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
246582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelint PrefixParser::parseSubnetMask(string in, IP_FAM famHint) {
247582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (in.empty())
248582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* Treat no subnet mask as fully qualified */
249582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return (famHint == IP_FAM::V6) ? 128 : 32;
250582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return atoi(in.c_str());
251582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* parseSubnetMask */
252582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
253582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::parseV4Addr(string in, Prefix &out) {
254582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    struct sockaddr_in sa;
255582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
256582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    int ret = inet_pton(AF_INET, in.c_str(), &(sa.sin_addr));
257582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
258582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (ret < 0) {
259582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* errno would be valid */
260582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
261582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (ret == 0) {
262582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* input was not a valid IP address */
263582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
264582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
265582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
266582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    /* Address in network byte order */
267582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    out.v4Addr = htonl(sa.sin_addr.s_addr);
268582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
269582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* parseV4Addr */
270582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
271582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::parseV6Addr(string in, Prefix &out) {
272582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    struct sockaddr_in6 sa;
273582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
274582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    int ret = inet_pton(AF_INET6, in.c_str(), &(sa.sin6_addr));
275582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
276582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (ret < 0) {
277582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* errno would be valid */
278582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
279582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (ret == 0) {
280582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        /* input was not a valid IP address */
281582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
282582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
283582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
284582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    /* Translate unsigned chars to unsigned ints to match IPA
285582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel     *
286582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel     * TODO there must be a better way to do this beyond bit fiddling
287582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel     * Maybe a Union since we've already made the assumption that the data
288582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel     * structures match?
289582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel     */
290582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    out.v6Addr[0] = (sa.sin6_addr.s6_addr[0] << 24) |
291582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[1] << 16) |
292582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[2] << 8) |
293582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[3]);
294582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    out.v6Addr[1] = (sa.sin6_addr.s6_addr[4] << 24) |
295582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[5] << 16) |
296582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[6] << 8) |
297582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[7]);
298582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    out.v6Addr[2] = (sa.sin6_addr.s6_addr[8] << 24) |
299582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[9] << 16) |
300582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[10] << 8) |
301582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[11]);
302582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    out.v6Addr[3] = (sa.sin6_addr.s6_addr[12] << 24) |
303582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[13] << 16) |
304582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[14] << 8) |
305582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                    (sa.sin6_addr.s6_addr[15]);
306582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
307582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* parseV6Addr */
308582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
309582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::populateV4Mask(int mask, Prefix &out) {
310582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (mask < 0 || mask > 32)
311582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
312582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    out.v4Mask = createMask(mask);
313582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
314582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* populateV4Mask */
315582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
316582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::populateV6Mask(int mask, Prefix &out) {
317582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (mask < 0 || mask > 128)
318582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
319582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
320582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    for (int i = 0; i < 4; i++) {
321582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        out.v6Mask[i] = createMask(mask);
322582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mask = (mask > 32) ? mask - 32 : 0;
323582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
324582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
325582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
326582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* populateV6Mask */
327582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
328582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudeluint32_t PrefixParser::createMask(int mask) {
329582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    uint32_t ret = 0;
330582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
331582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (mask >= 32) {
332582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        ret = ~ret;
333582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return ret;
334582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
335582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
336582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    for (int i = 0; i < 32; i++) {
337582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        if (i < mask)
338582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            ret = (ret << 1) | 1;
339582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        else
340582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel            ret = (ret << 1);
341582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
342582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
343582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return ret;
344582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* createMask */
345582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
346582b9e5c388f74eeafad876c81492c81bf1f3945Thierry StrudelPrefix PrefixParser::makeBlankPrefix(IP_FAM famHint) {
347582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    Prefix ret;
348582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
349582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.fam = famHint;
350582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
351582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v4Addr = 0;
352582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v4Mask = 0;
353582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
354582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Addr[0] = 0;
355582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Addr[1] = 0;
356582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Addr[2] = 0;
357582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Addr[3] = 0;
358582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
359582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Mask[0] = 0;
360582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Mask[1] = 0;
361582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Mask[2] = 0;
362582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    ret.v6Mask[3] = 0;
363582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
364582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return ret;
365582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* makeBlankPrefix */
366582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
367582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudelbool PrefixParser::isMaskValid(int mask, IP_FAM fam) {
368582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    if (mask < 0) {
369582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Failed parse subnet mask(" + std::to_string(mask) + ")";
370582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
371582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (mask == 0) {
372582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Subnet mask cannot be 0(" + std::to_string(mask) + ")";
373582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
374582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (fam == IP_FAM::V4 && mask > 32) {
375582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Interpreted address as V4 but mask was too large("
376582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                + std::to_string(mask) + ")";
377582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
378582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    } else if (fam == IP_FAM::V6 && mask > 128) {
379582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        mLastErr = "Interpreted address as V6 but mask was too large("
380582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel                + std::to_string(mask) + ")";
381582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel        return false;
382582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    }
383582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel
384582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel    return true;
385582b9e5c388f74eeafad876c81492c81bf1f3945Thierry Strudel} /* isMaskValid */
386