mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-08-08 09:21:48 +08:00
Merge branch 'tmp-711' into 'master'
Set `sa` before attempting to set `sa->sin6_family` Closes #711 See merge request openconnect/ocserv!554
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
* /cert.cer
|
||||
* /ca.pem
|
||||
* /ca.cer
|
||||
- Fix incorrect local address when using PROXY protocol with IPv6 (#711).
|
||||
|
||||
|
||||
* Version 1.4.2 (released 2026-04-16)
|
||||
|
||||
@@ -443,8 +443,8 @@ int parse_proxy_proto_header(struct worker_st *ws, int fd)
|
||||
|
||||
memset(&ws->remote_addr, 0, sizeof(ws->remote_addr));
|
||||
sa->sin_family = AF_INET;
|
||||
memcpy(&sa->sin_port, p + 8, 2);
|
||||
memcpy(&sa->sin_addr, p, 4);
|
||||
memcpy(&sa->sin_port, p + 8, 2);
|
||||
ws->remote_addr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
memset(&ws->our_addr, 0, sizeof(ws->our_addr));
|
||||
@@ -473,8 +473,8 @@ int parse_proxy_proto_header(struct worker_st *ws, int fd)
|
||||
ws->remote_addr_len = sizeof(struct sockaddr_in6);
|
||||
|
||||
memset(&ws->our_addr, 0, sizeof(ws->our_addr));
|
||||
sa->sin6_family = AF_INET6;
|
||||
sa = (void *)&ws->our_addr;
|
||||
sa->sin6_family = AF_INET6;
|
||||
memcpy(&sa->sin6_addr, p + 16, 16);
|
||||
memcpy(&sa->sin6_port, p + 34, 2);
|
||||
ws->our_addr_len = sizeof(struct sockaddr_in6);
|
||||
|
||||
@@ -130,6 +130,55 @@ static size_t build_v2_packet(uint8_t *buf, size_t bufsz,
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a proxy protocol v2 packet with an IPv6 address block into buf[].
|
||||
* Returns the total number of bytes written.
|
||||
*/
|
||||
static size_t build_v2_ipv6_packet(uint8_t *buf, size_t bufsz,
|
||||
const struct in6_addr *src_addr,
|
||||
uint16_t src_port,
|
||||
const struct in6_addr *dst_addr,
|
||||
uint16_t dst_port)
|
||||
{
|
||||
size_t pos = 0;
|
||||
uint16_t sp, dp, plen;
|
||||
|
||||
memcpy(buf + pos, PP2_SIG, 12);
|
||||
pos += 12;
|
||||
buf[pos++] = 0x21; /* ver=2, PROXY command */
|
||||
buf[pos++] = 0x21; /* AF_INET6 (0x2) | TCP (0x1) */
|
||||
|
||||
size_t len_offset = pos;
|
||||
buf[pos++] = 0;
|
||||
buf[pos++] = 0;
|
||||
|
||||
size_t payload_start = pos;
|
||||
|
||||
/* IPv6 address block (36 bytes):
|
||||
* src IP (16 bytes)
|
||||
* dst IP (16 bytes)
|
||||
* src port (2 bytes, network order)
|
||||
* dst port (2 bytes, network order)
|
||||
*/
|
||||
memcpy(buf + pos, src_addr, 16);
|
||||
pos += 16;
|
||||
memcpy(buf + pos, dst_addr, 16);
|
||||
pos += 16;
|
||||
sp = htons(src_port);
|
||||
dp = htons(dst_port);
|
||||
memcpy(buf + pos, &sp, 2);
|
||||
pos += 2;
|
||||
memcpy(buf + pos, &dp, 2);
|
||||
pos += 2;
|
||||
|
||||
plen = (uint16_t)(pos - payload_start);
|
||||
buf[len_offset] = (plen >> 8) & 0xff;
|
||||
buf[len_offset + 1] = plen & 0xff;
|
||||
|
||||
assert(pos <= bufsz);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Feed pkt into a pipe and call parse_proxy_proto_header.
|
||||
* ws->conn_type must be set by the caller.
|
||||
@@ -275,5 +324,78 @@ int main(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Test 6: IPv6 proxy protocol v2 — both remote and local addr correct */
|
||||
/* */
|
||||
/* Reproducer for the bug where sa->sin6_family was assigned before sa */
|
||||
/* was redirected to &ws->our_addr, leaving our_addr.sin6_family == 0. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
struct in6_addr src6, dst6;
|
||||
struct sockaddr_in6 *rem6, *loc6;
|
||||
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
ws.conn_type = SOCK_TYPE_TCP;
|
||||
|
||||
inet_pton(AF_INET6, "2001:db8::1", &src6);
|
||||
inet_pton(AF_INET6, "2001:db8::2", &dst6);
|
||||
|
||||
pkt_len = build_v2_ipv6_packet(pkt, sizeof(pkt), &src6, 1234,
|
||||
&dst6, 443);
|
||||
ret = run_parse(&ws, pkt, pkt_len);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Test 6: parse failed (%d)\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ws.remote_addr_len != sizeof(struct sockaddr_in6)) {
|
||||
fprintf(stderr, "Test 6: remote_addr_len wrong (%u)\n",
|
||||
ws.remote_addr_len);
|
||||
return 1;
|
||||
}
|
||||
if (ws.our_addr_len != sizeof(struct sockaddr_in6)) {
|
||||
fprintf(stderr, "Test 6: our_addr_len wrong (%u)\n",
|
||||
ws.our_addr_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rem6 = (void *)&ws.remote_addr;
|
||||
loc6 = (void *)&ws.our_addr;
|
||||
|
||||
if (rem6->sin6_family != AF_INET6) {
|
||||
fprintf(stderr,
|
||||
"Test 6: remote sin6_family wrong: %d\n",
|
||||
rem6->sin6_family);
|
||||
return 1;
|
||||
}
|
||||
/* This check catches the bug: sin6_family was written to
|
||||
* remote_addr a second time instead of to our_addr. */
|
||||
if (loc6->sin6_family != AF_INET6) {
|
||||
fprintf(stderr,
|
||||
"Test 6: local sin6_family wrong: %d (expected %d)\n",
|
||||
loc6->sin6_family, AF_INET6);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(&rem6->sin6_addr, &src6, 16) != 0) {
|
||||
fprintf(stderr, "Test 6: remote address mismatch\n");
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(&loc6->sin6_addr, &dst6, 16) != 0) {
|
||||
fprintf(stderr, "Test 6: local address mismatch\n");
|
||||
return 1;
|
||||
}
|
||||
if (ntohs(rem6->sin6_port) != 1234) {
|
||||
fprintf(stderr, "Test 6: remote port wrong: %u\n",
|
||||
ntohs(rem6->sin6_port));
|
||||
return 1;
|
||||
}
|
||||
if (ntohs(loc6->sin6_port) != 443) {
|
||||
fprintf(stderr, "Test 6: local port wrong: %u\n",
|
||||
ntohs(loc6->sin6_port));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user