]> git.stg.codes - stg.git/blob - include/stg/user_ips.h
Checkout submodules in GitHub Actions.
[stg.git] / include / stg / user_ips.h
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  */
20
21 #pragma once
22
23 #include "stg/common.h"
24
25 #include <vector>
26 #include <string>
27 #include <ostream>
28 #include <cstring>
29 #include <cstdint>
30
31 #ifdef FREE_BSD
32 #include <sys/types.h>
33 #endif
34
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38
39 namespace STG
40 {
41
42 //-------------------------------------------------------------------------
43 struct IPMask
44 {
45     IPMask() noexcept : ip(0), mask(0) {}
46     IPMask(uint32_t i, uint32_t m) noexcept : ip(i), mask(m) {}
47
48     IPMask(const IPMask&) = default;
49     IPMask& operator=(const IPMask&) = default;
50     IPMask(IPMask&&) = default;
51     IPMask& operator=(IPMask&&) = default;
52
53     uint32_t ip;
54     uint32_t mask;
55 };
56 //-------------------------------------------------------------------------
57 class UserIPs
58 {
59     friend std::ostream & operator<< (std::ostream & o, const UserIPs & i);
60
61     public:
62         using ContainerType = std::vector<IPMask>;
63         using IndexType = ContainerType::size_type;
64
65         UserIPs() = default;
66
67         UserIPs(const UserIPs&) = default;
68         UserIPs& operator=(const UserIPs&) = default;
69         UserIPs(UserIPs&&) = default;
70         UserIPs& operator=(UserIPs&&) = default;
71
72         static UserIPs parse(const std::string& source);
73
74         const IPMask& operator[](IndexType idx) const noexcept { return ips[idx]; }
75         std::string toString() const noexcept;
76         bool find(uint32_t ip) const noexcept;
77         bool onlyOneIP() const noexcept;
78         bool isAnyIP() const noexcept;
79         size_t count() const noexcept { return ips.size(); }
80         void add(const IPMask& im)  noexcept{ ips.push_back(im); }
81
82     private:
83         uint32_t calcMask(unsigned int msk) const noexcept;
84         ContainerType ips;
85 };
86 //-------------------------------------------------------------------------
87
88 inline
89 std::string UserIPs::toString() const noexcept
90 {
91     if (ips.empty())
92         return "";
93
94     if (ips[0].ip == 0)
95         return "*";
96
97     auto it = ips.begin();
98     std::string res = inet_ntostring(it->ip);
99     ++it;
100     for (; it != ips.end(); ++it)
101         res += "," + inet_ntostring(it->ip);
102     return res;
103 }
104 //-----------------------------------------------------------------------------
105 inline
106 uint32_t UserIPs::calcMask(unsigned int msk) const noexcept
107 {
108     if (msk > 32)
109         return 0;
110     return htonl(0xFFffFFff << (32 - msk));
111 }
112 //-----------------------------------------------------------------------------
113 inline
114 bool UserIPs::find(uint32_t ip) const noexcept
115 {
116     if (ips.empty())
117         return false;
118
119     if (ips.front().ip == 0)
120         return true;
121
122     for (auto it = ips.begin(); it != ips.end(); ++it)
123     {
124         const auto mask = calcMask(it->mask);
125         if ((ip & mask) == (it->ip & mask))
126             return true;
127     }
128     return false;
129 }
130 //-----------------------------------------------------------------------------
131 inline
132 bool UserIPs::onlyOneIP() const noexcept
133 {
134     if (ips.size() == 1 && ips.front().mask == 32 && ips.front().ip != 0)
135         return true;
136
137     return false;
138 }
139 //-----------------------------------------------------------------------------
140 inline
141 bool UserIPs::isAnyIP() const noexcept
142 {
143     return !ips.empty() && ips.front().ip == 0;
144 }
145 //-----------------------------------------------------------------------------
146 inline
147 std::ostream & operator<<(std::ostream& o, const UserIPs& i)
148 {
149     return o << i.toString();
150 }
151 //-----------------------------------------------------------------------------
152 inline
153 UserIPs UserIPs::parse(const std::string& source)
154 {
155     if (source.empty())
156         return {};
157
158     UserIPs ips;
159     if (source[0] == '*' && source.size() == 1)
160     {
161         ips.ips.push_back(IPMask());
162         return ips;
163     }
164
165     std::vector<std::string> ipMask;
166     char * tmp = new char[source.size() + 1];
167     strcpy(tmp, source.c_str());
168     char * pstr = tmp;
169     char * paddr = NULL;
170     while ((paddr = strtok(pstr, ",")))
171     {
172         pstr = NULL;
173         ipMask.push_back(paddr);
174     }
175
176     delete[] tmp;
177
178     for (UserIPs::IndexType i = 0; i < ipMask.size(); i++)
179     {
180         char str[128];
181         char * strIp;
182         char * strMask;
183         strcpy(str, ipMask[i].c_str());
184         strIp = strtok(str, "/");
185         if (strIp == NULL)
186             return ips;
187         strMask = strtok(NULL, "/");
188
189         IPMask im;
190
191         im.ip = inet_addr(strIp);
192         if (im.ip == INADDR_NONE)
193             return ips;
194
195         im.mask = 32;
196         if (strMask != NULL)
197         {
198             int m = 0;
199             if (str2x(strMask, m) != 0)
200                 return ips;
201             im.mask = m;
202
203             if (im.mask > 32)
204                 return ips;
205
206             if ((im.ip & ips.calcMask(im.mask)) != im.ip)
207                 return ips;
208         }
209         ips.ips.push_back(im);
210     }
211
212     return ips;
213 }
214 //-------------------------------------------------------------------------
215 }