GitLab HTTP_V2 Client Ignores Proxy Configuration During DNS Resolution for License Activation
Summary
GitLab's Gitlab::HTTP_V2::UrlBlocker performs DNS resolution for customers.gitlab.com despite correctly detecting proxy configuration, causing license activation to fail with "execution expired" timeout in proxy environments with restricted DNS resolution.
Can access customers.gitlab.com outside of GitLab via curl.
Environment
- GitLab Version: 18.3.0 EE (Omnibus)
- Operating System: RedHat Enterprise 8.10
- Network: Corporate proxy environment with restricted DNS resolution
Expected Behavior
When proxy environment variables are correctly configured and detected (uri_under_proxy_setting? returns true), GitLab should:
- Skip DNS resolution for external domains
- Use the configured proxy for all HTTP requests to
customers.gitlab.com - Allow the proxy to handle DNS resolution
Actual Behavior
Despite correct proxy detection, GitLab attempts DNS resolution for customers.gitlab.com before using the proxy, causing a 15-second timeout when internal DNS servers cannot resolve external domains.
Steps to Reproduce
-
Configure GitLab in a corporate environment with:
- HTTP proxy configured via environment variables
- Internal DNS servers that cannot resolve external domains
- Proxy correctly configured and working for other traffic
-
Set proxy environment variables:
gitlab_rails['env'] = { 'http_proxy' => 'http://proxy.company.com:80', 'https_proxy' => 'http://proxy.company.com:80', 'no_proxy' => 'company.com,localhost' } -
Verify proxy detection works:
# Test the proxy detection logicuri = URI('https://customers.gitlab.com/graphql')\ puts "URI: #{uri}"\ puts "Hostname: #{uri.hostname}"\ puts "Port: #{uri.port}"Output:URI: https://customers.gitlab.com/graphqlHostname: customers.gitlab.comPort: 443# Check environment variablesputs "\n=== Environment Variables ==="\ %w[http_proxy https_proxy HTTP_PROXY HTTPS_PROXY].each do |var|\ puts "#{var}: #{ENV[var] || 'NOT SET'}"\ endputs "no_proxy: #{ENV['no_proxy'] || 'NOT SET'}"\ puts "NO_PROXY: #{ENV['NO_PROXY'] || 'NOT SET'}"Output:http_proxy: http://<proxy>:80https_proxy: http://<proxy>80HTTP_PROXY: http://<proxy>:80HTTPS_PROXY: http://<proxy>:80=> ["http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY"]no_proxy: domain.de,localhostNO_PROXY: domain.de,localhost# Test GitLab's proxy detectionputs "\n=== GitLab Proxy Detection ==="\ puts "http_proxy_env?: #{Gitlab::HTTP_V2::UrlBlocker.send(:http_proxy_env?)}"\ puts "no_proxy_env: #{Gitlab::HTTP_V2::UrlBlocker.send(:no_proxy_env)}"Output:http_proxy_env?: trueno_proxy_env: domain.de,localhost# Test URI proxy logicno_proxy = Gitlab::HTTP_V2::UrlBlocker.send(:no_proxy_env)\ if no_proxy\ puts "use_proxy? result: #{::URI::Generic.use_proxy?(uri.hostname, nil, uri.port, no_proxy)}"\ endOutput:use_proxy? result: true# Test the full proxy detectionputs "uri_under_proxy_setting?: #{Gitlab::HTTP_V2::UrlBlocker.send(:uri_under_proxy_setting?, uri, nil)}"Output:uri_under_proxy_setting?: true -
Attempt license activation:
gitlab-rails runner "GitlabSubscriptions::ActivateService.new.execute('ACTIVATION_CODE')" -
Observe timeout error:
Gitlab::HTTP_V2::BlockedUrlError: URL is blocked: execution expired
Evidence
Network Traffic Analysis (tcpdump)
The tcpdump shows the problematic behavior:
`# DNS queries being made despite proxy configuration 08:56:37.640836 IP GITLAB_HOST.PORT > DNS_SERVER.domain: 42847+ A? customers.gitlab.com. (38) 08:56:37.640840 IP GITLAB_HOST.PORT > DNS_SERVER.domain: 22365+ AAAA? customers.gitlab.com. (38)
Successful proxy usage for other domains
08:56:36.732646 IP GITLAB_HOST.PORT > PROXY_SERVER.http: HTTP: CONNECT example-domain.com:443 HTTP/1.1 08:56:36.738915 IP PROXY_SERVER.http > GITLAB_HOST.PORT: HTTP: HTTP/1.1 200 Connection Established `
Proxy Detection Verification
# All proxy detection logic works correctly http_proxy_env?: true no_proxy_env: company.com,localhost use_proxy? result: true uri_under_proxy_setting?: true
Root Cause Analysis
The issue is in gems/gitlab-http/lib/gitlab/http_v2/url_blocker.rb in the get_address_info method:
def get_address_info(uri) Timeout.timeout(GETADDRINFO_TIMEOUT_SECONDS) do # 15 seconds Addrinfo.getaddrinfo(uri.hostname, get_port(uri), nil, :STREAM) end rescue Timeout::Error => e raise Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError, e.message # "execution expired" end
This method is called from validate_resolved_uri even when uri_under_proxy_setting? returns true, indicating that DNS resolution should be bypassed when using a proxy.
Code Location
-
File:
gems/gitlab-http/lib/gitlab/http_v2/url_blocker.rb -
Method:
get_address_info(line ~218) -
Called from:
validate_resolved_uri(line ~123)
Workaround
Adding customers.gitlab.com to /etc/hosts bypasses the DNS resolution issue:
echo "104.18.36.112 customers.gitlab.com" >> /etc/hosts gitlab-rails runner "GitlabSubscriptions::ActivateService.new.execute('ACTIVATION_CODE')" sed -i '/customers.gitlab.com/d' /etc/hosts
Proposed Fix
According to GitLab DUO the validate_resolved_uri method should check if a proxy is being used before attempting DNS resolution:
`def validate_resolved_uri(uri, ...)
Skip DNS resolution if proxy is configured and should be used
proxy_in_use = uri_under_proxy_setting?(uri, nil)
if proxy_in_use return Result.new(uri, nil, proxy_in_use) end
Continue with existing DNS resolution logic...
begin address_info = get_address_info(uri) rescue SocketError # existing error handling... end end `
Impact
- Severity: High - Blocks license activation in corporate proxy environments
- Affected Users: Customers with proxy configurations and restricted DNS resolution
-
Workaround Available: Yes (manual
/etc/hostsentry)
Related Issues
This appears related to issue Skip DNS rebinding protection when HTTP_PROXY environment is set which was closed in GitLab 15.11, but the fix may not cover all code paths or may have regressed.
Additional Information
- The issue affects specifically the license activation flow via
GitlabSubscriptions::ActivateService - Other HTTP traffic correctly uses the proxy (as evidenced by tcpdump)
- The proxy detection logic works correctly - the issue is that DNS resolution happens regardless of proxy detection results