Skip to content

Commit

Permalink
feat: enhance IP handling to support IPv6 and improve address validation
Browse files Browse the repository at this point in the history
Signed-off-by: Dengfeng Liu <[email protected]>
  • Loading branch information
liudf0716 committed Jan 26, 2025
1 parent 3029120 commit eff9f9d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 23 deletions.
29 changes: 22 additions & 7 deletions src/fw_nft.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,8 @@ check_nft_expr_json_array_object(json_object *jobj, const char *ip, const char *
mac_flag = 1;
} else if (strcmp(protocol, "ip") == 0 && ip && strcmp(right, ip) == 0) {
ip_flag = 1;
} else if (strcmp(protocol, "ip6") == 0 && ip && strcmp(right, ip) == 0) {
ip_flag = 1;
}
}
}
Expand Down Expand Up @@ -833,13 +835,26 @@ nft_fw_access(fw_access_t type, const char *ip, const char *mac, int tag)
switch(type) {
case FW_ACCESS_ALLOW:
// Add outgoing traffic rule with counter and mark
nftables_do_command("add rule inet fw4 mangle_prerouting_wifidogx_outgoing "
"ether saddr %s ip saddr %s counter mark set 0x20000 accept",
mac, ip);

// Add incoming traffic rule with counter
nftables_do_command("add rule inet fw4 mangle_postrouting_wifidogx_incoming "
"ip daddr %s counter accept", ip);
if (is_valid_ip(ip)) {
nftables_do_command("add rule inet fw4 mangle_prerouting_wifidogx_outgoing "
"ether saddr %s ip saddr %s counter mark set 0x20000 accept",
mac, ip);

// Add incoming traffic rule with counter
nftables_do_command("add rule inet fw4 mangle_postrouting_wifidogx_incoming "
"ip daddr %s counter accept", ip);
} else if (is_valid_ip6(ip)){
nftables_do_command("add rule inet fw4 mangle_prerouting_wifidogx_outgoing "
"ether saddr %s ip6 saddr %s counter mark set 0x20000 accept",
mac, ip);

// Add incoming traffic rule with counter
nftables_do_command("add rule inet fw4 mangle_postrouting_wifidogx_incoming "
"ip6 daddr %s counter accept", ip);
} else {
debug(LOG_ERR, "Invalid IP address: %s", ip);
}

break;

case FW_ACCESS_DENY:
Expand Down
68 changes: 55 additions & 13 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,6 @@ ev_http_reply_client_error(struct evhttp_request *req, enum reply_client_page_ty
int
ev_http_connection_get_peer(struct evhttp_connection *evcon, char **remote_host, uint16_t *port)
{
struct sockaddr_storage ss;
char *ip = NULL;
evhttp_connection_get_peer(evcon, &ip, port);
if (ip == NULL) {
Expand All @@ -446,21 +445,52 @@ ev_http_connection_get_peer(struct evhttp_connection *evcon, char **remote_host,
}
debug(LOG_DEBUG, "get peer ip is %s", ip);

struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&ss;
if (inet_pton(AF_INET6, ip, &sin->sin6_addr) > 0) {
if (IN6_IS_ADDR_V4MAPPED(&sin->sin6_addr)) {
struct sockaddr_storage ss;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
struct sockaddr_in *sin = (struct sockaddr_in *)&ss;

// Try IPv6 first
if (inet_pton(AF_INET6, ip, &sin6->sin6_addr) > 0) {
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
// Handle IPv4-mapped IPv6 address
struct in_addr ipv4_addr;
memcpy(&ipv4_addr, &sin->sin6_addr.s6_addr[12], 4);
memcpy(&ipv4_addr, &sin6->sin6_addr.s6_addr[12], 4);
*remote_host = safe_malloc(INET_ADDRSTRLEN);
if (!inet_ntop(AF_INET, &ipv4_addr, *remote_host, INET_ADDRSTRLEN)) {
debug(LOG_ERR, "inet_ntop failed: %s", strerror(errno));
debug(LOG_ERR, "inet_ntop failed for IPv4-mapped address: %s", strerror(errno));
free(*remote_host);
return 0;
}
debug(LOG_INFO, "IPv4-mapped IPv6 address detected, converted to IPv4: %s", *remote_host);
return 1; // IPv4
} else {
// Native IPv6 address
*remote_host = safe_malloc(INET6_ADDRSTRLEN);
if (!inet_ntop(AF_INET6, &sin6->sin6_addr, *remote_host, INET6_ADDRSTRLEN)) {
debug(LOG_ERR, "inet_ntop failed for IPv6 address: %s", strerror(errno));
free(*remote_host);
return 0;
}
debug(LOG_INFO, "IPv6 address detected: %s", *remote_host);
return 2; // IPv6
}
}
// Try IPv4
else if (inet_pton(AF_INET, ip, &sin->sin_addr) > 0) {
*remote_host = safe_malloc(INET_ADDRSTRLEN);
if (!inet_ntop(AF_INET, &sin->sin_addr, *remote_host, INET_ADDRSTRLEN)) {
debug(LOG_ERR, "inet_ntop failed for IPv4 address: %s", strerror(errno));
free(*remote_host);
return 0;
}
debug(LOG_INFO, "IPv4 address detected: %s", *remote_host);
return 1; // IPv4
}

return 1;
// If we get here, the address format was invalid
debug(LOG_ERR, "Invalid IP address format: %s", ip);
*remote_host = NULL;
return 0;
}

/**
Expand Down Expand Up @@ -503,8 +533,8 @@ ev_http_callback_404(struct evhttp_request *req, void *arg)

char *remote_host = NULL;
uint16_t port;
ev_http_connection_get_peer(evhttp_request_get_connection(req), &remote_host, &port);
if (remote_host == NULL) return;
int addr_type = ev_http_connection_get_peer(evhttp_request_get_connection(req), &remote_host, &port);
if (addr_type == 0) return;

struct bufferevent *bev = evhttp_connection_get_bufferevent(evhttp_request_get_connection(req));
evutil_socket_t fd = bufferevent_getfd(bev);
Expand All @@ -514,9 +544,9 @@ ev_http_callback_404(struct evhttp_request *req, void *arg)
return;
}

t_gateway_setting *gw_setting = get_gateway_setting_by_ipv4(remote_host);
t_gateway_setting *gw_setting = get_gateway_setting_by_addr(remote_host, addr_type);
if (!gw_setting) {
debug(LOG_ERR, "get_gateway_setting_by_ipv4 [%s] failed", remote_host);
debug(LOG_ERR, "Failed to get gateway settings for address [%s] type [%d]", remote_host, addr_type);
evhttp_send_error(req, 200, "Cant get gateway setting by client's ip");
return;
}
Expand All @@ -537,7 +567,7 @@ ev_http_callback_404(struct evhttp_request *req, void *arg)
enum reply_client_page_type r_type = get_authserver_offline_page_type();
debug(LOG_DEBUG, "Auth server is offline and its reply type is %d", r_type);
ev_http_reply_client_error(req, r_type,
gw_setting->gw_address_v4?gw_setting->gw_address_v4:gw_setting->gw_address_v6,
addr_type==1?gw_setting->gw_address_v4:gw_setting->gw_address_v6,
gw_port, "http", remote_host, mac);
return;
}
Expand Down Expand Up @@ -810,11 +840,23 @@ ev_http_callback_local_auth(struct evhttp_request *req, void *arg)
const char *mac = ev_http_find_query(req, "mac");
const char *ip = ev_http_find_query(req, "ip");
if (!mac || !ip) {
debug(LOG_INFO, "Local auth called without MAC and IP specified");
evhttp_send_error(req, HTTP_OK, "MAC and IP need to be specified");
goto END;
}

t_gateway_setting *gw = get_gateway_setting_by_ipv4(ip);
uint32_t addr_type = 0;
if (is_valid_ip(ip))
addr_type = 1;
else if (is_valid_ip6(ip))
addr_type = 2;
if (!addr_type) {
debug(LOG_INFO, "Invalid IP address format [%s]", ip);
evhttp_send_error(req, HTTP_OK, "Invalid IP address format");
goto END;
}

t_gateway_setting *gw = get_gateway_setting_by_addr(ip, addr_type);
if (!gw) {
evhttp_send_error(req, HTTP_OK, "Cant get gateway setting by client's ip");
goto END;
Expand Down
2 changes: 1 addition & 1 deletion src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

#ifndef _VERSION_
#define _VERSION_
#define VERSION "8.01.2309"
#define VERSION "8.01.2311"
#endif
24 changes: 23 additions & 1 deletion src/wd_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,7 @@ get_gateway_setting_by_id(const char *gw_id)
return NULL;
}

t_gateway_setting *
static t_gateway_setting *
get_gateway_setting_by_ipv4(const char *ip)
{
if (!ip)
Expand All @@ -1995,6 +1995,28 @@ get_gateway_setting_by_ipv4(const char *ip)
}
return NULL;
}

static t_gateway_setting *
get_gateway_setting_by_ipv6(const char *ipv6)
{
if (!ipv6)
return NULL;

return get_gateway_settings(); // TODO;
}

t_gateway_setting *
get_gateway_setting_by_addr(const char *addr, int type)
{
if (type ==1) { // ipv4
return get_gateway_setting_by_ipv4(addr);
} else if (type == 2) { // ipv6
return get_gateway_setting_by_ipv6(addr);
}

return NULL;
}

/**
* @brief generate cert for apfree-wifidog
* first, generate ca cert
Expand Down
2 changes: 1 addition & 1 deletion src/wd_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int get_ifname_by_address(const char *, char *);

t_gateway_setting *get_gateway_setting_by_ifname(const char *);
t_gateway_setting *get_gateway_setting_by_id(const char *);
t_gateway_setting *get_gateway_setting_by_ipv4(const char *);
t_gateway_setting *get_gateway_setting_by_addr(const char *, int);

/** @brief generate cert for apfree-wifidog */
void init_apfree_wifidog_cert();
Expand Down

0 comments on commit eff9f9d

Please sign in to comment.