Compare commits

...

15 Commits

Author SHA1 Message Date
8b38d4481b Test SOCKS4 client: connect with faulty Socket 2021-01-22 22:23:02 +01:00
cce39bb35c Test SOCKS4 client: connect using mocked Socket 2021-01-22 22:16:48 +01:00
6a841fced5 Test SOCKS4 client: CONNECTION_REFUSED when connecting 2021-01-22 21:43:22 +01:00
d614fa6cbd Test SOCKS4 client: refactor IPv6 test
We don't need to test the response data since we expect an exception anyway
2021-01-22 21:42:49 +01:00
472f2776fb Test SOCKS4 client: no response to connect 2021-01-22 21:34:41 +01:00
3cdffcfa4c Test SOCKS4 client: connect to host over proxy 2021-01-22 21:17:49 +01:00
0273ecaa9c Test SOCKS4 client: IPv6 expected failure
IPv6 isn't supported
2021-01-22 20:50:23 +01:00
a79a98f1d0 Test SOCKS4 client: IPv4 success 2021-01-22 20:49:46 +01:00
zzz
f71e59a049 Merge branch 'test-convert' into 'master'
Test net.i2p.util.ConvertToHash

See merge request i2p-hackers/i2p.i2p!13
2021-01-20 14:38:37 +00:00
169fb59d7d test: fix I2PSocketExceptionTest::testUnknownStatus
In non-English environments, the message is translated.
2021-01-20 14:38:37 +00:00
zzz
922178b2c7 SSU: Fix deadlock with router restart
http://zzz.i2p/topics/3036
2021-01-20 09:27:55 -05:00
zzz
74a9193ba5 Console: Fix link to UPnP status 2021-01-20 09:25:58 -05:00
idk
335409f1d2 Find and fix the bug which appears in 'https://old.reddit.com/r/i2p/search?q=console&restrict_sr=on&sort=relevance&t=all' a bunch of Reddit posts, due to a mistake in the Firefox Profile Installer which expected router.config to be in the (deprecated)Roaming application data, even though it was in the Local Application Data, and if it did not exist, created it. If the (deprecated)Roaming application data directory had a router.config file, then I2P attempted to use the Roaming application directory, and the user could end up with a router that had no client apps configured, resulting in a poor UX 2021-01-18 00:26:33 -05:00
idk
d6edb9e96c Merge branch 'gitlab-ci' into 'master'
Tests on Gitlab CI

See merge request i2p-hackers/i2p.i2p!12
2021-01-17 23:10:34 +00:00
f150855f1c test: fix I2PSocketExceptionTest::testUnknownStatus
In non-English environments, the message is translated.
2021-01-17 23:10:34 +00:00
9 changed files with 321 additions and 10 deletions

24
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,24 @@
image: openjdk:8-alpine
stages:
- test
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- .gradle
test:
stage: test
coverage: '/Total.*?([0-9]{1,3})%/'
before_script:
- apk add --no-cache grep
script:
- ./gradlew codeCoverageReport
# The actual output that will be parsed by the code coverage
- grep -oP "Total.*?%" build/reports/jacoco/html/index.html
only:
- merge_requests
- tags

View File

@@ -60,6 +60,6 @@ public class I2PSocketExceptionTest {
public void testUnknownStatus() {
I2PSocketException e = new I2PSocketException(255);
assertThat(e.getStatus(), is(255));
assertThat(e.getMessage(), is("Failure code: 255"));
assertThat(e.getMessage(), endsWith(": 255"));
}
}

View File

@@ -46,7 +46,7 @@
</td>
</tr>
<tr>
<th id="upnpconfig"><%=intl._t("UPnP Configuration")%>&nbsp;<a href="peers#upnp">[<%=intl._t("UPnP Status")%>]</a></th>
<th id="upnpconfig"><%=intl._t("UPnP Configuration")%>&nbsp;<a href="peers?tx=upnp">[<%=intl._t("UPnP Status")%>]</a></th>
</tr>
<tr>
<td>

