8 Commits

Author SHA1 Message Date
zzz
a6157ee8f5 set max jetty version 2011-12-31 15:13:56 +00:00
zzz
2a795f3d8a add throttle options 2011-09-12 20:36:04 +00:00
zzz
7a13998082 stub out announce-to-seedless 2011-09-12 19:57:43 +00:00
zzz
93a8e5bfd5 seedless fixes, untested 2011-09-12 15:46:19 +00:00
zzz
6e3b85ac97 0.5:
Final compact response format
2010-07-11 14:42:42 +00:00
zzz
48687daccc 0.4:
compact request/response support - may not be final format
Fix NPE if no ip parameter
2010-07-09 16:31:24 +00:00
zzz
66667de240 0.3: verify dest 2010-04-13 17:41:24 +00:00
zzz
eda5699f38 add xfs check 2010-04-12 22:01:50 +00:00
10 changed files with 143 additions and 21 deletions

View File

@ -11,7 +11,7 @@
<delete file="plugin/i2ptunnel.config" />
<!-- get version number -->
<buildnumber file="scripts/build.number" />
<property name="release.number" value="0.2" />
<property name="release.number" value="0.5" />
<!-- make the update xpi2p -->
<!-- this contains everything except i2ptunnel.config -->

View File

@ -8,6 +8,11 @@ tunnel.0.option.i2cp.reduceIdleTime=1200000
tunnel.0.option.i2cp.reduceOnIdle=true
tunnel.0.option.i2cp.reduceQuantity=1
tunnel.0.option.i2p.streaming.connectDelay=0
tunnel.0.option.i2p.streaming.maxConcurrentStreams=40
tunnel.0.option.i2p.streaming.maxConnsPerHour=100
tunnel.0.option.i2p.streaming.maxConnsPerMinute=10
tunnel.0.option.i2p.streaming.maxTotalConnsPerHour=2500
tunnel.0.option.i2p.streaming.maxTotalConnsPerMinute=60
tunnel.0.option.inbound.backupQuantity=0
tunnel.0.option.inbound.length=3
tunnel.0.option.inbound.lengthVariance=0

View File

@ -6,3 +6,4 @@ description=Open tracker
author=zzz
updateURL=http://stats.i2p/i2p/plugins/zzzot-update.xpi2p
license=Apache 2.0
max-jetty-version=5.99999

View File

@ -10,7 +10,7 @@
<pathelement location="${i2plib}/i2p.jar" />
<pathelement location="${i2plib}/i2ptunnel.jar" />
<pathelement location="${i2plib}/i2psnark.jar" />
<pathelement location="${i2plib}/routerconsole.jar" />
<pathelement location="${i2plib}/mstreaming.jar" />
<pathelement location="${jettylib}/ant.jar"/>
<pathelement location="${jettylib}/org.mortbay.jetty.jar"/>
<pathelement location="${jettylib}/jasper-compiler.jar" />
@ -34,7 +34,8 @@
srcdir="./java"
debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build/obj"
classpath="${i2plib}/i2p.jar:${i2plib}/i2ptunnel.jar:${i2plib}/i2psnark.jar:${i2plib}/systray.jar:${i2plib}/org.mortbay.jetty.jar" >
includeAntRuntime="false"
classpath="${i2plib}/i2p.jar:${i2plib}/i2ptunnel.jar:${i2plib}/i2psnark.jar:${i2plib}/mstreaming.jar:${i2plib}/systray.jar:${i2plib}/org.mortbay.jetty.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>
@ -70,6 +71,7 @@
destdir="build/war/WEB-INF/classes"
srcdir="./build/jspjava"
includes="**/*.java"
includeAntRuntime="false"
classpathref="jspcp"
failonerror="true" />

View File

