1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include "mongo/base/status_with.h"
34 #include "mongo/base/string_data.h"
35 #include "mongo/bson/bsonelement.h"
36 #include "mongo/bson/bsonmisc.h"
37 
38 #include <stdexcept>
39 #include <string>
40 
41 #ifndef _WIN32
42 #include <sys/socket.h>
43 #endif
44 
45 namespace mongo {
46 
47 /**
48  * CIDR (Classless Inter-Domain Routing)
49  */
50 class CIDR {
51 public:
52     explicit CIDR(StringData);
53 
54     /**
55      * If the given BSONElement represents a valid CIDR range,
56      * constructs and returns the CIDR.
57      * Otherwise returns an error.
58      */
59     static StatusWith<CIDR> parse(BSONElement from) noexcept;
60 
61     /**
62      * If the given string represents a valid CIDR range,
63      * constructs and returns the CIDR.
64      * Otherwise returns an error.
65      */
66     static StatusWith<CIDR> parse(StringData from) noexcept;
67 
68     /**
69      * Returns true if the provided address range is contained
70      * entirely within this one, false otherwise.
71      */
contains(const CIDR & cidr)72     bool contains(const CIDR& cidr) const {
73         if ((_family != cidr._family) || (_len > cidr._len)) {
74             return false;
75         }
76 
77         auto bytes = _len / 8;
78         auto const range = _ip.begin();
79         auto const ip = cidr._ip.begin();
80         if (!std::equal(range, range + bytes, ip, ip + bytes)) {
81             return false;
82         }
83 
84         if ((_len % 8) == 0) {
85             return true;
86         }
87 
88         auto mask = (0xFF << (8 - (_len % 8))) & 0xFF;
89         return (_ip[bytes] & mask) == (cidr._ip[bytes] & mask);
90     }
91 
92     friend bool operator==(const CIDR& lhs, const CIDR& rhs);
93     friend bool operator!=(const CIDR& lhs, const CIDR& rhs) {
94         return !(lhs == rhs);
95     }
96     friend std::ostream& operator<<(std::ostream& s, const CIDR& rhs);
97     friend StringBuilder& operator<<(StringBuilder& s, const CIDR& rhs);
98 
99     /**
100      * Return a string representation of this CIDR (i.e. "169.254.0.0/16")
101      */
toString()102     std::string toString() const {
103         StringBuilder s;
104         s << *this;
105         return s.str();
106     }
107 
108 private:
109 #ifdef _WIN32
110     using sa_family_t = int;
111 #endif
112 
equalityLens()113     auto equalityLens() const {
114         return std::tie(_ip, _family, _len);
115     }
116 
117     std::array<std::uint8_t, 16> _ip;
118     sa_family_t _family;
119     std::uint8_t _len;
120 };
121 
122 inline bool operator==(const CIDR& lhs, const CIDR& rhs) {
123     return lhs.equalityLens() == rhs.equalityLens();
124 }
125 
126 std::ostream& operator<<(std::ostream& s, const CIDR& cidr);
127 StringBuilder& operator<<(StringBuilder& s, const CIDR& cidr);
128 
129 /**
130  * Supports use of CIDR with the BSON macro:
131  *     BSON("cidr" << cidr) -> { cidr: "..." }
132  */
133 template <>
134 BSONObjBuilder& BSONObjBuilderValueStream::operator<<<CIDR>(CIDR value);
135 
136 }  // namespace mongo
137