Comparison

plugins/mod_http.lua @ 13837:0b63c2c3b563

Merge 13.0->trunk
author Kim Alvefur <zash@zash.se>
date Wed, 09 Apr 2025 20:28:28 +0200
parent 13835:a4b58ea5bf7b
comparison
equal deleted inserted replaced
13831:bf4cd327966f 13837:0b63c2c3b563
329 329
330 local trusted_proxies = module:get_option_set("trusted_proxies", { "127.0.0.1", "::1" })._items; 330 local trusted_proxies = module:get_option_set("trusted_proxies", { "127.0.0.1", "::1" })._items;
331 331
332 --- deal with [ipv6]:port / ip:port format 332 --- deal with [ipv6]:port / ip:port format
333 local function normal_ip(ip) 333 local function normal_ip(ip)
334 return ip:match("^%[([%x:]*)%]") or ip:match("^([%d.]+)") or ip; 334 return ip:match("^%[([%x:]*)%]") or ip:match("^%d+%.%d+%.%d+%.%d+") or ip;
335 end 335 end
336 336
337 local function is_trusted_proxy(ip) 337 local function is_trusted_proxy(ip)
338 ip = normal_ip(ip); 338 ip = normal_ip(ip);
339 if trusted_proxies[ip] then 339 if trusted_proxies[ip] then
340 return true; 340 return true;
341 end 341 end
342 local parsed_ip = new_ip(ip) 342 local parsed_ip, err = new_ip(ip);
343 if not parsed_ip then return nil, err; end
343 for trusted_proxy in trusted_proxies do 344 for trusted_proxy in trusted_proxies do
344 if match_ip(parsed_ip, parse_cidr(trusted_proxy)) then 345 if match_ip(parsed_ip, parse_cidr(trusted_proxy)) then
345 return true; 346 return true;
346 end 347 end
347 end 348 end
355 local forwarded = http_util.parse_forwarded(request.headers.forwarded); 356 local forwarded = http_util.parse_forwarded(request.headers.forwarded);
356 if forwarded then 357 if forwarded then
357 request.forwarded = forwarded; 358 request.forwarded = forwarded;
358 for i = #forwarded, 1, -1 do 359 for i = #forwarded, 1, -1 do
359 local proxy = forwarded[i] 360 local proxy = forwarded[i]
360 if is_trusted_proxy(ip) then 361 local trusted, err = is_trusted_proxy(ip);
362 if trusted then
361 ip = normal_ip(proxy["for"]); 363 ip = normal_ip(proxy["for"]);
362 secure = secure and proxy.proto == "https"; 364 secure = secure and proxy.proto == "https";
363 else 365 else
366 if err then
367 request.log("warn", "Could not parse forwarded connection details: %s");
368 end
364 break 369 break
365 end 370 end
366 end 371 end
367 end 372 end
368 373
385 -- Case b) The original request IP is in trusted proxies. In that case, the if branch in the for loop will skip the last IP, causing it to be ignored. The second-to-last IP will be taken instead. 390 -- Case b) The original request IP is in trusted proxies. In that case, the if branch in the for loop will skip the last IP, causing it to be ignored. The second-to-last IP will be taken instead.
386 -- Case c) If the second-to-last IP is also a trusted proxy, it will also be ignored, iteratively, up to the last IP which isn’t in trusted proxies. 391 -- Case c) If the second-to-last IP is also a trusted proxy, it will also be ignored, iteratively, up to the last IP which isn’t in trusted proxies.
387 -- Case d) If all IPs are in trusted proxies, something went obviously wrong and the logic never overwrites `ip`, leaving it at the original request IP. 392 -- Case d) If all IPs are in trusted proxies, something went obviously wrong and the logic never overwrites `ip`, leaving it at the original request IP.
388 forwarded_for = forwarded_for..", "..ip; 393 forwarded_for = forwarded_for..", "..ip;
389 for forwarded_ip in forwarded_for:gmatch("[^%s,]+") do 394 for forwarded_ip in forwarded_for:gmatch("[^%s,]+") do
390 if not is_trusted_proxy(forwarded_ip) then 395 local trusted, err = is_trusted_proxy(forwarded_ip);
396 if err then
397 request.log("warn", "Could not parse forwarded connection details: %s");
398 elseif not trusted then
391 ip = forwarded_ip; 399 ip = forwarded_ip;
392 end 400 end
393 end 401 end
394 end 402 end
395 403