//******************************************************************
//******************************************************************
//********** ANts Peer To Peer Sources *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.
// Copyright (C) 2004 Roberto Rossi
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
package ants.p2p.security.sockets;
import java.net.*;
import java.io.*;
import java.security.*;
import java.security.spec.*;
import javax.net.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.net.ssl.*;
import ants.p2p.*;
import ants.p2p.utils.addresses.InetAddressWatchdog;
import ants.p2p.utils.addresses.AddressServerThread;
import org.apache.log4j.*;
public class SecureServer implements Runnable{
String KEYSTORE = "certs";
char[] KEYSTOREPW = "serverkspw".toCharArray();
char[] KEYPW = "serverpw".toCharArray();
int serverPort = 443;
ServerSocket serverSocket = null;
static Logger _logger = Logger.getLogger(SecureServer.class.getName());
public Thread serverThread;
Ant n;
public SecureServer(Ant n, int port) throws Exception{
this.n = n;
this.serverPort = port;
this.serverSocket = this.createServerSocket();
try{
serverThread = new Thread(this);
serverThread.setPriority(10);
serverThread.start();
}catch(Exception e){_logger.error("",e);}
}
public SecureServer(Ant n) throws Exception,
NoSuchAlgorithmException,
InvalidParameterSpecException,
InvalidAlgorithmParameterException,
InvalidKeyException {
this.n = n;
this.serverSocket = this.createServerSocket();
serverThread = new Thread(this);
serverThread.setPriority(10);
serverThread.start();
}
public void listen() {
//UPnP mapping
this.n.uPnPMapping();
while (!n.isDisconnected() && !this.serverSocket.isClosed()) {
try {
_logger.info(n.getShortId() + " :Server Listening...");
Socket localSocket = this.serverSocket.accept();
if (localSocket != null) {
RequestsHandler handler = new RequestsHandler(this, localSocket);
handler.start();
}
}
catch (Exception e) {
_logger.error("Secure Server Socket listen cycle: " + this.serverSocket.getLocalPort() + " ", e);
this.n.disconnect();
}
}
_logger.info("Secure Server Socket closed: "+this.serverSocket.getLocalPort());
}
public void run(){
listen();
}
public ServerSocket getServerSocket(){
return this.serverSocket;
}
private ServerSocket createServerSocket() throws Exception {
// Make sure that JSSE is available
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
// A keystore is where keys and certificates are kept
// Both the keystore and individual private keys should be password protected
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(this.getClass().getClassLoader().getResource(KEYSTORE).openStream(), KEYSTOREPW);
// A KeyManagerFactory is used to create key managers
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
// Initialize the KeyManagerFactory to work with our keystore
kmf.init(keystore, KEYPW);
// An SSLContext is an environment for implementing JSSE
// It is used to create a ServerSocketFactory
SSLContext sslc = SSLContext.getInstance("TLSv1");
// Initialize the SSLContext to work with our key managers
sslc.init(kmf.getKeyManagers(), null, null);
// Create a ServerSocketFactory from the SSLContext
ServerSocketFactory ssf = sslc.getServerSocketFactory();
// Socket to me
SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(serverPort);
// Return a ServerSocket on the desired port (443)
return serverSocket;
}
}
class RequestsHandler extends Thread{
Socket localSocket;
SecureServer caller;
static Logger _logger = Logger.getLogger(RequestsHandler.class.getName());
public RequestsHandler(SecureServer caller, Socket localSocket){
this.localSocket = localSocket;
this.caller = caller;
}
public void run(){
try {
int type = this.localSocket.getInputStream().read();
if(type == 0){
_logger.info("Connection type: 0");
NewClientHandler handler = new NewClientHandler(this.caller, this.localSocket);
handler.start();
}else if(type == 1){
_logger.info("Connection type: 1");
AddressesRequestHandler handler = new AddressesRequestHandler(this.caller, this.localSocket);
handler.start();
}else if(type == 2 && caller.n.acceptTCPDirectConnections()){
_logger.info("Connection type: 2");
DirectNeighbourRequestHandler handler = new DirectNeighbourRequestHandler(this.caller, this.localSocket);
handler.start();
}else{
localSocket.close();
}
}
catch (IOException ex) {
_logger.error("", ex);
return;
}
}
}
class NewClientHandler extends Thread{
Socket localSocket;
SecureServer caller;
static Logger _logger = Logger.getLogger(NewClientHandler.class.getName());
public NewClientHandler(SecureServer caller, Socket localSocket){
this.localSocket = localSocket;
this.caller = caller;
this.setPriority(5);
}
public void run(){
try {
String remoteAddress = localSocket.getInetAddress().getHostAddress();
if (!InetAddressWatchdog.getInstance().allowedAddress(InetAddress.
getByName(remoteAddress).getHostAddress())) {
localSocket.close();
throw new Exception("Address is not allowed: " + remoteAddress);
}
if (caller.n.getNeighboursNumber() < caller.n.getMaxNeighbours()) {
localSocket.setKeepAlive(true);
SecureServerSocketThread serverSocketThread = new
SecureServerSocketThread(localSocket);
if (serverSocketThread.isNewVersionDetected()) {
this.caller.n.getPropertyChangeSupport().firePropertyChange(
"newANtsVersionDetected", null,
serverSocketThread.getNewerVersion());
}
if (!localSocket.isClosed()) {
_logger.info(this.caller.serverSocket.getInetAddress().getHostAddress() +
": Local time elapsed: " +
serverSocketThread.getTimeElapsed() + "[Thresold: " +
caller.n.getRateThresold() + "]");
/*if (caller.n.getUnderRatedNeighbours() >=
Math.floor(Ant.maxNeighbours * Ant.underRateConnections) &&
serverSocketThread.getTimeElapsed() >= caller.n.getRateThresold()) {
throw new Exception(this.caller.serverSocket.getInetAddress().
getHostAddress() +
": Rejected neighbour cause it doesn't satisfy bandwith request: [" +
caller.n.getUnderRatedNeighbours() + "/" +
Math.floor(Ant.maxNeighbours *
Ant.underRateConnections) + "]");
}*/
NeighbourAnt na = new NeighbourAnt(caller.n,
localSocket.getInetAddress() +
"",
localSocket.getPort(),
serverSocketThread.
getRemoteServerPort(),
serverSocketThread.
getCipherEnc(),
serverSocketThread.
getCipherDec(),
serverSocketThread.getSocket(),
false,
serverSocketThread.getTimeElapsed());
try {
caller.n.addNeighbour(na);
na.start();
}
catch (Exception e) {
na.terminate();
na.setFailure();
na.start();
throw new Exception(e);
}
_logger.info(caller.n.getShortId() + " :Server added neighbour...");
}
else {
_logger.info(caller.n.getShortId() + " :Rejected connection...");
}
}
else {
localSocket.close();
_logger.info(caller.n.getShortId() + " :Rejected neighbour...");
}
}
catch (Exception e) {
_logger.error("New client handler: " + this.caller.serverSocket.getLocalPort() +
" ", e);
}
}
}
class AddressesRequestHandler extends Thread{
Socket localSocket;
SecureServer caller;
static Logger _logger = Logger.getLogger(NewClientHandler.class.getName());
public AddressesRequestHandler(SecureServer caller, Socket localSocket){
this.localSocket = localSocket;
this.caller = caller;
this.setPriority(5);
}
public void run(){
try {
String remoteAddress = localSocket.getInetAddress().getHostAddress();
if (!InetAddressWatchdog.getInstance().allowedAddress(InetAddress.
getByName(remoteAddress).getHostAddress())) {
_logger.info("Address is not allowed: " + remoteAddress);
localSocket.close();
}
else {
AddressServerThread serverThread = new AddressServerThread(
localSocket);
serverThread.start();
}
}
catch (Exception e) {
_logger.error("Addresses request handler: " + this.caller.serverSocket.getLocalPort() + " ", e);
}
}
}
class DirectNeighbourRequestHandler extends Thread{
Socket localSocket;
SecureServer caller;
static Logger _logger = Logger.getLogger(NewClientHandler.class.getName());
public DirectNeighbourRequestHandler(SecureServer caller, Socket localSocket){
this.localSocket = localSocket;
this.caller = caller;
}
public void run(){
try {
localSocket.setKeepAlive(true);
localSocket.setSoTimeout(3 * 60000);
TCPDirectServerThread tcpDirectServerThread = new TCPDirectServerThread(localSocket, caller.n);
tcpDirectServerThread.setPriority(10);
tcpDirectServerThread.start();
}
catch (Exception e) {
_logger.error("Direct neighbour request handler: " + this.caller.serverSocket.getLocalPort() + " ", e);
}
}
}