package com.limegroup.gnutella.messagehandlers; import java.io.File; import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.PublicKey; import java.util.List; import java.util.concurrent.Executor; import junit.framework.Test; import org.limewire.io.GGEP; import org.limewire.io.IpPort; import org.limewire.io.IpPortImpl; import org.limewire.io.SimpleNetworkInstanceUtils; import org.limewire.security.SecureMessage; import org.limewire.security.SecureMessageCallback; import org.limewire.security.SecureMessageVerifier; import org.limewire.security.Verifier; import org.limewire.setting.LongSetting; import org.limewire.setting.SettingsFactory; import org.limewire.setting.StringArraySetting; import org.limewire.util.BaseTestCase; import org.limewire.util.PrivilegedAccessor; import com.google.inject.Injector; import com.limegroup.gnutella.LimeTestUtils; import com.limegroup.gnutella.NetworkManager; import com.limegroup.gnutella.ReplyHandler; import com.limegroup.gnutella.UDPReplyHandlerCache; import com.limegroup.gnutella.UDPReplyHandlerFactory; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.messages.PingRequestFactory; import com.limegroup.gnutella.messages.vendor.RoutableGGEPMessage; import com.limegroup.gnutella.simpp.SimppListener; import com.limegroup.gnutella.simpp.SimppManager; import com.limegroup.gnutella.stubs.ReplyHandlerStub; @SuppressWarnings("all") public class RestrictedResponderTest extends BaseTestCase { private PingRequestFactory pingRequestFactory; private NetworkManager networkManager; private SimppManager simppManager; private UDPReplyHandlerFactory udpReplyHandlerFactory; private UDPReplyHandlerCache udpReplyHandlerCache; public RestrictedResponderTest(String name) { super(name); } public static Test suite() { return buildTestSuite(RestrictedResponderTest.class); } static InetSocketAddress addr; static ReplyHandler h; static StringArraySetting ipSetting; static LongSetting versionSetting; public void setUp() throws Exception { SettingsFactory f = new SettingsFactory(new File("set")); ipSetting = f.createStringArraySetting("ips", new String[]{"1.2.3.4"}); versionSetting = f.createLongSetting("version", 0); addr = new InetSocketAddress(InetAddress.getLocalHost(),1000); h = new ReplyHandlerStub() { public String getAddress() { return "1.2.3.4"; } }; Injector injector = LimeTestUtils.createInjector(); pingRequestFactory = injector.getInstance(PingRequestFactory.class); networkManager = injector.getInstance(NetworkManager.class); simppManager = injector.getInstance(SimppManager.class); udpReplyHandlerFactory = injector.getInstance(UDPReplyHandlerFactory.class); udpReplyHandlerCache = injector.getInstance(UDPReplyHandlerCache.class); } public void testRestrictions() throws Exception { // ban everyone ipSetting.setValue(new String[0]); TestResponder responder = new TestResponder(null); Message m = pingRequestFactory.createMulticastPing(); responder.handleMessage(m, addr, h); assertNull(responder.msg); assertNull(responder.addr); assertNull(responder.handler); // allow this specific hosts ipSetting.setValue(new String[]{"1.2.3.4"}); triggerSimppUpdate(); responder.handleMessage(m, addr, h); assertSame(m, responder.msg); assertSame(addr, responder.addr); assertSame(h, responder.handler); // but someone else won't get in responder.reset(); responder.handleMessage(m, addr, new ReplyHandlerStub() { public String getAddress() { return "1.2.3.5"; } }); assertNull(responder.msg); assertNull(responder.addr); assertNull(responder.handler); } /** * tests that messages are verified. */ public void testSecure() throws Exception { TestVerifier verifier = new TestVerifier(); TestResponder responder = new TestResponder(verifier); InetSocketAddress addr = new InetSocketAddress(InetAddress.getLocalHost(),1000); ReplyHandler h = new ReplyHandlerStub() { public String getAddress() { return "1.2.3.4"; } }; TestGGEPMessage m = new TestGGEPMessage(); // the message should be sent for verification m.returnAddr = new IpPortImpl("1.2.3.4",5); responder.handleMessage(m, addr, h); assertSame(verifier.sm, m); // if it doesn't verify, it wont' get processed verifier.smc.handleSecureMessage(verifier.sm, false); assertNull(responder.msg); // but a message that verifies will be processed verifier.smc.handleSecureMessage(verifier.sm, true); assertSame(m,responder.msg); } /** tests that the return address of a message is respected */ public void testReturnAddress() throws Exception { TestResponder responder = new TestResponder(null); final IpPort allowed = new IpPortImpl("1.2.3.4",100); final IpPort notAllowed = new IpPortImpl("1.2.3.5",100); // try a message that comes from an allowed host but wants to go // to a non-allowed return address. It should not be handled. TestGGEPMessage m = new TestGGEPMessage(); m.returnAddr = notAllowed; responder.handleMessage(m, addr, h); assertNull(responder.msg); // try a message that comes from a non-allowed host but wants to // go to an allowed return address m.returnAddr = allowed; ReplyHandler notAllowedHandler = new ReplyHandlerStub() { public String getAddress() { return "1.2.3.6"; } }; responder.handleMessage(m,addr,notAllowedHandler); assertSame(m,responder.msg); assertEquals(allowed.getAddress(),responder.handler.getAddress()); // if both the return address and source address are allowed, the // return address takes precedence. responder = new TestResponder(null); m.version++; responder.handleMessage(m,addr,h); assertSame(m,responder.msg); assertEquals(allowed.getAddress(),responder.handler.getAddress()); } /** * tests that only newer messages are handled. */ public void testVersioning() throws Exception { TestResponder responder = new TestResponder(null); TestGGEPMessage m = new TestGGEPMessage(); responder.handleMessage(m, addr, h); assertSame(m,responder.msg); // now try the same message again, it should not be handled. responder.msg = null; responder.handleMessage(m, addr, h); assertNull(responder.msg); // but if the version number is higher, it gets handled. m.version = 2; responder.handleMessage(m, addr, h); assertSame(m,responder.msg); // a message w/o a version will not go through. m.version = -1; responder.msg = null; responder.handleMessage(m, addr, h); assertNull(responder.msg); // but if it has a version it will have to be higher than the current. responder.msg = null; m.version = 1; responder.handleMessage(m, addr, h); assertNull(responder.msg); // create a new responder - it should look up the last routed version // from the persisted setting. responder = new TestResponder(null); responder.handleMessage(m, addr, h); assertNull(responder.msg); m.version = 3; responder.handleMessage(m, addr, h); assertSame(m,responder.msg); assertEquals(3, versionSetting.getValue()); } public void testDestinationAddress() throws Exception { TestResponder responder = new TestResponder(null); TestGGEPMessage m = new TestGGEPMessage(); // a message w/o a version will go through if it has the proper // destination address m.version = -1; m.destAddr = new IpPortImpl(InetAddress.getByAddress(networkManager.getExternalAddress()),1234); responder.handleMessage(m, addr, h); assertSame(m, responder.msg); // if the destination address is wrong, it is dropped. m.destAddr = new IpPortImpl("1.2.3.4",100); responder.msg = null; responder.handleMessage(m, addr, h); assertNull(responder.msg); } private static int simppVersion; private void triggerSimppUpdate() throws Exception { List<SimppListener> l = (List<SimppListener>) PrivilegedAccessor.getValue(simppManager, "listeners"); for (SimppListener s : l) s.simppUpdated(simppVersion++); } private class TestResponder extends RestrictedResponder { Message msg; InetSocketAddress addr; ReplyHandler handler; public TestResponder(SecureMessageVerifier verifier) { super(ipSetting, verifier, versionSetting, networkManager, simppManager, udpReplyHandlerFactory, udpReplyHandlerCache, new ImmediateExecutor(), new SimpleNetworkInstanceUtils()); } @Override protected void processAllowedMessage(Message msg, InetSocketAddress addr, ReplyHandler handler) { this.msg = msg; this.addr = addr; this.handler = handler; } void reset() { this.msg = null; this.addr = null; this.handler = null; } } private static class TestVerifier implements SecureMessageVerifier { SecureMessage sm; SecureMessageCallback smc; TestVerifier() { } public void verify(Verifier verifier) { sm = verifier.getSecureMessage(); smc = verifier.getSecureMessageCallback(); } public void verify(SecureMessage sm, SecureMessageCallback smc) { this.sm = sm; this.smc = smc; } public void verify(PublicKey pubKey, String algorithm, SecureMessage sm, SecureMessageCallback smc) { this.sm = sm; this.smc = smc; } } private static class TestGGEPMessage extends RoutableGGEPMessage { int version = 1; IpPort returnAddr, destAddr; protected TestGGEPMessage() throws BadPacketException { super(new byte[4], 1, 1, new RoutableGGEPMessage.GGEPSigner() { public GGEP getSecureGGEP(GGEP original) { return original; } },new GGEP(true)); } @Override public long getRoutableVersion() { return version; } @Override public IpPort getReturnAddress() { return returnAddr; } @Override public IpPort getDestinationAddress() { return destAddr; } } private static class ImmediateExecutor implements Executor { public void execute(Runnable command) { command.run(); } } }