All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.markusbernhardt.proxy.search.desktop.osx.OsxProxySearchStrategy Maven / Gradle / Ivy

package com.github.markusbernhardt.proxy.search.desktop.osx;

import java.io.File;
import java.io.IOException;
import java.net.NetworkInterface;
import java.net.ProxySelector;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

import com.github.markusbernhardt.proxy.ProxySearchStrategy;
import com.github.markusbernhardt.proxy.search.browser.ie.IELocalByPassFilter;
import com.github.markusbernhardt.proxy.search.wpad.WpadProxySearchStrategy;
import com.github.markusbernhardt.proxy.selector.direct.NoProxySelector;
import com.github.markusbernhardt.proxy.selector.fixed.FixedProxySelector;
import com.github.markusbernhardt.proxy.selector.fixed.FixedSocksSelector;
import com.github.markusbernhardt.proxy.selector.misc.ProtocolDispatchSelector;
import com.github.markusbernhardt.proxy.selector.whitelist.ProxyBypassListSelector;
import com.github.markusbernhardt.proxy.util.Logger;
import com.github.markusbernhardt.proxy.util.Logger.LogLevel;
import com.github.markusbernhardt.proxy.util.PListParser;
import com.github.markusbernhardt.proxy.util.PListParser.Dict;
import com.github.markusbernhardt.proxy.util.PListParser.XmlParseException;
import com.github.markusbernhardt.proxy.util.ProxyException;
import com.github.markusbernhardt.proxy.util.ProxyUtil;
import com.github.markusbernhardt.proxy.util.UriFilter;