View File

@@ -0,0 +1,164 @@
package net.i2p.socks;
import org.junit.Test;
import org.mockito.Mockito;
import sun.net.util.IPAddressUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import static net.i2p.socks.SOCKS4Constants.SOCKS_VERSION_4;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThrows;
public class SOCKS4ClientTest {
/**
* A successful connection to an IPv4 host
*/
@Test
public void connect() throws IOException {
_testConnect(false);
}
/**
* A successful connection to an IPv4 host using a socket
*/
@Test
public void connect__withSocket() throws IOException {
_testConnect(true);
}
private void _testConnect(boolean useSocket) throws IOException {
String hostIPv4 = "11.22.33.44";
int connectionPort = 8080;
byte[] hostIPv4Bin = IPAddressUtil.textToNumericFormatV4(hostIPv4);
// Build sequence of bytes to be expected
ByteArrayOutputStream expectedByteStream = new ByteArrayOutputStream();
DataOutputStream writerStream = new DataOutputStream(expectedByteStream);
writerStream.writeByte(SOCKS_VERSION_4);
writerStream.writeByte(SOCKS4Constants.Command.CONNECT);
writerStream.writeShort(connectionPort);
writerStream.write(hostIPv4Bin);
writerStream.write((byte) 0);
ByteArrayInputStream ips = new ByteArrayInputStream(new byte[]{
0, // dummy
SOCKS4Constants.Reply.SUCCEEDED, // Connection succeeded
0, 0, 0, 0, 0, 0 // filler
});
ByteArrayOutputStream ops = new ByteArrayOutputStream();
// Test overloaded function
if (useSocket) {
Socket socket = Mockito.mock(Socket.class);
Mockito.when(socket.getInputStream()).thenReturn(ips);
Mockito.when(socket.getOutputStream()).thenReturn(ops);
SOCKS4Client.connect(socket, hostIPv4, connectionPort);
} else {
SOCKS4Client.connect(ips, ops, hostIPv4, connectionPort);
}
assertArrayEquals(expectedByteStream.toByteArray(), ops.toByteArray());
}
/**
* Connect proxy with a domain name
*/
@Test
public void connect__host() throws IOException {
String host = "stats.i2p";
int connectionPort = 80;
// Build sequence of bytes to be expected
ByteArrayOutputStream expectedByteStream = new ByteArrayOutputStream();
DataOutputStream writerStream = new DataOutputStream(expectedByteStream);
writerStream.writeByte(SOCKS_VERSION_4);
writerStream.writeByte(SOCKS4Constants.Command.CONNECT);
writerStream.writeShort(connectionPort);
writerStream.write(new byte[]{0,0,0,1}); // 0.0.0.1
writerStream.write((byte) 0); // empty userID
writerStream.write(host.getBytes(StandardCharsets.ISO_8859_1));
writerStream.write((byte) 0);
ByteArrayInputStream ips = new ByteArrayInputStream(new byte[]{
0, // dummy
SOCKS4Constants.Reply.SUCCEEDED, // Connection succeeded
0, 0, 0, 0, 0, 0 // filler
});
ByteArrayOutputStream ops = new ByteArrayOutputStream();
SOCKS4Client.connect(ips, ops, host, connectionPort);
assertArrayEquals(expectedByteStream.toByteArray(), ops.toByteArray());
}
/**
* Run into IOException while trying to connect due to no input/response
*/
@Test
public void connect__ioException() {
assertThrows(IOException.class, () -> {
SOCKS4Client.connect(
new ByteArrayInputStream(new byte[]{}),
new ByteArrayOutputStream(),
"127.0.0.1",
80);
});
}
/**
* Run into IOException while trying to connect due to closed input stream
*/
@Test
public void connect__ioExceptionWithSocket() {
assertThrows(IOException.class, () -> {
// Create an IOException by closing input stream before it can used
ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[]{});
inputStream.close();
Socket socket = Mockito.mock(Socket.class);
Mockito.when(socket.getInputStream()).thenReturn(inputStream);
Mockito.when(socket.getOutputStream()).thenReturn(new ByteArrayOutputStream());
SOCKS4Client.connect(
socket,
"127.0.0.1",
80
);
});
}
/**
* Check that CONNECTION_REFUSED throws exception
*/
@Test
public void connect__responseCONNECTION_REFUSED() {
assertThrows(SOCKSException.class, () -> {
SOCKS4Client.connect(new ByteArrayInputStream(new byte[]{
0, // dummy
SOCKS4Constants.Reply.CONNECTION_REFUSED, // Connection succeeded
}),
new ByteArrayOutputStream(),
"1.1.1.1",
80
);
});
}
/**
* IPv6 is not supported by this SOCKS client so it just throws an exception
*/
@Test
public void connect__IPv6() {
assertThrows(SOCKSException.class, () -> {
SOCKS4Client.connect(
new ByteArrayInputStream(new byte[]{}),
new ByteArrayOutputStream(),
"::1",
80);
});
}
}

