Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/net/sdp/SdpProvider.java
32288 views
/*1* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.net.sdp;2627import sun.net.NetHooks;28import java.net.InetAddress;29import java.net.Inet4Address;30import java.net.UnknownHostException;31import java.util.*;32import java.io.File;33import java.io.FileDescriptor;34import java.io.IOException;35import java.io.PrintStream;36import java.security.AccessController;3738import sun.net.sdp.SdpSupport;39import sun.security.action.GetPropertyAction;4041/**42* A NetHooks provider that converts sockets from the TCP to SDP protocol prior43* to binding or connecting.44*/4546public class SdpProvider extends NetHooks.Provider {47// maximum port48private static final int MAX_PORT = 65535;4950// indicates if SDP is enabled and the rules for when the protocol is used51private final boolean enabled;52private final List<Rule> rules;5354// logging for debug purposes55private PrintStream log;5657public SdpProvider() {58// if this property is not defined then there is nothing to do.59String file = AccessController.doPrivileged(60new GetPropertyAction("com.sun.sdp.conf"));61if (file == null) {62this.enabled = false;63this.rules = null;64return;65}6667// load configuration file68List<Rule> list = null;69if (file != null) {70try {71list = loadRulesFromFile(file);72} catch (IOException e) {73fail("Error reading %s: %s", file, e.getMessage());74}75}7677// check if debugging is enabled78PrintStream out = null;79String logfile = AccessController.doPrivileged(80new GetPropertyAction("com.sun.sdp.debug"));81if (logfile != null) {82out = System.out;83if (logfile.length() > 0) {84try {85out = new PrintStream(logfile);86} catch (IOException ignore) { }87}88}8990this.enabled = !list.isEmpty();91this.rules = list;92this.log = out;93}9495// supported actions96private static enum Action {97BIND,98CONNECT;99}100101// a rule for matching a bind or connect request102private static interface Rule {103boolean match(Action action, InetAddress address, int port);104}105106// rule to match port[-end]107private static class PortRangeRule implements Rule {108private final Action action;109private final int portStart;110private final int portEnd;111PortRangeRule(Action action, int portStart, int portEnd) {112this.action = action;113this.portStart = portStart;114this.portEnd = portEnd;115}116Action action() {117return action;118}119@Override120public boolean match(Action action, InetAddress address, int port) {121return (action == this.action &&122port >= this.portStart &&123port <= this.portEnd);124}125}126127// rule to match address[/prefix] port[-end]128private static class AddressPortRangeRule extends PortRangeRule {129private final byte[] addressAsBytes;130private final int prefixByteCount;131private final byte mask;132AddressPortRangeRule(Action action, InetAddress address,133int prefix, int port, int end)134{135super(action, port, end);136this.addressAsBytes = address.getAddress();137this.prefixByteCount = prefix >> 3;138this.mask = (byte)(0xff << (8 - (prefix % 8)));139}140@Override141public boolean match(Action action, InetAddress address, int port) {142if (action != action())143return false;144byte[] candidate = address.getAddress();145// same address type?146if (candidate.length != addressAsBytes.length)147return false;148// check bytes149for (int i=0; i<prefixByteCount; i++) {150if (candidate[i] != addressAsBytes[i])151return false;152}153// check remaining bits154if ((prefixByteCount < addressAsBytes.length) &&155((candidate[prefixByteCount] & mask) !=156(addressAsBytes[prefixByteCount] & mask)))157return false;158return super.match(action, address, port);159}160}161162// parses port:[-end]163private static int[] parsePortRange(String s) {164int pos = s.indexOf('-');165try {166int[] result = new int[2];167if (pos < 0) {168boolean all = s.equals("*");169result[0] = all ? 0 : Integer.parseInt(s);170result[1] = all ? MAX_PORT : result[0];171} else {172String low = s.substring(0, pos);173if (low.length() == 0) low = "*";174String high = s.substring(pos+1);175if (high.length() == 0) high = "*";176result[0] = low.equals("*") ? 0 : Integer.parseInt(low);177result[1] = high.equals("*") ? MAX_PORT : Integer.parseInt(high);178}179return result;180} catch (NumberFormatException e) {181return new int[0];182}183}184185private static void fail(String msg, Object... args) {186Formatter f = new Formatter();187f.format(msg, args);188throw new RuntimeException(f.out().toString());189}190191// loads rules from the given file192// Each non-blank/non-comment line must have the format:193// ("bind" | "connect") 1*LWSP-char (hostname | ipaddress["/" prefix])194// 1*LWSP-char ("*" | port) [ "-" ("*" | port) ]195private static List<Rule> loadRulesFromFile(String file)196throws IOException197{198Scanner scanner = new Scanner(new File(file));199try {200List<Rule> result = new ArrayList<Rule>();201while (scanner.hasNextLine()) {202String line = scanner.nextLine().trim();203204// skip blank lines and comments205if (line.length() == 0 || line.charAt(0) == '#')206continue;207208// must have 3 fields209String[] s = line.split("\\s+");210if (s.length != 3) {211fail("Malformed line '%s'", line);212continue;213}214215// first field is the action ("bind" or "connect")216Action action = null;217for (Action a: Action.values()) {218if (s[0].equalsIgnoreCase(a.name())) {219action = a;220break;221}222}223if (action == null) {224fail("Action '%s' not recognized", s[0]);225continue;226}227228// * port[-end]229int[] ports = parsePortRange(s[2]);230if (ports.length == 0) {231fail("Malformed port range '%s'", s[2]);232continue;233}234235// match all addresses236if (s[1].equals("*")) {237result.add(new PortRangeRule(action, ports[0], ports[1]));238continue;239}240241// hostname | ipaddress[/prefix]242int pos = s[1].indexOf('/');243try {244if (pos < 0) {245// hostname or ipaddress (no prefix)246InetAddress[] addresses = InetAddress.getAllByName(s[1]);247for (InetAddress address: addresses) {248int prefix =249(address instanceof Inet4Address) ? 32 : 128;250result.add(new AddressPortRangeRule(action, address,251prefix, ports[0], ports[1]));252}253} else {254// ipaddress/prefix255InetAddress address = InetAddress256.getByName(s[1].substring(0, pos));257int prefix = -1;258try {259prefix = Integer.parseInt(s[1].substring(pos+1));260if (address instanceof Inet4Address) {261// must be 1-31262if (prefix < 0 || prefix > 32) prefix = -1;263} else {264// must be 1-128265if (prefix < 0 || prefix > 128) prefix = -1;266}267} catch (NumberFormatException e) {268}269270if (prefix > 0) {271result.add(new AddressPortRangeRule(action,272address, prefix, ports[0], ports[1]));273} else {274fail("Malformed prefix '%s'", s[1]);275continue;276}277}278} catch (UnknownHostException uhe) {279fail("Unknown host or malformed IP address '%s'", s[1]);280continue;281}282}283return result;284} finally {285scanner.close();286}287}288289// converts unbound TCP socket to a SDP socket if it matches the rules290private void convertTcpToSdpIfMatch(FileDescriptor fdObj,291Action action,292InetAddress address,293int port)294throws IOException295{296boolean matched = false;297for (Rule rule: rules) {298if (rule.match(action, address, port)) {299SdpSupport.convertSocket(fdObj);300matched = true;301break;302}303}304if (log != null) {305String addr = (address instanceof Inet4Address) ?306address.getHostAddress() : "[" + address.getHostAddress() + "]";307if (matched) {308log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port);309} else {310log.format("%s to %s:%d (no match)\n", action, addr, port);311}312}313}314315@Override316public void implBeforeTcpBind(FileDescriptor fdObj,317InetAddress address,318int port)319throws IOException320{321if (enabled)322convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port);323}324325@Override326public void implBeforeTcpConnect(FileDescriptor fdObj,327InetAddress address,328int port)329throws IOException330{331if (enabled)332convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port);333}334}335336337