@ -20,7 +20,10 @@ import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.crypto.SHA256Generator;
import net.i2p.data.Base64;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
@ -70,6 +73,17 @@ public class Peer extends HashMap<String, Object> {
return lastSeen;
}
/** convert b64.i2p to a Hash, then to a binary string */
/* or should we just store it in the constructor? cache it? */
public String getHash() {
String ip = (String) get("ip");
byte[] b = Base64.decode(ip.substring(0, ip.length() - 4));
Hash h = SHA256Generator.getInstance().calculateHash(b);
try {
return new String(h.getData(), "ISO-8859-1");
} catch (UnsupportedEncodingException uee) { return null; }
}
private static class Cleaner implements SimpleTimer.TimedEvent {
public void timeReached() {
destCache.clear();

View File

@ -0,0 +1,60 @@
package net.i2p.zzzot;
/*
* Copyright 2010 zzz (zzz@mail.i2p)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import java.io.IOException;
import java.io.OutputStream;
import net.i2p.I2PAppContext;
import net.i2p.client.streaming.I2PSocketEepGet;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.data.Base64;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.util.EepGet;
/**
* Announce to seedless
* @since 0.6
*/
public class SeedlessAnnouncer {
private static final String SPONGE =
"VG4Bd~q1RA3BdoF3z5fSR7p0xe1CTVgDMWVGyFchA9Wm2iXUkIR35G45XE31Uc9~IOt-ktNLL2~TYQZ13Vl8udosngDn8RJG1NtVASH4khsbgkkoFLWd6UuvuOjQKBFKjaEPJgxOzh0kxolRPPNHhFuuAGzNLKvz~LI2MTf0P6nwmRg1lBoRIUpSVocEHY4X306nT2VtY07FixbJcPCU~EeRin24yNoiZop-C3Wi1SGwJJK-NS7mnkNzd8ngDJXDJtR-wLP1vNyyBY6NySgqPiIhENHoVeXd5krlR42HORCxEDb4jhoqlbyJq-PrhTJ5HdH4-~gEq09B~~NIHzy7X02XgmBXhTYRtl6HbLMXs6SI5fq9OFgVp5YZWYUklJjMDI7jOrGrEZGSHhnJK9kT6D3CqVIM0cYEhe4ttmTegbZvC~J6DrRTIAX422qRQJBPsTUnv4iFyuJE-8SodP6ikTjRH21Qx73SxqOvmrOiu7Bsp0lvVDa84aoaYLdiGv87AAAA";
private static final String ANNOUNCE = "announce " + Base64.encode("seedless,eepsite,torrent");
public void announce(TunnelController controller) {
// get the I2PTunnel from the controller (no method now)
// get the I2PTunnelTask from I2PTunnel
// cast to an I2PTunnelServer
// get the SocketManager from the server (no method now)
I2PSocketManager mgr = null;
I2PAppContext ctx = I2PAppContext.getGlobalContext();
String url = "http://" + SPONGE + "/Seedless/seedless";
EepGet get = new I2PSocketEepGet(ctx, mgr, 1, -1, 1024, null, new DummyOutputStream(), url);
get.addHeader("X-Seedless", ANNOUNCE);
get.fetch();
}
private static class DummyOutputStream extends OutputStream {
public void write(int b) {}
}
}

View File

@ -100,6 +100,7 @@ public class ZzzOTController {
}
startJetty(pluginDir, dest);
startI2PTunnel(pluginDir, dest);
// SeedlessAnnouncer.announce(_tunnel);
}

View File

@ -28,6 +28,8 @@
// would be nice to make these configurable
final int MAX_RESPONSES = 25;
final int INTERVAL = 27*60;
final boolean ALLOW_IP_MISMATCH = false;
final boolean ALLOW_COMPACT_RESPONSE = true;
// so the chars will turn into bytes correctly
request.setCharacterEncoding("ISO-8859-1");
@ -47,14 +49,16 @@
String event = request.getParameter("event");
String ip = request.getParameter("ip");
String numwant = request.getParameter("numwant");
// ignored, use someday to enforce destination
String him = request.getHeader("X-I2P-DestB32");
boolean compact = ALLOW_COMPACT_RESPONSE && request.getParameter("compact") != null;
// use to enforce destination
String him = request.getHeader("X-I2P-DestB64");
String xff = request.getHeader("X-Forwarded-For");
String xfs = request.getHeader("X-Forwarded-Server");
boolean fail = false;
String msg = "bad announce";
if (xff != null) {
if (xff != null || xfs != null) {
fail = true;
msg = "Non-I2P access denied";
response.setStatus(403, msg);
@ -134,6 +138,14 @@
want = 0;
} catch (NumberFormatException nfe) {};
// spoof check
// if him == null, we are not using the I2P HTTP server tunnel, or something is wrong
boolean matchIP = ALLOW_IP_MISMATCH || him == null || ip == null || ip.equals(him);
if (want <= 0 && (!matchIP) && !fail) {
fail = true;
msg = "ip mismatch";
}
long left = 0;
if (!"completed".equals(event)) {
try {
@ -149,7 +161,7 @@
m.put("failure reason", msg);
} else if ("stopped".equals(event)) {
Peers peers = torrents.get(ih);
if (peers != null)
if (matchIP && peers != null)
peers.remove(pid);
m.put("interval", Integer.valueOf(INTERVAL));
} else {
@ -165,11 +177,16 @@
Peer p = peers.get(pid);
if (p == null) {
p = new Peer(pid.getData(), d);
Peer p2 = peers.putIfAbsent(pid, p);
if (p2 != null)
p = p2;
// don't add if spoofed
if (matchIP) {
Peer p2 = peers.putIfAbsent(pid, p);
if (p2 != null)
p = p2;
}
}
p.setLeft(left);
// don't update if spoofed
if (matchIP)
p.setLeft(left);
m.put("interval", Integer.valueOf(INTERVAL));
int size = peers.size();
@ -184,7 +201,19 @@
peerlist.remove(p); // them
if (want < size - 1) {
Collections.shuffle(peerlist);
m.put("peers", peerlist.subList(0, want));
peerlist = peerlist.subList(0, want);
}
if (compact) {
// old experimental way - list of hashes
//List<String> peerhashes = new ArrayList(peerlist.size());
//for (Peer pe : peerlist) {
// peerhashes.add(pe.getHash());
//}
// new way - one big string
byte[] peerhashes = new byte[32 * peerlist.size()];
for (int i = 0; i < peerlist.size(); i++)
System.arraycopy(peerlist.get(i).getHash().getBytes("ISO-8859-1"), 0, peerhashes, i * 32, 32);
m.put("peers", peerhashes);
} else {
m.put("peers", peerlist);
}

View File

@ -33,11 +33,12 @@
response.setHeader("Pragma", "no-cache");
String info_hash = request.getParameter("info_hash");
String xff = request.getHeader("X-Forwarded-For");
String xfs = request.getHeader("X-Forwarded-Server");
boolean fail = false;
String msg = "bad";
if (xff != null) {
if (xff != null || xfs != null) {
fail = true;
msg = "Non-I2P access denied";
response.setStatus(403, msg);

View File

@ -27,15 +27,18 @@
me = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b32.i2p";
// unused, we don't accept announces
String him = request.getHeader("X-I2P-DestB32");
if (him == null)
him = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b32.i2p";
String xff = request.getHeader("X-Forwarded-For");
String xfs = request.getHeader("X-Forwarded-Server");
response.setContentType("text/plain");
response.setHeader("X-Seedless", me);
response.setHeader("X-Seedless", him);
final int US_MINUTES = 360;
final int PEER_MINUTES = 60;
if (xff != null) {
if (xff != null || xfs != null) {
String msg = "Non-I2P access denied";
response.setStatus(403, msg);
out.println(msg);
@ -46,12 +49,17 @@
out.println("seedless " + US_MINUTES);
} else if (req.startsWith("announce")) {
out.println("thanks");
} else if (req.startsWith("locate")) {
} else if (req.startsWith("locate c2VlZGxlc")) { // locate b64(seedless)
// ignore the search string, if any, in the request
// us
out.println(Base64.encode(me + ' ' + US_MINUTES + " tracker"));
out.println(Base64.encode(me + ' ' + US_MINUTES + " seedless"));
out.println(Base64.encode(me + ' ' + US_MINUTES + " eepsite"));
} else if (req.startsWith("locate ZWVwc2l0Z")) { // locate b64(eepsite)
// ignore the search string, if any, in the request
// us
out.println(Base64.encode(me + ' ' + US_MINUTES + " zzzot"));
} else if (req.startsWith("locate dG9ycmVud")) { // locate b64(torrent)
// all the peers
Torrents torrents = ZzzOTController.getTorrents();
for (InfoHash ihash : torrents.keySet()) {
@ -67,19 +75,20 @@
// service type
String role;
if (p.isSeed())
role = " bt-seed";
role = "seed";
else
role = " bt-leech";
role = "leech";
// spg wants UTF-8 but all we have is binary data, so hex it
String ihs = DataHelper.toHexString(ihash.getData());
String ids = DataHelper.toHexString((byte[])p.get("peer id"));
out.println(Base64.encode(b32 + PEER_MINUTES + role +
" info_hash=" + ihs +
";peer_id=" + ids));
out.println(Base64.encode(b32 + PEER_MINUTES + ihs + '\n' +
ids + '\n' +
role));
}
}
} else {
// error code
response.setStatus(406, "Bad request");
out.println("SC_NOT_ACCEPTABLE");
}