View File

@@ -0,0 +1,69 @@
package net.i2p.util;
import net.i2p.data.Hash;
import org.junit.Test;
import static org.junit.Assert.*;
public class ConvertToHashTest {
private static final String zzzDotI2pBase32Hash = "lhbd7ojcaiofbfku7ixh47qj537g572zmhdc4oilvugzxdpdghua";
private static final String zzzDotI2pBase64Hash = "WcI~uSICHFCVVPoufn4J7v5u~1lhxi45C60Nm43jMeg=";
private static final String zzzDotI2pBase64Dest = "GKapJ8koUcBj~jmQzHsTYxDg2tpfWj0xjQTzd8BhfC9c3OS5fwPBNajgF-eOD6eCjFTqTlorlh7Hnd8kXj1qblUGXT-tDoR9~YV8dmXl51cJn9MVTRrEqRWSJVXbUUz9t5Po6Xa247Vr0sJn27R4KoKP8QVj1GuH6dB3b6wTPbOamC3dkO18vkQkfZWUdRMDXk0d8AdjB0E0864nOT~J9Fpnd2pQE5uoFT6P0DqtQR2jsFvf9ME61aqLvKPPWpkgdn4z6Zkm-NJOcDz2Nv8Si7hli94E9SghMYRsdjU-knObKvxiagn84FIwcOpepxuG~kFXdD5NfsH0v6Uri3usE3XWD7Pw6P8qVYF39jUIq4OiNMwPnNYzy2N4mDMQdsdHO3LUVh~DEppOy9AAmEoHDjjJxt2BFBbGxfdpZCpENkwvmZeYUyNCCzASqTOOlNzdpne8cuesn3NDXIpNnqEE6Oe5Qm5YOJykrX~Vx~cFFT3QzDGkIjjxlFBsjUJyYkFjBQAEAAcAAA==";
@Test
public void getHashNullPeer() {
assertNull(ConvertToHash.getHash(null));
}
@Test
public void getHashB64() {
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Hash);
assertNotNull(hash);
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
}
@Test
public void getHashB64DotI2P() {
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Hash + ".i2p");
assertNotNull(hash);
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
}
@Test
public void getHashDestinationB64() {
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Dest);
assertNotNull(hash);
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
}
@Test
public void getHashDestinationB64DotI2P() {
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Dest + ".i2p");
assertNotNull(hash);
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
}
@Test
public void getHashB32() {
Hash hash = ConvertToHash.getHash(zzzDotI2pBase32Hash);
assertNotNull(hash);
assertEquals(hash.toBase32(), zzzDotI2pBase32Hash + ".b32.i2p");
}
@Test
public void getHashB32DotI2P() {
String zzzB32I2P = zzzDotI2pBase32Hash + ".b32.i2p";
Hash hash = ConvertToHash.getHash(zzzB32I2P);
assertNotNull(hash);
assertEquals(hash.toBase32(), zzzB32I2P);
}
/**
* The case where a destination cannot be resolved at all
*/
@Test
public void getHashResolveDestinationFail() {
assertNull(ConvertToHash.getHash("unknown.i2p"));
}
}

