From 93c1fbf8255d1ca101c22a12d3381e93db72884c Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 27 Jun 2026 03:03:50 +0300 Subject: [PATCH] veb: fall back to peer IP from client fd (#27568) --- vlib/veb/context.v | 11 +++++++ vlib/veb/tests/context_ip_test.v | 52 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 vlib/veb/tests/context_ip_test.v diff --git a/vlib/veb/context.v b/vlib/veb/context.v index a5ac69108..e5f6af023 100644 --- a/vlib/veb/context.v +++ b/vlib/veb/context.v @@ -572,6 +572,14 @@ pub fn (ctx &Context) user_agent() string { return ctx.req.header.get(.user_agent) or { '' } } +fn peer_ip_from_socket_handle(handle int) string { + address := net.peer_addr_from_socket_handle(handle) or { return '' }.str() + if address.contains(']:') { + return address.all_before(']:').all_after('[') + } + return address.all_before(':') +} + // Returns the ip address from the current user pub fn (ctx &Context) ip() string { mut ip := ctx.req.header.get_custom('CF-Connecting-IP') or { '' } @@ -590,6 +598,9 @@ pub fn (ctx &Context) ip() string { if ip == '' && ctx.conn != unsafe { nil } { ip = ctx.conn.peer_ip() or { '' } } + if ip == '' && ctx.client_fd >= 0 { + ip = peer_ip_from_socket_handle(ctx.client_fd) + } return ip } diff --git a/vlib/veb/tests/context_ip_test.v b/vlib/veb/tests/context_ip_test.v new file mode 100644 index 000000000..2623f67f7 --- /dev/null +++ b/vlib/veb/tests/context_ip_test.v @@ -0,0 +1,52 @@ +// vtest build: !windows // fasthttp.Server.run is not implemented on windows yet +import net.http +import time +import veb + +const port = 13066 +const localserver = 'http://127.0.0.1:${port}' +const exit_after = time.second * 10 + +pub struct Context { + veb.Context +} + +pub struct App { +mut: + started chan bool +} + +pub fn (mut app App) before_accept_loop() { + app.started <- true +} + +pub fn (mut app App) index(mut ctx Context) veb.Result { + return ctx.text('ip=${ctx.ip()} conn_nil=${ctx.conn == unsafe { nil }}') +} + +fn testsuite_begin() { + spawn fn () { + time.sleep(exit_after) + assert true == false, 'timeout reached!' + exit(1) + }() + + mut app := &App{} + spawn veb.run_at[App, Context](mut app, port: port, timeout_in_seconds: 2, family: .ip) + _ := <-app.started +} + +fn test_context_ip_uses_peer_ip_for_buffered_requests() { + res := http.get(localserver)! + assert res.body == 'ip=127.0.0.1 conn_nil=true' +} + +fn test_context_ip_prefers_proxy_headers() { + res := http.fetch( + url: localserver + header: http.new_header_from_map({ + .x_forwarded_for: '9.9.9.9, 8.8.8.8' + }) + )! + assert res.body == 'ip=9.9.9.9 conn_nil=true' +} -- 2.39.5