Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java
41137 views
1
/*
2
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.net.sdp;
27
28
import sun.net.NetHooks;
29
import java.net.InetAddress;
30
import java.net.Inet4Address;
31
import java.net.UnknownHostException;
32
import java.util.*;
33
import java.io.File;
34
import java.io.FileDescriptor;
35
import java.io.IOException;
36
import java.io.PrintStream;
37
38
import sun.net.sdp.SdpSupport;
39
import sun.security.action.GetPropertyAction;
40
41
/**
42
* A NetHooks provider that converts sockets from the TCP to SDP protocol prior
43
* to binding or connecting.
44
*/
45
46
public class SdpProvider extends NetHooks.Provider {
47
// maximum port
48
private static final int MAX_PORT = 65535;
49
50
// indicates if SDP is enabled and the rules for when the protocol is used
51
private final boolean enabled;
52
private final List<Rule> rules;
53
54
// logging for debug purposes
55
private PrintStream log;
56
57
public SdpProvider() {
58
Properties props = GetPropertyAction.privilegedGetProperties();
59
// if this property is not defined then there is nothing to do.
60
String file = props.getProperty("com.sun.sdp.conf");
61
if (file == null) {
62
this.enabled = false;
63
this.rules = null;
64
return;
65
}
66
67
// load configuration file
68
List<Rule> list = null;
69
try {
70
list = loadRulesFromFile(file);
71
} catch (IOException e) {
72
fail("Error reading %s: %s", file, e.getMessage());
73
}
74
75
// check if debugging is enabled
76
PrintStream out = null;
77
String logfile = props.getProperty("com.sun.sdp.debug");
78
if (logfile != null) {
79
out = System.out;
80
if (!logfile.isEmpty()) {
81
try {
82
out = new PrintStream(logfile);
83
} catch (IOException ignore) { }
84
}
85
}
86
87
this.enabled = !list.isEmpty();
88
this.rules = list;
89
this.log = out;
90
}
91
92
// supported actions
93
private static enum Action {
94
BIND,
95
CONNECT;
96
}
97
98
// a rule for matching a bind or connect request
99
private static interface Rule {
100
boolean match(Action action, InetAddress address, int port);
101
}
102
103
// rule to match port[-end]
104
private static class PortRangeRule implements Rule {
105
private final Action action;
106
private final int portStart;
107
private final int portEnd;
108
PortRangeRule(Action action, int portStart, int portEnd) {
109
this.action = action;
110
this.portStart = portStart;
111
this.portEnd = portEnd;
112
}
113
Action action() {
114
return action;
115
}
116
@Override
117
public boolean match(Action action, InetAddress address, int port) {
118
return (action == this.action &&
119
port >= this.portStart &&
120
port <= this.portEnd);
121
}
122
}
123
124
// rule to match address[/prefix] port[-end]
125
private static class AddressPortRangeRule extends PortRangeRule {
126
private final byte[] addressAsBytes;
127
private final int prefixByteCount;
128
private final byte mask;
129
AddressPortRangeRule(Action action, InetAddress address,
130
int prefix, int port, int end)
131
{
132
super(action, port, end);
133
this.addressAsBytes = address.getAddress();
134
this.prefixByteCount = prefix >> 3;
135
this.mask = (byte)(0xff << (8 - (prefix % 8)));
136
}
137
@Override
138
public boolean match(Action action, InetAddress address, int port) {
139
if (action != action())
140
return false;
141
byte[] candidate = address.getAddress();
142
// same address type?
143
if (candidate.length != addressAsBytes.length)
144
return false;
145
// check bytes
146
for (int i=0; i<prefixByteCount; i++) {
147
if (candidate[i] != addressAsBytes[i])
148
return false;
149
}
150
// check remaining bits
151
if ((prefixByteCount < addressAsBytes.length) &&
152
((candidate[prefixByteCount] & mask) !=
153
(addressAsBytes[prefixByteCount] & mask)))
154
return false;
155
return super.match(action, address, port);
156
}
157
}
158
159
// parses port:[-end]
160
private static int[] parsePortRange(String s) {
161
int pos = s.indexOf('-');
162
try {
163
int[] result = new int[2];
164
if (pos < 0) {
165
boolean all = s.equals("*");
166
result[0] = all ? 0 : Integer.parseInt(s);
167
result[1] = all ? MAX_PORT : result[0];
168
} else {
169
String low = s.substring(0, pos);
170
if (low.isEmpty()) low = "*";
171
String high = s.substring(pos+1);
172
if (high.isEmpty()) high = "*";
173
result[0] = low.equals("*") ? 0 : Integer.parseInt(low);
174
result[1] = high.equals("*") ? MAX_PORT : Integer.parseInt(high);
175
}
176
return result;
177
} catch (NumberFormatException e) {
178
return new int[0];
179
}
180
}
181
182
private static void fail(String msg, Object... args) {
183
Formatter f = new Formatter();
184
f.format(msg, args);
185
throw new RuntimeException(f.out().toString());
186
}
187
188
// loads rules from the given file
189
// Each non-blank/non-comment line must have the format:
190
// ("bind" | "connect") 1*LWSP-char (hostname | ipaddress["/" prefix])
191
// 1*LWSP-char ("*" | port) [ "-" ("*" | port) ]
192
private static List<Rule> loadRulesFromFile(String file)
193
throws IOException
194
{
195
Scanner scanner = new Scanner(new File(file));
196
try {
197
List<Rule> result = new ArrayList<>();
198
while (scanner.hasNextLine()) {
199
String line = scanner.nextLine().trim();
200
201
// skip blank lines and comments
202
if (line.isEmpty() || line.charAt(0) == '#')
203
continue;
204
205
// must have 3 fields
206
String[] s = line.split("\\s+");
207
if (s.length != 3) {
208
fail("Malformed line '%s'", line);
209
continue;
210
}
211
212
// first field is the action ("bind" or "connect")
213
Action action = null;
214
for (Action a: Action.values()) {
215
if (s[0].equalsIgnoreCase(a.name())) {
216
action = a;
217
break;
218
}
219
}
220
if (action == null) {
221
fail("Action '%s' not recognized", s[0]);
222
continue;
223
}
224
225
// * port[-end]
226
int[] ports = parsePortRange(s[2]);
227
if (ports.length == 0) {
228
fail("Malformed port range '%s'", s[2]);
229
continue;
230
}
231
232
// match all addresses
233
if (s[1].equals("*")) {
234
result.add(new PortRangeRule(action, ports[0], ports[1]));
235
continue;
236
}
237
238
// hostname | ipaddress[/prefix]
239
int pos = s[1].indexOf('/');
240
try {
241
if (pos < 0) {
242
// hostname or ipaddress (no prefix)
243
InetAddress[] addresses = InetAddress.getAllByName(s[1]);
244
for (InetAddress address: addresses) {
245
int prefix =
246
(address instanceof Inet4Address) ? 32 : 128;
247
result.add(new AddressPortRangeRule(action, address,
248
prefix, ports[0], ports[1]));
249
}
250
} else {
251
// ipaddress/prefix
252
InetAddress address = InetAddress
253
.getByName(s[1].substring(0, pos));
254
int prefix = -1;
255
try {
256
prefix = Integer.parseInt(s[1], pos + 1,
257
s[1].length(), 10);
258
if (address instanceof Inet4Address) {
259
// must be 1-31
260
if (prefix < 0 || prefix > 32) prefix = -1;
261
} else {
262
// must be 1-128
263
if (prefix < 0 || prefix > 128) prefix = -1;
264
}
265
} catch (NumberFormatException e) {
266
}
267
268
if (prefix > 0) {
269
result.add(new AddressPortRangeRule(action,
270
address, prefix, ports[0], ports[1]));
271
} else {
272
fail("Malformed prefix '%s'", s[1]);
273
continue;
274
}
275
}
276
} catch (UnknownHostException uhe) {
277
fail("Unknown host or malformed IP address '%s'", s[1]);
278
continue;
279
}
280
}
281
return result;
282
} finally {
283
scanner.close();
284
}
285
}
286
287
// converts unbound TCP socket to a SDP socket if it matches the rules
288
private void convertTcpToSdpIfMatch(FileDescriptor fdObj,
289
Action action,
290
InetAddress address,
291
int port)
292
throws IOException
293
{
294
boolean matched = false;
295
for (Rule rule: rules) {
296
if (rule.match(action, address, port)) {
297
SdpSupport.convertSocket(fdObj);
298
matched = true;
299
break;
300
}
301
}
302
if (log != null) {
303
String addr = (address instanceof Inet4Address) ?
304
address.getHostAddress() : "[" + address.getHostAddress() + "]";
305
if (matched) {
306
log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port);
307
} else {
308
log.format("%s to %s:%d (no match)\n", action, addr, port);
309
}
310
}
311
}
312
313
@Override
314
public void implBeforeTcpBind(FileDescriptor fdObj,
315
InetAddress address,
316
int port)
317
throws IOException
318
{
319
if (enabled)
320
convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port);
321
}
322
323
@Override
324
public void implBeforeTcpConnect(FileDescriptor fdObj,
325
InetAddress address,
326
int port)
327
throws IOException
328
{
329
if (enabled)
330
convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port);
331
}
332
}
333
334