Skip to content

Commit 3e3de59

Browse files
committed
Normalize IPv4-mapped IPv6 in per-IP connection limit
A client connecting as ::ffff:192.168.1.1 (IPv6 socket) and 192.168.1.1 (IPv4 socket) was counted as two different IPs. Extract the IPv4 address from IPv4-mapped IPv6 before comparing, consistent with how acl_check handles it.
1 parent fb8d992 commit 3e3de59

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

thinproxy.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,31 +461,57 @@ connect_port_allowed(const char *port)
461461
return 0;
462462
}
463463

464+
/*
465+
* Extract IPv4 address from sockaddr, handling IPv4-mapped IPv6.
466+
* Returns 1 and fills *out if IPv4 (native or mapped), 0 otherwise.
467+
*/
468+
static int
469+
extract_v4(struct sockaddr *sa, struct in_addr *out)
470+
{
471+
if (sa->sa_family == AF_INET) {
472+
*out = ((struct sockaddr_in *)sa)->sin_addr;
473+
return 1;
474+
}
475+
if (sa->sa_family == AF_INET6) {
476+
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
477+
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
478+
memcpy(out, sin6->sin6_addr.s6_addr + 12, 4);
479+
return 1;
480+
}
481+
}
482+
return 0;
483+
}
484+
464485
static int
465486
per_ip_check(struct sockaddr *sa)
466487
{
467488
int fd, count;
489+
struct in_addr new_v4;
490+
int new_is_v4;
468491

469492
if (cfg_maxconns_per_ip <= 0)
470493
return 1;
471494

495+
new_is_v4 = extract_v4(sa, &new_v4);
496+
472497
count = 0;
473498
for (fd = 0; fd < MAX_FDS; fd++) {
474499
struct conn *c = fdmap[fd];
500+
struct in_addr peer_v4;
475501
if (c == NULL || fdtype_arr[fd] != FD_CLIENT)
476502
continue;
477503
if (c->cfd != fd)
478504
continue;
479-
if (c->peer.ss_family != sa->sa_family)
480-
continue;
481-
if (sa->sa_family == AF_INET) {
482-
struct sockaddr_in *a = (struct sockaddr_in *)sa;
483-
struct sockaddr_in *b = (struct sockaddr_in *)&c->peer;
484-
if (a->sin_addr.s_addr == b->sin_addr.s_addr)
505+
if (new_is_v4) {
506+
if (extract_v4((struct sockaddr *)&c->peer,
507+
&peer_v4) &&
508+
new_v4.s_addr == peer_v4.s_addr)
485509
count++;
486-
} else if (sa->sa_family == AF_INET6) {
510+
} else if (sa->sa_family == AF_INET6 &&
511+
c->peer.ss_family == AF_INET6) {
487512
struct sockaddr_in6 *a = (struct sockaddr_in6 *)sa;
488-
struct sockaddr_in6 *b = (struct sockaddr_in6 *)&c->peer;
513+
struct sockaddr_in6 *b =
514+
(struct sockaddr_in6 *)&c->peer;
489515
if (memcmp(&a->sin6_addr, &b->sin6_addr, 16) == 0)
490516
count++;
491517
}

0 commit comments

Comments
 (0)