View File

@@ -1,3 +1,22 @@
2021-01-20 zzz
* Console: Fix link to UPnP status
* SSU: Fix deadlock with router restart
2021-01-14 zzz
* Router:
- Change default encryption type to ECIES-X25519 (proposal 156)
- Move Sybil subsystem from console to router
- Limit max addresses in RI
2021-01-13 zzz
* Jetty: Fix URI in request logs
2021-01-12 zzz
* i2psnark: Don't decrement downloaded counter after receiving bad piece
2021-01-11 zzz
* Console: Delete rrd files for no-longer-configured stats at startup
2021-01-08 zzz
* i2ptunnel: Disable shared clients (DSA) (part 2)
* SSU: Fix bandwidth estimator deadlock (ticket #2798)

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 13;
public final static long BUILD = 14;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -81,22 +81,33 @@ public class WorkingDir {
String home = System.getProperty("user.home");
if (isWindows) {
String appdata = System.getenv("LOCALAPPDATA");
if (appdata != null)
if (appdata != null) {
home = appdata;
}
// Don't mess with existing Roaming Application Data installs,
// in case somebody is using roaming appdata for a reason
// already. In new installs, use local appdata by default. -idk
appdata = System.getenv("APPDATA");
if (appdata != null) {
File checkOld = new File(appdata, WORKING_DIR_DEFAULT_WINDOWS);
if (checkOld.exists() && checkOld.isDirectory())
home = appdata;
if (checkOld.exists() && checkOld.isDirectory()){
File routerConfig = new File(checkOld.getAbsolutePath(), "router.config");
// The Firefox profile installer was mistakenly using the Roaming application data
// which is synced between devices on some Windows machines using MS cloud services,
// instead of the local application data which is used by default.
// It would create the router.config file in an empty directory, which the router would
// then attempt to use, resulting in a router with no client applications. Checking
// for clients.config.d determines if the directory is "Real" or not.
File clientAppsConfig = new File(checkOld.getAbsolutePath(), "clients.config.d");
if (routerConfig.exists() && clientAppsConfig.exists() && clientAppsConfig.isDirectory())
home = appdata;
}
}
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_WINDOWS);
} else if (SystemVersion.isMac()) {
String appdata = "/Library/Application Support/";
File old = new File(home,WORKING_DIR_DEFAULT);
if (old.exists() && old.isDirectory())
File old = new File(home,WORKING_DIR_DEFAULT);
if (old.exists() && old.isDirectory())
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT);
else {
home = home+appdata;

View File

@@ -2455,7 +2455,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// warning, this calls back into us with allowRebuildRouterInfo = false,
// via CSFI.createAddresses->TM.getAddresses()->updateAddress()->REA
if (allowRebuildRouterInfo)
_context.router().rebuildRouterInfo();
rebuildRouterInfo();
} else {
addr = null;
}
@@ -2510,11 +2510,35 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// warning, this calls back into us with allowRebuildRouterInfo = false,
// via CSFI.createAddresses->TM.getAddresses()->updateAddress()->REA
if (allowRebuildRouterInfo)
_context.router().rebuildRouterInfo();
rebuildRouterInfo();
}
}
}
/**
* Avoid deadlocks part 999
* @since 0.9.49
*/
private void rebuildRouterInfo() {
(new RebuildEvent()).schedule(0);
}
/**
* @since 0.9.49
*/
private class RebuildEvent extends SimpleTimer2.TimedEvent {
/**
* Caller must schedule
*/
public RebuildEvent() {
super(_context.simpleTimer2());
}
public void timeReached() {
_context.router().rebuildRouterInfo(true);
}
}
/**
* Simple fetch of stored IP and port, since
* we don't put them in the real, published RouterAddress anymore