Our network is behind a corporate proxy which requires us to properly configure our tools to access Internet.
For most of our CLI tools, we rely on the no_proxy environment variables to set the list of exclusions. Unfortunately, this variable (and the associated logic) does not support wildcard and can only contain a limited number of chars. That means that we can only whitelist some IP addresses and FQDN.
For Java-based tool, we use the system property http.nonProxyHosts which is much more convenient since it supports wildcard and regex.
Our Jenkins agents are executed in environment which contain the aforementioned environment variables, in a JVM with the corresponding system properties as well.
Some part of the remoting lib seems to give precedence to environment variables over system properties. Meaning that if the master IP address is in the system property but not in the env var, the agent will try to go through the proxy and timeout.
- Command: java -cp /path/to/remoting.jar hudson.remoting.jnlp.Main -headless -url http://172.17.0.1:8080 <agent_secret> <agent_name>
- System properties:
- Environment variables:
Agent connects to the master since its IP address is in the exclusion list defined by a system property which has precedence over the corresponding environment variable.
Agent successfully validates the provided credentials and checks that the master is up and running, but timeout when trying to open the JNLP channel.
ProxySelector.getDefault() resolves to sun.net.spi.DefaultProxySelector which is a basic helper to retrieve all available proxy connections defined with system properties and/or provided by the operating system.
The most important information of the Proxy object is its type which can either be:
- Type.DIRECT: direct connection to the URL without going through a proxy
- Type.HTTP: connection through a HTTP proxy
- Type.SOCKS: connection through a SOCK proxy
By default, a Proxy has a DIRECT type. The static variable Proxy.NO_PROXY is an alias to the default constructor.
In JnlpAgentEndpointResolver, when the returned proxy is of type DIRECT, the while loop is terminated: JnlpAgentEndpointResolver#338. When exiting the loop, no value has been assigned to targetAddress which is still equal to null.
At JnlpAgentEndpointResolver#354, the script fallbacks to the proxy environment variables if targetAddress is still null.
Unfortunately in our case, DefaultProxySelector.select() will return a unique proxy of type DIRECT because the system property http.nonProxyHosts does contain the URL in argument (172.17.0.1).
Even if you don't go through the entire logic of DefaultProxySelector.select(), it is fairly easy to draw general conclusion from this test: ProxySelector.getDefault().select(URI.create("http://172.17.0.1:80")) will return:
- Proxy.NO_PROXY when the system property is not set
- Proxy.NO_PROXY when the system property is http.nonProxyHosts=172.17.0.1
- "HTTP @ 200.xxx.xxx.xxx:80" when the system property is http.nonProxyHosts=127.0.0.1