Files
tools/blockip/src/ip_utils.c
T
sushen339 43fc123cb4 c
2025-11-18 12:54:21 +08:00

181 lines
4.8 KiB
C

#include "ip_utils.h"
#include <arpa/inet.h>
#include <ctype.h>
bool is_ipv6(const char *ip) {
if (!ip) return false;
/* 移除CIDR部分 */
char ip_copy[MAX_IP_LEN];
strncpy(ip_copy, ip, sizeof(ip_copy) - 1);
ip_copy[sizeof(ip_copy) - 1] = '\0';
char *slash = strchr(ip_copy, '/');
if (slash) *slash = '\0';
return strchr(ip_copy, ':') != NULL;
}
bool is_cidr(const char *ip) {
return strchr(ip, '/') != NULL;
}
int parse_ip_info(const char *input, ip_info_t *info) {
if (!input || !info) {
return ERROR_INVALID_ARG;
}
memset(info, 0, sizeof(ip_info_t));
strncpy(info->ip, input, sizeof(info->ip) - 1);
/* 检查是否是CIDR */
char *slash = strchr(info->ip, '/');
if (slash) {
*slash = '\0';
info->cidr_mask = atoi(slash + 1);
if (is_ipv6(info->ip)) {
info->type = IP_TYPE_V6_CIDR;
} else {
info->type = IP_TYPE_V4_CIDR;
}
*slash = '/'; /* 恢复 */
} else {
if (is_ipv6(info->ip)) {
info->type = IP_TYPE_V6;
} else {
info->type = IP_TYPE_V4;
}
}
return SUCCESS;
}
char* get_remote_ip(void) {
static char ip[MAX_IP_LEN];
char *env_ip = NULL;
env_ip = getenv("PAM_RHOST");
if (!env_ip) {
env_ip = getenv("RHOST");
}
if (env_ip) {
strncpy(ip, env_ip, sizeof(ip) - 1);
ip[sizeof(ip) - 1] = '\0';
return ip;
}
return NULL;
}
bool validate_ip_format(const char *ip) {
if (!ip) return false;
char ip_copy[MAX_IP_LEN];
strncpy(ip_copy, ip, sizeof(ip_copy) - 1);
ip_copy[sizeof(ip_copy) - 1] = '\0';
/* 检查CIDR */
char *slash = strchr(ip_copy, '/');
if (slash) {
*slash = '\0';
int mask = atoi(slash + 1);
if (is_ipv6(ip_copy)) {
if (mask < 0 || mask > 128) return false;
} else {
if (mask < 0 || mask > 32) return false;
}
}
/* 验证IP地址 */
struct sockaddr_in sa;
struct sockaddr_in6 sa6;
if (inet_pton(AF_INET, ip_copy, &(sa.sin_addr)) == 1) {
return true;
}
if (inet_pton(AF_INET6, ip_copy, &(sa6.sin6_addr)) == 1) {
return true;
}
return false;
}
void format_nft_element(const char *ip, char *output, size_t size, const char *timeout) {
if (!ip || !output) return;
char element[MAX_LINE_LEN];
if (is_cidr(ip)) {
strncpy(element, ip, sizeof(element) - 1);
} else if (is_ipv6(ip)) {
snprintf(element, sizeof(element), "%s/128", ip);
} else {
snprintf(element, sizeof(element), "%s/32", ip);
}
if (timeout && strlen(timeout) > 0) {
snprintf(output, size, "%s timeout %s", element, timeout);
} else {
snprintf(output, size, "%s", element);
}
}
bool ip_matches_whitelist_entry(const char *ip, const char *whitelist_entry) {
if (!ip || !whitelist_entry) return false;
/* 完全匹配 */
if (strcmp(ip, whitelist_entry) == 0) {
return true;
}
/* CIDR匹配 */
if (strchr(whitelist_entry, '/')) {
char wl_copy[MAX_IP_LEN];
strncpy(wl_copy, whitelist_entry, sizeof(wl_copy) - 1);
wl_copy[sizeof(wl_copy) - 1] = '\0';
char *slash = strchr(wl_copy, '/');
if (slash) {
*slash = '\0';
int mask = atoi(slash + 1);
/* 简单的IPv4段匹配 */
if (!is_ipv6(ip)) {
char ip_prefix[MAX_IP_LEN];
strncpy(ip_prefix, ip, sizeof(ip_prefix) - 1);
if (mask == 8) {
/* 匹配 A.*.*.* */
char *dot = strchr(ip_prefix, '.');
if (dot) *dot = '\0';
return strncmp(ip, wl_copy, strlen(ip_prefix)) == 0;
} else if (mask == 16) {
/* 匹配 A.B.*.* */
char *dot1 = strchr(ip_prefix, '.');
if (dot1) {
char *dot2 = strchr(dot1 + 1, '.');
if (dot2) *dot2 = '\0';
}
return strncmp(ip, wl_copy, strlen(ip_prefix)) == 0;
} else if (mask == 24) {
/* 匹配 A.B.C.* */
char *dot1 = strchr(ip_prefix, '.');
if (dot1) {
char *dot2 = strchr(dot1 + 1, '.');
if (dot2) {
char *dot3 = strchr(dot2 + 1, '.');
if (dot3) *dot3 = '\0';
}
}
return strncmp(ip, wl_copy, strlen(ip_prefix)) == 0;
}
}
}
}
return false;
}