* HTTP Proxy:
- Put B32 instead of B64 in Host: header, saves 450 bytes - Eliminate some redundant lookups - Fix http://i2p/b64/ and /eepproxy/site/ requests - Disallow a port specified for an i2p address - Cleanup and comments
This commit is contained in:
@ -26,6 +26,7 @@ import net.i2p.I2PException;
|
|||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
import net.i2p.client.streaming.I2PSocketManager;
|
import net.i2p.client.streaming.I2PSocketManager;
|
||||||
import net.i2p.client.streaming.I2PSocketOptions;
|
import net.i2p.client.streaming.I2PSocketOptions;
|
||||||
|
import net.i2p.data.Base32;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
@ -46,8 +47,14 @@ import net.i2p.util.Translate;
|
|||||||
* $method http://i2p/$b64key/$path $protocolVersion
|
* $method http://i2p/$b64key/$path $protocolVersion
|
||||||
* or
|
* or
|
||||||
* $method /$site/$path $protocolVersion
|
* $method /$site/$path $protocolVersion
|
||||||
|
* or (deprecated)
|
||||||
|
* $method /eepproxy/$site/$path $protocolVersion
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
* Note that http://i2p/$b64key/... and /eepproxy/$site/... are not recommended
|
||||||
|
* in browsers or other user-visible applications, as relative links will not
|
||||||
|
* resolve correctly, cookies won't work, etc.
|
||||||
|
*
|
||||||
* If the $site resolves with the I2P naming service, then it is directed towards
|
* If the $site resolves with the I2P naming service, then it is directed towards
|
||||||
* that eepsite, otherwise it is directed towards this client's outproxy (typically
|
* that eepsite, otherwise it is directed towards this client's outproxy (typically
|
||||||
* "squid.i2p"). Only HTTP is supported (no HTTPS, ftp, mailto, etc). Both GET
|
* "squid.i2p"). Only HTTP is supported (no HTTPS, ftp, mailto, etc). Both GET
|
||||||
@ -303,14 +310,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
|
|
||||||
if (method == null) { // first line (GET /base64/realaddr)
|
if (method == null) { // first line (GET /base64/realaddr)
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug(getPrefix(requestId) + "Method is null for [" + line + "]");
|
_log.debug(getPrefix(requestId) + "First line [" + line + "]");
|
||||||
|
|
||||||
int pos = line.indexOf(" ");
|
int pos = line.indexOf(" ");
|
||||||
if (pos == -1) break;
|
if (pos == -1) break;
|
||||||
method = line.substring(0, pos);
|
method = line.substring(0, pos);
|
||||||
// TODO use Java URL class to make all this simpler and more robust
|
// TODO use Java URL class to make all this simpler and more robust
|
||||||
|
// That will also fix IPV6 [a:b:c]
|
||||||
String request = line.substring(pos + 1);
|
String request = line.substring(pos + 1);
|
||||||
if (request.startsWith("/") && getTunnel().getClientOptions().getProperty("i2ptunnel.noproxy") != null) {
|
if (request.startsWith("/") && getTunnel().getClientOptions().getProperty("i2ptunnel.noproxy") != null) {
|
||||||
|
// what is this for ???
|
||||||
request = "http://i2p" + request;
|
request = "http://i2p" + request;
|
||||||
} else if (request.startsWith("/eepproxy/")) {
|
} else if (request.startsWith("/eepproxy/")) {
|
||||||
// /eepproxy/foo.i2p/bar/baz.html HTTP/1.0
|
// /eepproxy/foo.i2p/bar/baz.html HTTP/1.0
|
||||||
@ -322,6 +331,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
}
|
}
|
||||||
// "http://" + "foo.i2p/bar/baz.html" + " HTTP/1.0"
|
// "http://" + "foo.i2p/bar/baz.html" + " HTTP/1.0"
|
||||||
request = "http://" + uri + subRequest.substring(protopos);
|
request = "http://" + uri + subRequest.substring(protopos);
|
||||||
|
} else if (request.toLowerCase().startsWith("http://i2p/")) {
|
||||||
|
// http://i2p/b64key/bar/baz.html HTTP/1.0
|
||||||
|
String subRequest = request.substring("http://i2p/".length());
|
||||||
|
int protopos = subRequest.indexOf(" ");
|
||||||
|
String uri = subRequest.substring(0, protopos);
|
||||||
|
if (uri.indexOf("/") == -1) {
|
||||||
|
uri = uri + "/";
|
||||||
|
}
|
||||||
|
// "http://" + "b64key/bar/baz.html" + " HTTP/1.0"
|
||||||
|
request = "http://" + uri + subRequest.substring(protopos);
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = request.indexOf("//");
|
pos = request.indexOf("//");
|
||||||
@ -334,6 +353,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
|
|
||||||
targetRequest = request;
|
targetRequest = request;
|
||||||
|
|
||||||
|
// pos is the start of the path
|
||||||
pos = request.indexOf("/");
|
pos = request.indexOf("/");
|
||||||
if (pos == -1) {
|
if (pos == -1) {
|
||||||
method = null;
|
method = null;
|
||||||
@ -354,9 +374,22 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host.toLowerCase().equals("proxy.i2p")) {
|
// Go through the various types of host names, set
|
||||||
|
// the host and destination variables accordingly,
|
||||||
|
// and transform the first line.
|
||||||
|
// For all i2p network hosts, ensure that the host is a
|
||||||
|
// Base 32 hostname so that we do not reveal our name for it
|
||||||
|
// in our addressbook (all naming is local),
|
||||||
|
// and it is removed from the request line.
|
||||||
|
|
||||||
|
if (host.length() >= 516 && host.indexOf(".") < 0) {
|
||||||
|
// http://b64key/bar/baz.html
|
||||||
|
destination = host;
|
||||||
|
host = getHostName(destination);
|
||||||
|
line = method + ' ' + request.substring(pos);
|
||||||
|
} else if (host.toLowerCase().equals("proxy.i2p")) {
|
||||||
// so we don't do any naming service lookups
|
// so we don't do any naming service lookups
|
||||||
destination = "proxy.i2p";
|
destination = host;
|
||||||
usingInternalServer = true;
|
usingInternalServer = true;
|
||||||
} else if (host.toLowerCase().endsWith(".i2p")) {
|
} else if (host.toLowerCase().endsWith(".i2p")) {
|
||||||
// Destination gets the host name
|
// Destination gets the host name
|
||||||
@ -482,6 +515,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug(getPrefix(requestId) + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
|
_log.debug(getPrefix(requestId) + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
|
||||||
} else {
|
} else {
|
||||||
|
// what is left for here? a hostname with no dots, and != "i2p"
|
||||||
|
// and not a destination ???
|
||||||
|
// Perhaps something in privatehosts.txt ...
|
||||||
request = request.substring(pos + 1);
|
request = request.substring(pos + 1);
|
||||||
pos = request.indexOf("/");
|
pos = request.indexOf("/");
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
@ -494,31 +530,49 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
destination = request.substring(0, pos);
|
destination = request.substring(0, pos);
|
||||||
|
host = getHostName(destination);
|
||||||
line = method + " " + request.substring(pos);
|
line = method + " " + request.substring(pos);
|
||||||
} // end host name processing
|
} // end host name processing
|
||||||
|
|
||||||
|
if (port != 80 && !usingWWWProxy) {
|
||||||
|
if (out != null) {
|
||||||
|
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
||||||
|
writeFooter(out);
|
||||||
|
}
|
||||||
|
s.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol);
|
boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol);
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "notValid(" + host + ")");
|
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "notValid(" + host + ")");
|
||||||
method = null;
|
method = null;
|
||||||
destination = null;
|
destination = null;
|
||||||
break;
|
break;
|
||||||
} else if ((!usingWWWProxy) && (!usingInternalServer)) {
|
|
||||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "host=getHostName(" + destination + ")");
|
|
||||||
host = getHostName(destination); // hide original host
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't do this, it forces yet another hostname lookup,
|
||||||
|
// and in all cases host was already set above
|
||||||
|
//if ((!usingWWWProxy) && (!usingInternalServer)) {
|
||||||
|
// String oldhost = host;
|
||||||
|
// host = getHostName(destination); // hide original host
|
||||||
|
// if (_log.shouldLog(Log.INFO))
|
||||||
|
// _log.info(getPrefix(requestId) + " oldhost " + oldhost + " newhost " + host + " dest " + destination);
|
||||||
|
//}
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
_log.debug(getPrefix(requestId) + "METHOD:" + method + ":");
|
_log.debug(getPrefix(requestId) + "METHOD: \"" + method + "\"");
|
||||||
_log.debug(getPrefix(requestId) + "PROTOC:" + protocol + ":");
|
_log.debug(getPrefix(requestId) + "PROTOC: \"" + protocol + "\"");
|
||||||
_log.debug(getPrefix(requestId) + "HOST :" + host + ":");
|
_log.debug(getPrefix(requestId) + "HOST : \"" + host + "\"");
|
||||||
_log.debug(getPrefix(requestId) + "DEST :" + destination + ":");
|
_log.debug(getPrefix(requestId) + "DEST : \"" + destination + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// end first line processing
|
// end first line processing
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (lowercaseLine.startsWith("host: ") && !usingWWWProxy) {
|
if (lowercaseLine.startsWith("host: ") && !usingWWWProxy) {
|
||||||
|
// Note that we only pass the original Host: line through to the outproxy
|
||||||
|
// But we don't create a Host: line if it wasn't sent to us
|
||||||
line = "Host: " + host;
|
line = "Host: " + host;
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info(getPrefix(requestId) + "Setting host = " + host);
|
_log.info(getPrefix(requestId) + "Setting host = " + host);
|
||||||
@ -575,7 +629,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
|
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
|
||||||
|
|
||||||
if (method == null || destination == null) {
|
if (method == null || destination == null) {
|
||||||
l.log("No HTTP method found in the request.");
|
//l.log("No HTTP method found in the request.");
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
if ("http://".equalsIgnoreCase(protocol))
|
if ("http://".equalsIgnoreCase(protocol))
|
||||||
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
||||||
@ -598,7 +652,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Destination clientDest = I2PTunnel.destFromName(destination);
|
// If the host is "i2p", the getHostName() lookup failed, don't try to
|
||||||
|
// look it up again as the naming service does not do negative caching
|
||||||
|
// so it will be slow.
|
||||||
|
|
||||||
|
Destination clientDest;
|
||||||
|
if ("i2p".equals(host))
|
||||||
|
clientDest = null;
|
||||||
|
else
|
||||||
|
clientDest = I2PTunnel.destFromName(destination);
|
||||||
|
|
||||||
if (clientDest == null) {
|
if (clientDest == null) {
|
||||||
//l.log("Could not resolve " + destination + ".");
|
//l.log("Could not resolve " + destination + ".");
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
@ -679,12 +742,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return b32hash.b32.i2p, or "i2p" on lookup failure.
|
||||||
|
* Prior to 0.7.12, returned b64 key
|
||||||
|
*/
|
||||||
private final static String getHostName(String host) {
|
private final static String getHostName(String host) {
|
||||||
if (host == null) return null;
|
if (host == null) return null;
|
||||||
|
if (host.length() == 60 && host.toLowerCase().endsWith(".b32.i2p"))
|
||||||
|
return host;
|
||||||
try {
|
try {
|
||||||
Destination dest = I2PTunnel.destFromName(host);
|
Destination dest = I2PTunnel.destFromName(host);
|
||||||
if (dest == null) return "i2p";
|
if (dest == null) return "i2p";
|
||||||
return dest.toBase64();
|
return Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
return "i2p";
|
return "i2p";
|
||||||
}
|
}
|
||||||
@ -858,8 +927,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
|
|
||||||
private final static String SUPPORTED_HOSTS[] = { "i2p", "www.i2p.com", "i2p."};
|
private final static String SUPPORTED_HOSTS[] = { "i2p", "www.i2p.com", "i2p."};
|
||||||
|
|
||||||
|
/** @param host ignored */
|
||||||
private static boolean isSupportedAddress(String host, String protocol) {
|
private static boolean isSupportedAddress(String host, String protocol) {
|
||||||
if ((host == null) || (protocol == null)) return false;
|
if ((host == null) || (protocol == null)) return false;
|
||||||
|
|
||||||
|
/****
|
||||||
|
* Let's not look up the name _again_
|
||||||
|
* and now that host is a b32, this was failing
|
||||||
|
*
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
String lcHost = host.toLowerCase();
|
String lcHost = host.toLowerCase();
|
||||||
for (int i = 0; i < SUPPORTED_HOSTS.length; i++) {
|
for (int i = 0; i < SUPPORTED_HOSTS.length; i++) {
|
||||||
@ -876,7 +951,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
|||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
return protocol.equalsIgnoreCase("http://");
|
return protocol.equalsIgnoreCase("http://");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
history.txt
24
history.txt
@ -1,3 +1,27 @@
|
|||||||
|
2010-02-27 zzz
|
||||||
|
* eepsite: Add some help to index.html
|
||||||
|
* HTTP Proxy:
|
||||||
|
- Put B32 instead of B64 in Host: header, saves 450 bytes
|
||||||
|
- Eliminate some redundant lookups
|
||||||
|
- Fix http://i2p/b64/ and /eepproxy/site/ requests
|
||||||
|
- Disallow a port specified for an i2p address
|
||||||
|
- Cleanup and comments
|
||||||
|
* i2psnark:
|
||||||
|
- Fix NPE after create file failure
|
||||||
|
- Sanitize more characters in file names
|
||||||
|
* netdb: Fix NPE after OOM http://trac.i2p2.i2p/ticket/38
|
||||||
|
* NTCP Transport:
|
||||||
|
- Replace lists with concurrent queues in EventPumper
|
||||||
|
and NTCPConnection to remove global locks
|
||||||
|
- Java 5 cleanup
|
||||||
|
* Plugins: Support console themes
|
||||||
|
* UDP Transport:
|
||||||
|
- Replace the unused-since-2006 TimedWeightedPriorityMessageQueue
|
||||||
|
with DummyThrottle
|
||||||
|
- Don't instantiate and start TWPMQ Cleaner and OutboundRefiller
|
||||||
|
threads, part of priority queues unused since 0.6.1.11
|
||||||
|
- Don't instantiate and start UDPFlooder, it is for testing only
|
||||||
|
|
||||||
2010-02-23 zzz
|
2010-02-23 zzz
|
||||||
* Unzip: Any files in the zip with a .jar.pack or .war.pack extension
|
* Unzip: Any files in the zip with a .jar.pack or .war.pack extension
|
||||||
will be transparently unpacked with unpack200. Savings is about 60%.
|
will be transparently unpacked with unpack200. Savings is about 60%.
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 5;
|
public final static long BUILD = 6;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user