IP白名单支持ipv6 (#2858)

Fix #2855
This commit is contained in:
夏楚 2023-09-26 14:48:19 +08:00 committed by GitHub
parent 3ff373471e
commit 9f6930390a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 19 deletions

View File

@ -244,7 +244,7 @@ forwarded_ip_header=
#默认允许所有跨域请求 #默认允许所有跨域请求
allow_cross_domains=1 allow_cross_domains=1
#允许访问http api和http文件索引的ip地址范围白名单置空情况下不做限制 #允许访问http api和http文件索引的ip地址范围白名单置空情况下不做限制
allow_ip_range=127.0.0.1,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255 allow_ip_range=::1,127.0.0.1,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255
[multicast] [multicast]
#rtp组播截止组播ip地址 #rtp组播截止组播ip地址

View File

@ -194,7 +194,7 @@ static onceToken token([]() {
mINI::Instance()[kForbidCacheSuffix] = ""; mINI::Instance()[kForbidCacheSuffix] = "";
mINI::Instance()[kForwardedIpHeader] = ""; mINI::Instance()[kForwardedIpHeader] = "";
mINI::Instance()[kAllowCrossDomains] = 1; mINI::Instance()[kAllowCrossDomains] = 1;
mINI::Instance()[kAllowIPRange] = "127.0.0.1,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255"; mINI::Instance()[kAllowIPRange] = "::1,127.0.0.1,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255";
}); });
} // namespace Http } // namespace Http

View File

@ -50,29 +50,69 @@ const string &HttpFileManager::getContentType(const char *name) {
return HttpConst::getHttpContentType(name); return HttpConst::getHttpContentType(name);
} }
#ifndef ntohll namespace {
static uint64_t ntohll(uint64_t val) { class UInt128 {
return (((uint64_t)ntohl(val)) << 32) + ntohl(val >> 32); public:
} UInt128() = default;
#endif
static uint64_t get_ip_uint64(const std::string &ip) { UInt128(const struct sockaddr_storage &storage) {
_family = storage.ss_family;
memset(_bytes, 0, 16);
switch (storage.ss_family) {
case AF_INET: {
memcpy(_bytes, &(reinterpret_cast<const struct sockaddr_in &>(storage).sin_addr), 4);
break;
}
case AF_INET6: {
memcpy(_bytes, &(reinterpret_cast<const struct sockaddr_in6 &>(storage).sin6_addr), 16);
break;
}
default: CHECK(false, "Invalid socket family"); break;
}
}
bool operator==(const UInt128 &that) const { return _family == that._family && !memcmp(_bytes, that._bytes, 16); }
bool operator<=(const UInt128 &that) const { return *this < that || *this == that; }
bool operator>=(const UInt128 &that) const { return *this > that || *this == that; }
bool operator>(const UInt128 &that) const { return that < *this; }
bool operator<(const UInt128 &that) const {
auto sz = _family == AF_INET ? 4 : 16;
for (int i = 0; i < sz; ++i) {
if (_bytes[i] < that._bytes[i]) {
return true;
} else if (_bytes[i] > that._bytes[i]) {
return false;
}
}
return false;
}
operator bool() const { return _family != -1; }
bool same_type(const UInt128 &that) const { return _family == that._family; }
private:
int _family = -1;
uint8_t _bytes[16];
};
}
static UInt128 get_ip_uint64(const std::string &ip) {
try { try {
auto storage = SockUtil::make_sockaddr(ip.data(), 0); return UInt128(SockUtil::make_sockaddr(ip.data(), 0));
if (storage.ss_family == AF_INET) {
return ntohl(reinterpret_cast<uint32_t &>(reinterpret_cast<struct sockaddr_in &>(storage).sin_addr));
}
if (storage.ss_family == AF_INET6) {
return ntohll(reinterpret_cast<uint64_t &>(reinterpret_cast<struct sockaddr_in6 &>(storage).sin6_addr));
}
} catch (std::exception &ex) { } catch (std::exception &ex) {
WarnL << ex.what(); WarnL << ex.what();
} }
return 0; return UInt128();
} }
bool HttpFileManager::isIPAllowed(const std::string &ip) { bool HttpFileManager::isIPAllowed(const std::string &ip) {
using IPRangs = std::vector<std::pair<uint64_t /*min_ip*/, uint64_t /*max_ip*/>>; using IPRangs = std::vector<std::pair<UInt128 /*min_ip*/, UInt128 /*max_ip*/>>;
GET_CONFIG_FUNC(IPRangs, allow_ip_range, Http::kAllowIPRange, [](const string &str) -> IPRangs { GET_CONFIG_FUNC(IPRangs, allow_ip_range, Http::kAllowIPRange, [](const string &str) -> IPRangs {
IPRangs ret; IPRangs ret;
auto vec = split(str, ","); auto vec = split(str, ",");
@ -84,13 +124,17 @@ bool HttpFileManager::isIPAllowed(const std::string &ip) {
if (range.size() == 2) { if (range.size() == 2) {
auto ip_min = get_ip_uint64(trim(range[0])); auto ip_min = get_ip_uint64(trim(range[0]));
auto ip_max = get_ip_uint64(trim(range[1])); auto ip_max = get_ip_uint64(trim(range[1]));
if (ip_min && ip_max) { if (ip_min && ip_max && ip_min.same_type(ip_max)) {
ret.emplace_back(ip_min, ip_max); ret.emplace_back(ip_min, ip_max);
} else {
WarnL << "Invalid ip range or family: " << item;
} }
} else if (range.size() == 1) { } else if (range.size() == 1) {
auto ip = get_ip_uint64(trim(range[0])); auto ip = get_ip_uint64(trim(range[0]));
if (ip) { if (ip) {
ret.emplace_back(ip, ip); ret.emplace_back(ip, ip);
} else {
WarnL << "Invalid ip: " << item;
} }
} else { } else {
WarnL << "Invalid ip range: " << item; WarnL << "Invalid ip range: " << item;
@ -104,7 +148,7 @@ bool HttpFileManager::isIPAllowed(const std::string &ip) {
} }
auto ip_int = get_ip_uint64(ip); auto ip_int = get_ip_uint64(ip);
for (auto &range : allow_ip_range) { for (auto &range : allow_ip_range) {
if (ip_int >= range.first && ip_int <= range.second) { if (ip_int.same_type(range.first) && ip_int >= range.first && ip_int <= range.second) {
return true; return true;
} }
} }