xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/network_proxy/filtering.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "sandboxed_api/sandbox2/network_proxy/filtering.h"
16 
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 
21 #include <algorithm>
22 #include <cerrno>
23 #include <cstdint>
24 #include <cstring>
25 #include <string>
26 #include <vector>
27 
28 #include "absl/log/log.h"
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "absl/strings/match.h"
32 #include "absl/strings/numbers.h"
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/str_split.h"
35 #include "sandboxed_api/util/status_macros.h"
36 
37 namespace sandbox2 {
38 
Addr6ToString(const struct sockaddr_in6 * saddr)39 static absl::StatusOr<std::string> Addr6ToString(
40     const struct sockaddr_in6* saddr) {
41   char addr[INET6_ADDRSTRLEN];
42   int port = htons(saddr->sin6_port);
43   if (!inet_ntop(AF_INET6, &saddr->sin6_addr, addr, sizeof addr)) {
44     return absl::InternalError(
45         "Error in converting sockaddr_in6 addres to string");
46   }
47   return absl::StrCat("IP: ", addr, ", port: ", port);
48 }
49 
50 // Converts sockaddr_in structure into a string IPv4 representation.
Addr4ToString(const struct sockaddr_in * saddr)51 static absl::StatusOr<std::string> Addr4ToString(
52     const struct sockaddr_in* saddr) {
53   char addr[INET_ADDRSTRLEN];
54   int port = htons(saddr->sin_port);
55   if (!inet_ntop(AF_INET, &saddr->sin_addr, addr, sizeof addr)) {
56     return absl::InternalError(
57         "Error in converting sockaddr_in addres to string");
58   }
59   return absl::StrCat("IP: ", addr, ", port: ", port);
60 }
61 
62 // Converts sockaddr_in6 structure into a string IPv6 representation.
AddrToString(const struct sockaddr * saddr)63 absl::StatusOr<std::string> AddrToString(const struct sockaddr* saddr) {
64   switch (saddr->sa_family) {
65     case AF_INET:
66       return Addr4ToString(reinterpret_cast<const struct sockaddr_in*>(saddr));
67     case AF_INET6:
68       return Addr6ToString(reinterpret_cast<const struct sockaddr_in6*>(saddr));
69     default:
70       return absl::InternalError(
71           absl::StrCat("Unexpected sa_family value: ", saddr->sa_family));
72   }
73 }
74 
IPStringToAddr(const std::string & ip,int address_family,void * addr)75 static absl::Status IPStringToAddr(const std::string& ip, int address_family,
76                                    void* addr) {
77   if (int err = inet_pton(address_family, ip.c_str(), addr); err == 0) {
78     return absl::InvalidArgumentError(absl::StrCat("Invalid address: ", ip));
79   } else if (err == -1) {
80     return absl::ErrnoToStatus(errno,
81                                absl::StrCat("inet_pton() failed for ", ip));
82   }
83   return absl::OkStatus();
84 }
85 
86 // Parses a string of type IP or IP/mask or IP/cidr and saves appropriate
87 // values in output arguments.
ParseIpAndMask(const std::string & ip_and_mask,std::string * ip,std::string * mask,uint32_t * cidr)88 static absl::Status ParseIpAndMask(const std::string& ip_and_mask,
89                                    std::string* ip, std::string* mask,
90                                    uint32_t* cidr) {
91   // mask is checked later because only IPv4 format supports mask
92   if (ip == nullptr || cidr == nullptr) {
93     return absl::InvalidArgumentError(
94         "ip and cidr arguments of ParseIpAndMask cannot be nullptr");
95   }
96   *cidr = 0;
97 
98   std::vector<std::string> ip_and_mask_split =
99       absl::StrSplit(ip_and_mask, absl::MaxSplits('/', 1));
100 
101   *ip = ip_and_mask_split[0];
102   if (ip_and_mask_split.size() == 1) {
103     return absl::OkStatus();
104   }
105   std::string mask_or_cidr = ip_and_mask_split[1];
106 
107   const bool has_dot = absl::StrContains(mask_or_cidr, '.');
108   if (has_dot) {
109     if (mask == nullptr) {
110       return absl::InvalidArgumentError(
111           "mask argument of ParseIpAndMask cannot be NULL in this case");
112     }
113     *mask = std::string(mask_or_cidr);
114   } else {  // mask_or_cidr is cidr
115     bool res = absl::SimpleAtoi<uint32_t>(mask_or_cidr, cidr);
116     if (!res || !*cidr) {
117       return absl::InvalidArgumentError(
118           absl::StrCat(mask_or_cidr, " is not a correct cidr"));
119     }
120   }
121   return absl::OkStatus();
122 }
123 
CidrToIn6Addr(uint32_t cidr,in6_addr * addr)124 static absl::Status CidrToIn6Addr(uint32_t cidr, in6_addr* addr) {
125   if (cidr > 128) {
126     return absl::InvalidArgumentError(
127         absl::StrCat(cidr, " is not a correct cidr"));
128   }
129 
130   memset(addr, 0, sizeof(*addr));
131 
132   int i = 0;
133   while (cidr >= 8) {
134     addr->s6_addr[i++] = 0xff;
135     cidr -= 8;
136   }
137   if (cidr) {
138     uint8_t tmp = 0x0;
139     while (cidr--) {
140       tmp >>= 1;
141       tmp |= 0x80;
142     }
143     addr->s6_addr[i] = tmp;
144   }
145   return absl::OkStatus();
146 }
147 
CidrToInAddr(uint32_t cidr,in_addr * addr)148 static absl::Status CidrToInAddr(uint32_t cidr, in_addr* addr) {
149   if (cidr > 32) {
150     return absl::InvalidArgumentError(
151         absl::StrCat(cidr, " is not a correct cidr"));
152   }
153 
154   memset(addr, 0, sizeof(*addr));
155 
156   uint32_t tmp = 0x0;
157   while (cidr--) {
158     tmp >>= 1;
159     tmp |= 0x80000000;
160   }
161   addr->s_addr = htonl(tmp);
162   return absl::OkStatus();
163 }
164 
IsIPv4MaskCorrect(in_addr_t m)165 static bool IsIPv4MaskCorrect(in_addr_t m) {
166   m = ntohl(m);
167   if (m == 0) {
168     return false;
169   }
170   m = ~m + 1;
171   return !(m & (m - 1));
172 }
173 
AllowIPv4(const std::string & ip_and_mask,uint32_t port)174 absl::Status AllowedHosts::AllowIPv4(const std::string& ip_and_mask,
175                                      uint32_t port) {
176   std::string ip, mask;
177   uint32_t cidr;
178   SAPI_RETURN_IF_ERROR(ParseIpAndMask(ip_and_mask, &ip, &mask, &cidr));
179   SAPI_RETURN_IF_ERROR(AllowIPv4(ip, mask, cidr, port));
180 
181   return absl::OkStatus();
182 }
183 
AllowIPv6(const std::string & ip_and_mask,uint32_t port)184 absl::Status AllowedHosts::AllowIPv6(const std::string& ip_and_mask,
185                                      uint32_t port) {
186   std::string ip;
187   uint32_t cidr;
188   SAPI_RETURN_IF_ERROR(ParseIpAndMask(ip_and_mask, &ip, NULL, &cidr));
189   SAPI_RETURN_IF_ERROR(AllowIPv6(ip, cidr, port));
190   return absl::OkStatus();
191 }
192 
AllowIPv4(const std::string & ip,const std::string & mask,uint32_t cidr,uint32_t port)193 absl::Status AllowedHosts::AllowIPv4(const std::string& ip,
194                                      const std::string& mask, uint32_t cidr,
195                                      uint32_t port) {
196   in_addr addr{};
197   in_addr m{};
198 
199   if (!mask.empty()) {
200     SAPI_RETURN_IF_ERROR(IPStringToAddr(mask, AF_INET, &m));
201 
202     if (!IsIPv4MaskCorrect(m.s_addr)) {
203       return absl::InvalidArgumentError(
204           absl::StrCat(mask, " is not a correct mask"));
205     }
206 
207   } else {
208     if (cidr > 32) {
209       return absl::InvalidArgumentError(
210           absl::StrCat(cidr, " is not a correct cidr"));
211     }
212     if (!cidr) {
213       cidr = 32;
214     }
215 
216     SAPI_RETURN_IF_ERROR(CidrToInAddr(cidr, &m));
217   }
218 
219   SAPI_RETURN_IF_ERROR(IPStringToAddr(ip, AF_INET, &addr));
220   allowed_IPv4_.emplace_back(addr.s_addr, m.s_addr, htons(port));
221 
222   return absl::OkStatus();
223 }
224 
AllowIPv6(const std::string & ip,uint32_t cidr,uint32_t port)225 absl::Status AllowedHosts::AllowIPv6(const std::string& ip, uint32_t cidr,
226                                      uint32_t port) {
227   if (cidr == 0) {
228     cidr = 128;
229   }
230 
231   in6_addr addr{};
232   SAPI_RETURN_IF_ERROR(IPStringToAddr(ip, AF_INET6, &addr));
233 
234   in6_addr m;
235   SAPI_RETURN_IF_ERROR(CidrToIn6Addr(cidr, &m));
236 
237   allowed_IPv6_.emplace_back(addr, m, htons(port));
238   return absl::OkStatus();
239 }
240 
IsHostAllowed(const struct sockaddr * saddr) const241 bool AllowedHosts::IsHostAllowed(const struct sockaddr* saddr) const {
242   switch (saddr->sa_family) {
243     case AF_INET:
244       return IsIPv4Allowed(reinterpret_cast<const struct sockaddr_in*>(saddr));
245     case AF_INET6:
246       return IsIPv6Allowed(reinterpret_cast<const struct sockaddr_in6*>(saddr));
247     default:
248       LOG(FATAL) << absl::StrCat("Unexpected sa_family value: ",
249                                  saddr->sa_family);
250       return false;
251   }
252 }
253 
IsIPv6Allowed(const struct sockaddr_in6 * saddr) const254 bool AllowedHosts::IsIPv6Allowed(const struct sockaddr_in6* saddr) const {
255   auto result = std::find_if(
256       allowed_IPv6_.begin(), allowed_IPv6_.end(), [saddr](const IPv6& entry) {
257         for (int i = 0; i < 16; i++) {
258           if ((entry.ip.s6_addr[i] & entry.mask.s6_addr[i]) !=
259               (saddr->sin6_addr.s6_addr[i] & entry.mask.s6_addr[i])) {
260             return false;
261           }
262         }
263         if (!entry.port || (entry.port == saddr->sin6_port)) {
264           return true;
265         }
266         return false;
267       });
268 
269   return result != allowed_IPv6_.end();
270 }
271 
IsIPv4Allowed(const struct sockaddr_in * saddr) const272 bool AllowedHosts::IsIPv4Allowed(const struct sockaddr_in* saddr) const {
273   auto result = std::find_if(
274       allowed_IPv4_.begin(), allowed_IPv4_.end(), [saddr](const IPv4& entry) {
275         return ((entry.ip & entry.mask) ==
276                 (saddr->sin_addr.s_addr & entry.mask)) &&
277                (!entry.port || (entry.port == saddr->sin_port));
278       });
279 
280   return result != allowed_IPv4_.end();
281 }
282 
283 }  // namespace sandbox2
284