/*****************************************************************************
 * Loads the OSX system proxy settings from the settings file.
 * 

* All settings are stored in OSX in a special XML file format. These settings * file are named plist files and contain nested dictionaries, arrays and * values. *

*

* To parse this file we use a parser that is derived from a plist parser that * comes with the xmlwise XML parser package: *

*

* http://code.google.com/p/xmlwise/ *

*

* I modified that parser to work with the default Java XML parsing library. *

*

* The plist file is located on OSX at: *

*

* /Library/Preferences/SystemConfiguration/preferences.plist *

* * @author Markus Bernhardt, Copyright 2016 * @author Bernd Rosstauscher, Copyright 2009 ****************************************************************************/ public class OsxProxySearchStrategy implements ProxySearchStrategy { public static final String OVERRIDE_SETTINGS_FILE = "com.github.markusbernhardt.proxy.osx.settingsFile"; public static final String OVERRIDE_ACCEPTED_DEVICES = "com.github.markusbernhardt.proxy.osx.acceptedDevices"; private static final String SETTINGS_FILE = "/Library/Preferences/SystemConfiguration/preferences.plist"; /************************************************************************* * ProxySelector * * @see java.net.ProxySelector#ProxySelector() ************************************************************************/ public OsxProxySearchStrategy() { super(); } /************************************************************************* * Loads the proxy settings and initializes a proxy selector for the OSX * proxy settings. * * @return a configured ProxySelector, null if none is found. * @throws ProxyException * on file reading error. ************************************************************************/ @Override public ProxySelector getProxySelector() throws ProxyException { Logger.log(getClass(), LogLevel.TRACE, "Detecting OSX proxy settings"); try { List acceptedInterfaces = getNetworkInterfaces(); Dict settings = PListParser.load(getSettingsFile()); Object currentSet = settings.getAtPath("/CurrentSet"); if (currentSet == null) { throw new ProxyException("CurrentSet not defined"); } Dict networkSet = (Dict) settings.getAtPath(String.valueOf(currentSet)); // TODO 30.03.2015 bros Test for IP6 compatibility List serviceOrder = (List) networkSet.getAtPath("/Network/Global/IPv4/ServiceOrder"); if (serviceOrder == null || serviceOrder.isEmpty()) { throw new ProxyException("ServiceOrder not defined"); } // Look at the Services in priority order and pick the first one // that was // also accepted above Dict proxySettings = null; for (int i = 0; i < serviceOrder.size() && proxySettings == null; i++) { Object candidateService = serviceOrder.get(i); Object networkService = networkSet.getAtPath("/Network/Service/" + candidateService + "/__LINK__"); if (networkService == null) { throw new ProxyException("NetworkService not defined."); } Dict selectedServiceSettings = (Dict) settings.getAtPath("" + networkService); String interfaceName = (String) selectedServiceSettings.getAtPath("/Interface/DeviceName"); if (acceptedInterfaces.contains(interfaceName)) { Logger.log(getClass(), LogLevel.TRACE, "Looking up proxies for device " + interfaceName); proxySettings = (Dict) selectedServiceSettings.getAtPath("/Proxies"); } } if (proxySettings == null) { return NoProxySelector.getInstance(); } return buildSelector(proxySettings); } catch (XmlParseException | IOException e) { throw new ProxyException(e); } } /************************************************************************* * Gets the printable name of the search strategy. * * @return the printable name of the search strategy ************************************************************************/ @Override public String getName() { return "osx"; } /************************************************************************* * Build a selector from the given settings. * * @param proxySettings * to parse * @return the configured selector * @throws ProxyException * on error ************************************************************************/ private ProxySelector buildSelector(Dict proxySettings) throws ProxyException { ProtocolDispatchSelector ps = new ProtocolDispatchSelector(); installSelectorForProtocol(proxySettings, ps, "HTTP"); installSelectorForProtocol(proxySettings, ps, "HTTPS"); installSelectorForProtocol(proxySettings, ps, "FTP"); installSelectorForProtocol(proxySettings, ps, "Gopher"); installSelectorForProtocol(proxySettings, ps, "RTSP"); installSocksProxy(proxySettings, ps); ProxySelector result = ps; result = installPacProxyIfAvailable(proxySettings, result); result = autodetectProxyIfAvailable(proxySettings, result); if (result != null) { result = installExceptionList(proxySettings, result); result = installSimpleHostFilter(proxySettings, result); } return result; } /************************************************************************* * Create a list of Ethernet interfaces that are connected * * @return a list of available interface names * @throws SocketException ************************************************************************/ private List getNetworkInterfaces() throws SocketException { String override = System.getProperty(OVERRIDE_ACCEPTED_DEVICES); if (override != null && override.length() > 0) { return Arrays.asList(override.split(";")); } List acceptedInterfaces = new ArrayList<>(); Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface ni = interfaces.nextElement(); if (isInterfaceAllowed(ni)) { acceptedInterfaces.add(ni.getName()); } } return acceptedInterfaces; } /************************************************************************* * Check if a given network interface is interesting for us. * * @param ni * the interface to check * @return true if accepted else false. * @throws SocketException * on error. ************************************************************************/ private boolean isInterfaceAllowed(NetworkInterface ni) throws SocketException { return !ni.isLoopback() && !ni.isPointToPoint() && // Not sure if we // should filter the // point to point // interfaces? !ni.isVirtual() && ni.isUp(); } /************************************************************************* * Gets the settings file to parse the settings from. * * @return the settings file. ************************************************************************/ private File getSettingsFile() { File result = new File(SETTINGS_FILE); String overrideFile = System.getProperty(OVERRIDE_SETTINGS_FILE); if (overrideFile != null) { return new File(overrideFile); } return result; } /************************************************************************* * Install a filter to ignore simple host names without domain name. * * @param proxySettings * the dictionary containing all settings * @param result * the proxy selector that needs to be adapted. * @return a wrapped proxy selector that will ignore simple names. ************************************************************************/ private ProxySelector installSimpleHostFilter(Dict proxySettings, ProxySelector result) { if (isActive(proxySettings.get("ExcludeSimpleHostnames"))) { List localBypassFilter = new ArrayList<>(); localBypassFilter.add(new IELocalByPassFilter()); result = new ProxyBypassListSelector(localBypassFilter, result); } return result; } /************************************************************************* * Install a host name base filter to handle the proxy exclude list. * * @param proxySettings * the dictionary containing all settings * @param result * the proxy selector that needs to be adapted. * @return a wrapped proxy selector that will handle the exclude list. ************************************************************************/ private ProxySelector installExceptionList(Dict proxySettings, ProxySelector result) { List proxyExceptions = (List) proxySettings.get("ExceptionsList"); if (proxyExceptions != null && !proxyExceptions.isEmpty()) { Logger.log(getClass(), LogLevel.TRACE, "OSX uses proxy bypass list: {}", proxyExceptions); String noProxyList = toCommaSeparatedString(proxyExceptions); result = new ProxyBypassListSelector(noProxyList, result); } return result; } /************************************************************************* * Convert a list to a comma separated list. * * @param proxyExceptions * list of elements. * @return a comma separated string of the list's content. ************************************************************************/ private String toCommaSeparatedString(List proxyExceptions) { StringBuilder result = new StringBuilder(); for (Object object : proxyExceptions) { if (result.length() > 0) { result.append(","); } result.append(object); } return result.toString(); } /************************************************************************* * Invoke WPAD proxy detection if configured. * * @param proxySettings * the settings to analyse. * @param result * the current proxy selector. * @return a WPAD proxy selector or the passed in proxy selector. * @throws ProxyException * on automatic detection errors. ************************************************************************/ private ProxySelector autodetectProxyIfAvailable(Dict proxySettings, ProxySelector result) throws ProxyException { if (isActive(proxySettings.get("ProxyAutoDiscoveryEnable"))) { ProxySelector wp = new WpadProxySearchStrategy().getProxySelector(); if (wp != null) { result = wp; } } return result; } /************************************************************************* * Use a PAC based proxy selector if configured. * * @param proxySettings * the settings to analyse. * @param result * the current proxy selector. * @return a PAC proxy selector or the passed in proxy selector. ************************************************************************/ private ProxySelector installPacProxyIfAvailable(Dict proxySettings, ProxySelector result) { if (isActive(proxySettings.get("ProxyAutoConfigEnable"))) { String url = (String) proxySettings.get("ProxyAutoConfigURLString"); result = ProxyUtil.buildPacSelectorForUrl(url); } return result; } /************************************************************************* * Build a socks proxy and set it for the socks protocol. * * @param proxySettings * to read the config values from. * @param ps * the ProtocolDispatchSelector to install the new proxy on. ************************************************************************/ private void installSocksProxy(Dict proxySettings, ProtocolDispatchSelector ps) { if (isActive(proxySettings.get("SOCKSEnable"))) { String proxyHost = (String) proxySettings.get("SOCKSProxy"); int proxyPort = (Integer) proxySettings.get("SOCKSPort"); ps.setSelector("socks", new FixedSocksSelector(proxyHost, proxyPort)); Logger.log(getClass(), LogLevel.TRACE, "OSX socks proxy is {}:{}", proxyHost, proxyPort); } } /************************************************************************* * Installs a proxy selector for the given protocoll on the * ProtocolDispatchSelector * * @param proxySettings * to read the config for the procotol from. * @param ps * the ProtocolDispatchSelector to install the new selector on. * @param protocol * to use. ************************************************************************/ private void installSelectorForProtocol(Dict proxySettings, ProtocolDispatchSelector ps, String protocol) { String prefix = protocol.trim(); if (isActive(proxySettings.get(prefix + "Enable"))) { String proxyHost = (String) proxySettings.get(prefix + "Proxy"); int proxyPort = (Integer) proxySettings.get(prefix + "Port"); FixedProxySelector fp = new FixedProxySelector(proxyHost, proxyPort); ps.setSelector(protocol.toLowerCase(), fp); Logger.log(getClass(), LogLevel.TRACE, "OSX uses for {} the proxy {}:{}", protocol, proxyHost, proxyPort); } } /************************************************************************* * Checks if the given value is set to "on". * * @param value * the value to test. * @return true if it is set else false. ************************************************************************/ private boolean isActive(Object value) { return Integer.valueOf(1).equals(value); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy