|
9 | 9 | # include <winsock2.h> |
10 | 10 | # include <ws2tcpip.h> |
11 | 11 | #else |
| 12 | +# include <arpa/inet.h> |
12 | 13 | # include <sys/types.h> |
13 | 14 | # include <sys/socket.h> |
14 | 15 | # include <netdb.h> |
@@ -132,3 +133,126 @@ char *dns_resolve(const char *host, int32_t *error) { |
132 | 133 | char *dns_resolve_ex(const char *host, int32_t *error) { |
133 | 134 | return dns_resolve_filter(host, AF_UNSPEC, UINT8_MAX, error); |
134 | 135 | } |
| 136 | + |
| 137 | +#if _WIN32_WINNT < _WIN32_WINNT_VISTA |
| 138 | +// Backwards compatible inet_pton for Windows XP |
| 139 | +int32_t inet_pton(int32_t af, const char *src, void *dst) { |
| 140 | + struct sockaddr_storage sock_storage; |
| 141 | + int32_t size = sizeof(sockaddr_storage); |
| 142 | + char src_copy[INET6_ADDRSTRLEN + 1]; |
| 143 | + |
| 144 | + memset(&sock_storage, 0, sizeof(sock_storage)); |
| 145 | + strncpy(src_copy, src, INET6_ADDRSTRLEN + 1); |
| 146 | + src_copy[INET6_ADDRSTRLEN] = 0; |
| 147 | + |
| 148 | + if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&sock_storage, &size) == 0) { |
| 149 | + switch (af) { |
| 150 | + case AF_INET: |
| 151 | + *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; |
| 152 | + return 1; |
| 153 | + case AF_INET6: |
| 154 | + *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; |
| 155 | + return 1; |
| 156 | + } |
| 157 | + } |
| 158 | + return 0; |
| 159 | +} |
| 160 | +#endif |
| 161 | + |
| 162 | +// Check if the ipv4 address matches the cidr notation range |
| 163 | +bool is_ipv4_in_cidr_range(const char *ip, const char *cidr) { |
| 164 | + if (!ip || !cidr) |
| 165 | + return false; |
| 166 | + |
| 167 | + // Convert ip from text to binary |
| 168 | + struct in_addr ip_addr; |
| 169 | + if (!inet_pton(AF_INET, ip, &ip_addr)) |
| 170 | + return false; |
| 171 | + |
| 172 | + // Parse cidr notation |
| 173 | + char *cidr_ip = strdup(cidr); |
| 174 | + char *cidr_prefix = strchr(cidr_ip, '/'); |
| 175 | + if (!cidr_prefix) { |
| 176 | + free(cidr_ip); |
| 177 | + return false; |
| 178 | + } |
| 179 | + *cidr_prefix = 0; |
| 180 | + cidr_prefix++; |
| 181 | + |
| 182 | + // Parse cidr prefix |
| 183 | + int32_t prefix = atoi(cidr_prefix); |
| 184 | + if (prefix < 0 || prefix > 32) { |
| 185 | + free(cidr_ip); |
| 186 | + return false; |
| 187 | + } |
| 188 | + |
| 189 | + // Convert cidr ip from text to binary |
| 190 | + struct in_addr cidr_addr; |
| 191 | + if (!inet_pton(AF_INET, cidr_ip, &cidr_addr)) { |
| 192 | + free(cidr_ip); |
| 193 | + return false; |
| 194 | + } |
| 195 | + free(cidr_ip); |
| 196 | + |
| 197 | + // Check if ip address is in cidr range |
| 198 | + uint32_t ip_int = ntohl(ip_addr.s_addr); |
| 199 | + uint32_t cidr_int = ntohl(cidr_addr.s_addr); |
| 200 | + uint32_t mask = prefix >= 32 ? 0xFFFFFFFFu : ~(0xFFFFFFFFu >> prefix); |
| 201 | + |
| 202 | + return (ip_int & mask) == (cidr_int & mask); |
| 203 | +} |
| 204 | + |
| 205 | +// Check if the ipv6 address matches the cidr notation range |
| 206 | +bool is_ipv6_in_cidr_range(const char *ip, const char *cidr) { |
| 207 | + if (!ip || !cidr) |
| 208 | + return false; |
| 209 | + |
| 210 | + // Convert ip from text to binary |
| 211 | + struct in6_addr ip_addr; |
| 212 | + if (!inet_pton(AF_INET6, ip, &ip_addr)) |
| 213 | + return false; |
| 214 | + |
| 215 | + // Parse cidr notation |
| 216 | + char *cidr_ip = strdup(cidr); |
| 217 | + char *cidr_prefix = strchr(cidr_ip, '/'); |
| 218 | + if (!cidr_prefix) { |
| 219 | + free(cidr_ip); |
| 220 | + return false; |
| 221 | + } |
| 222 | + *cidr_prefix = 0; |
| 223 | + cidr_prefix++; |
| 224 | + |
| 225 | + // Parse cidr prefix |
| 226 | + int32_t prefix = atoi(cidr_prefix); |
| 227 | + if (prefix < 0 || prefix > 128) { |
| 228 | + free(cidr_ip); |
| 229 | + return false; |
| 230 | + } |
| 231 | + |
| 232 | + // Convert cidr ip from text to binary |
| 233 | + struct in6_addr cidr_addr; |
| 234 | + if (!inet_pton(AF_INET6, cidr_ip, &cidr_addr)) { |
| 235 | + free(cidr_ip); |
| 236 | + return false; |
| 237 | + } |
| 238 | + free(cidr_ip); |
| 239 | + |
| 240 | + // Check if ip address is in cidr range |
| 241 | + uint8_t *ip_data = (uint8_t *)&ip_addr.s6_addr; |
| 242 | + uint8_t *cidr_data = (uint8_t *)&cidr_addr.s6_addr; |
| 243 | + |
| 244 | + // Compare leading bytes of address |
| 245 | + int32_t check_bytes = prefix / 8; |
| 246 | + if (check_bytes) { |
| 247 | + if (memcmp(ip_data, cidr_data, check_bytes)) |
| 248 | + return false; |
| 249 | + } |
| 250 | + |
| 251 | + // Check remaining bits of address |
| 252 | + int32_t check_bits = prefix & 0x07; |
| 253 | + if (!check_bits) |
| 254 | + return true; |
| 255 | + |
| 256 | + uint8_t mask = (0xff << (8 - check_bits)); |
| 257 | + return ((ip_data[check_bytes] ^ cidr_data[check_bytes]) & mask) == 0; |
| 258 | +} |
0 commit comments