1-to-1 proxy using sockets

  • (2 Pages)
  • +
  • 1
  • 2

23 Replies - 1216 Views - Last Post: 22 July 2021 - 04:23 AM Rate Topic: -----

#1 pheonixfire   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 34
  • Joined: 26-July 17

1-to-1 proxy using sockets

Posted 09 June 2021 - 06:32 AM

Hi,
I'm trying to get my proxy running correctly using socket, before anyone tells me I should be using some other class this started
off as a uni assignment which I have come back to since it was annoying me so much that I couldn't getting it working properly

At the moment it will do the initial http request but I can't get any subsequent request to go through, the web server will show
the requests in the access log when the browser connects directly but only shows the initial request through the proxy

I've placed my connectToServer and sendQueryToServer functions below, hopefully this is a simple or obvious problem that I've
managed to overlook somehow

public Boolean connectToServer (String query)
    {
        try
        {
            sock = new Socket(address.getHostAddress(), 80);
            outStream = sock.getOutputStream();
            printWriter = new PrintWriter(outStream, true);
            inStream = sock.getInputStream();
            dataStream = new DataInputStream(inStream);
            bufRead = new BufferedReader(new InputStreamReader(inStream, Charset.forName("UTF-8")));
            return true;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
    }

public void sendQueryToServer(String query)
    {
        System.out.println("query being sent to server: \n" + query);
        printWriter.println(query);
    }



let me know if additional code chunks are required to troubleshoot this
Best Regards
pheonixfire

Is This A Good Question/Topic? 0
  • +

Replies To: 1-to-1 proxy using sockets

#2 NormR   User is offline

  • D.I.C Lover
  • member icon

Reputation: 870
  • View blog
  • Posts: 6,679
  • Joined: 25-December 13

Re: 1-to-1 proxy using sockets

Posted 09 June 2021 - 08:28 AM

How can the code be compiled and executed for testing?
Was This Post Helpful? 0
  • +
  • -

#3 g00se   User is offline

  • D.I.C Lover
  • member icon

Reputation: 3737
  • View blog
  • Posts: 17,104
  • Joined: 20-September 08

Re: 1-to-1 proxy using sockets

Posted 09 June 2021 - 08:56 AM

My advice to you is not to assume that you know how to talk http proxy. Study how the protocol is meant to work. Even straight http is probably not as simple as you imagine it is. If you get it wrong, it simply won't work and you'll probably not even know why.
Was This Post Helpful? 0
  • +
  • -

#4 pheonixfire   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 34
  • Joined: 26-July 17

Re: 1-to-1 proxy using sockets

Posted 09 June 2021 - 06:26 PM

View Postg00se, on 10 June 2021 - 02:56 AM, said:

My advice to you is not to assume that you know how to talk http proxy. Study how the protocol is meant to work. Even straight http is probably not as simple as you imagine it is. If you get it wrong, it simply won't work and you'll probably not even know why.


at the moment all the proxy does is receive the request on one connection, replace the destination address then send it out on the other connection.
The browser is doing the request command generation, so I'm assuming the issue is to do with how my code is sending the requests in the first place

Best Regards
pheonixfire

This post has been edited by pheonixfire: 09 June 2021 - 06:27 PM

Was This Post Helpful? 0
  • +
  • -

#5 NormR   User is offline

  • D.I.C Lover
  • member icon

Reputation: 870
  • View blog
  • Posts: 6,679
  • Joined: 25-December 13

Re: 1-to-1 proxy using sockets

Posted 09 June 2021 - 06:27 PM

Post some code that compiles and can be executed for testing.
Was This Post Helpful? 0
  • +
  • -

#6 g00se   User is offline

  • D.I.C Lover
  • member icon

Reputation: 3737
  • View blog
  • Posts: 17,104
  • Joined: 20-September 08

Re: 1-to-1 proxy using sockets

Posted 10 June 2021 - 01:49 AM

Quote

The browser is doing the request command generation


Your browser is a client of your Java code?
Was This Post Helpful? 0
  • +
  • -

#7 pheonixfire   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 34
  • Joined: 26-July 17

Re: 1-to-1 proxy using sockets

Posted 10 June 2021 - 03:41 AM

yes, the browser talks to my proxy which in turn talks to the webserver

I've put the contents of my code files below since I can't get the upload to work, don't be too harsh on the judgement
some of the code is to meet assignment requirements and I wanted the class names to mean something to me


package Communications;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * handles all interaction between the client and the 
 * @author 
 */
public class BullRoarer
{
    ServerSocket servSock;
    Socket responseSock;
    LocalDateTime currentTime;
    PrintWriter printWriter;
    OutputStream outStream;
    InputStream inStream;
    InputStreamReader inStreamReader;
    BufferedReader bufRead;

    public BullRoarer(LocalDateTime currentTime)
    {
        this.currentTime = currentTime;
    }
    
    /**
     * Listens for a client connection request, then acts on behalf of the client for connections
     */
    public void listenForClient()
    {
        try
        {
            servSock = new ServerSocket(3310);
            responseSock = servSock.accept();
            inStream = responseSock.getInputStream();
            outStream = responseSock.getOutputStream();
            inStreamReader = new InputStreamReader(inStream, Charset.forName("UTF-8"));
            bufRead = new BufferedReader(inStreamReader);
            printWriter = new PrintWriter(outStream, true);
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
    
    /**
     * checks if the client is still connected to the proxy/mirror
     * @return 
     */
    public Boolean checkClientConnected()
    {
        try
        {
            if (inStream.read() == -1)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
   }
    
    /**
     * retrieves the next client request and sends it to the caller
     * @return 
     */
    public String readClientRequest()
    {
        try
        {
            StringBuilder receivedRequest = new StringBuilder();
            String temp;
            while ((temp = bufRead.readLine()) != null)
            {
                if (temp.contains("GET / HTTP"))
                {
                    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/mm/yyyy HH:mm:ss");
                    System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                }
                
                receivedRequest.append(temp).append("\r\n");
                if (temp.isBlank())
                {
                    receivedRequest.append("\n");
                    break;
                }
            }
            return receivedRequest.toString();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return new String();
        }
    }
    
    
    /**
     * sends response to client containing text file
     * @param response 
     */
    public void sendResponse(String response)
    {
        printWriter.println(response);
    }
    
    /**
     * sends response to client containing image file
     * @param imageData 
     */
    public void sendResponse(byte[] imageData)
    {
        printWriter.println(imageData);
    }
    
    /**
     * Closes connection to the client
     */
    public void closeConnection()
    {
        try
        {
            printWriter.close();
            responseSock.close();
            servSock.close();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}



package Communications;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * handles all interaction between the proxy/mirror and the destination webserver
 * @author 
 */
public class MessageStick
{
    InetAddress address;
    private Boolean verbose;
    private LocalDateTime currentTime;
    private Socket sock;
    private PrintWriter printWriter;
    private BufferedReader bufRead;
    private OutputStream outStream;
    private InputStream inStream;
    private DataInputStream dataStream;
    
    public MessageStick(InetAddress address, Boolean verbose, LocalDateTime currentTime)
    {
        this.address = address;
        this.verbose = verbose;
        this.currentTime = currentTime;
    }
    
    /**
     * handles the initial process of establishing a connection to the destination server
     * @param query
     * @return 
     */
    public Boolean connectToServer (String query)
    {
        try
        {
            sock = new Socket(address.getHostAddress(), 80);
            outStream = sock.getOutputStream();
            printWriter = new PrintWriter(outStream, true);
            inStream = sock.getInputStream();
            dataStream = new DataInputStream(inStream);
            bufRead = new BufferedReader(new InputStreamReader(inStream, Charset.forName("UTF-8")));
            return true;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
    }
    
    /**
     * retrieves a image file from destination server and passes it to caller
     * @return 
     */
    public byte [] retrieveImage ()
    {
        try
        {
            byte[] receivedImage = dataStream.readAllBytes();
//            byte[] receivedImage = byte[dataStream.];
            System.out.println("number of bytes in receivedImage: " + receivedImage.length);
            for (byte imgByte : receivedImage)
            {
                System.out.println(imgByte);
            }
            return receivedImage;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * retrieves text files from web server
     * @return 
     */
    public String retrieveText()
    {
        try
        {
            StringBuilder result = new StringBuilder();
            String temp = new String();
            DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/mm/yyyy HH:mm:ss");
            while ((temp = bufRead.readLine()) != null)
            {
                if (verbose)
                {
                    System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                }
                else
                {
                    if (temp.contains("GET / HTTP"))
                    {
                        System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                    }
                    else if (temp.contains("HTTP"))
                    {
                        System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                    }
                }
                result = result.append(temp).append("\n");
                if (temp.contains("</html>"))
                {
                    result = result.append("\n");
                    break;
                }
            }
            return result.toString();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * takes care of sending a request to the web server
     * @param query
     * @return 
     */
    public void sendQueryToServer(String query)
    {
        System.out.println("query being sent to server: \n" + query);
        printWriter.println(query);
    }
    
    /**
     * closes all connections to the web server and any related object
     */
    public void closeConnection()
    {
        try
        {
            bufRead.close();
            printWriter.close();
            sock.close();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}



package assignment2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Hashtable;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;

/**
 *
 * @author 
 */
public class Elder
{
    private Hashtable<String, String> CapChange = new Hashtable<>();
    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/mm/yyyy HH:mm:ss");
    String destinationServer;
    
    public Elder()
    {
        createCapChangeDict();
    }
    
    /**
     * Populates the capital city change dictionary with a one-to-one mapping between
     * the original city name and the replacement city name
     */
    private void createCapChangeDict ()
    {
        CapChange.put("Canberra", "Jervis Bay");
        CapChange.put("Brisbane", "Longreach");
        CapChange.put("Darwin", "Alice Springs");
        CapChange.put("Sydney", "Queanbeyan");
        CapChange.put("Melbourne", "Albury");
        CapChange.put("Adelaide", "Coober Pedy");
        CapChange.put("Perth", "Geraldton");
        CapChange.put("Hobart", "Launceston");
    }
    
    /**
     * Takes a canonical web address and then returns INetAddress which is capable of
     * providing an IP address
     * @param String canonical web address
     * @return InetAddress 
     */
    public InetAddress getIPAddressFromDomain (String url)// throws UnknownHostException
    {
        try
        {
            String trimmedAddress;
            if (url.charAt(url.length() - 1) == '/')
            {
                trimmedAddress = url.substring(7, url.length() - 1);
            }
            else
            {
                trimmedAddress = url.substring(7);
            }
            
            destinationServer = InetAddress.getByName(trimmedAddress).getHostAddress();
            return InetAddress.getByName(trimmedAddress);
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    public InetAddress getIPAddressFromIpString (String ipString)
    {
        try
        {
            return InetAddress.getByName(ipString);
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * Receives a string containing the webpage content, this is then sent to the replaceCaps and
     * updateLinks functions before returning the string to the caller
     * @param webContent String containing the webpage content
     * @param address string containing the canonical web address
     * @return webContent string containing the modified web page content
     */
    public String checkContent(String webContent, String address)
    {
        webContent = replaceCaps(webContent);
        webContent = updateLinks(webContent, address);
        webContent = updateContentLength(webContent);
        return webContent;
    }
    
    /**
     * updates the content length to reflect the changes to the capital city names and urls
     * @param webcontent
     * @return 
     */
    private String updateContentLength (String webcontent)
    {
        try
        {
            Integer length = webcontent.length();            
            Integer substring = webcontent.indexOf("<!doctype html>");
            if (substring != -1)
            {
                length = length - webcontent.substring(0, substring).length();
                BufferedReader bufStringRead = new BufferedReader(new StringReader(webcontent));
                String returnContent = new String();
                String line;
                while ((line = bufStringRead.readLine()) != null)
                {
                    if (line.contains("Content-Length: "))
                    {
                        line = new String("Content-Length: " + length + "\n");
                        returnContent = returnContent.concat(line);
                    }
                    else
                    {
                        returnContent = returnContent.concat(line).concat("\n");
                    }
                }
                return returnContent;
            }
            else
            {
                return webcontent;
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return webcontent;
        }
    }
    
    /**
     * replaceCaps goes through the webContent string and replaces all occurrences of city names with
     * their designated replacement name as defined by the capChange Dictionary/HashMap
     * @param webContent string containing the web page content
     * @return webContent string containing the web page with capital city names replaced
     */
    private String replaceCaps(String webContent)
    {
        Integer capChanges = 0;
        for (Map.Entry element : CapChange.entrySet())
        {
            webContent = webContent.replace(element.getKey().toString(), element.getValue().toString());
            capChanges += StringUtils.countMatches(webContent, element.getValue().toString());
        }
        System.out.println(dateFormatter.format(getTimestamp()) + ": Text changes: " + capChanges);
        return webContent;
    }
    
    /**
     * updateLinks takes a string containing the webpage contents, then replaces the canonical address with
     * the proxy servers ip address
     * @param webContent String containing the web page contents
     * @param address String containing the canonical address of the original webserver
     * @return webContent String with the web address replaced
     */
    public String updateLinks(String webContent, String address)
    {
        String localAddress = getLocalAddress().concat("/");
        webContent = webContent.replace(address, localAddress);
        System.out.println(dateFormatter.format(getTimestamp()) +": Link rewrites, not including relative links: " + StringUtils.countMatches(webContent, localAddress));
        return webContent;
    }
    
    /**
     * updates the received request to have the destination servers ip address instead of the proxy/mirrors
     * ip address
     * @param request
     * @return 
     */
    public String updateRequest(String request, String newDestinationAddress)
    {
        try
        {
            request = request.replace(InetAddress.getLocalHost().getHostAddress(), newDestinationAddress);
            request = request.replace("3310", "80");
            request = request.replace("Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0", "comp3310/1.0");
            return request;
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * Returns a string containing the ip address of the proxy server
     * @return String containing ip address
     */
    private String getLocalAddress()
    {
        try
        {
            InetAddress localAddress = InetAddress.getLocalHost();
            return localAddress.getHostAddress();
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return "127.0.0.1";
        }
    }
    
    /**
     * Returns a LocalDateTime object containing the current date time timestamp
     * @return LocalDateTime object
     */
    public LocalDateTime getTimestamp()
    {
        LocalDateTime currentDateTime = LocalDateTime.now();
        return currentDateTime;
    }
    
    public String repairET(String query)
    {
        if (query.contains("ET"))
        {
            return query.replace("ET", "GET");
        }
        else
        {
            return query;
        }
    }
    
    public Boolean requestedImageFile (String request)
    {
        if (request.contains(".jpg"))
        {
            return true;
        }
        else if (request.contains(".png"))
        {
            return true;
        }
        else if (request.contains(".gif"))
        {
            return true;
        }
        else if (request.contains(".ico"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}



package assignment2;
import Communications.BullRoarer;
import com.google.common.net.InetAddresses;
import static java.lang.Thread.sleep;
import java.net.InetAddress;
import org.apache.commons.cli.*;

/**
 *
 * @author 
 */
public class Assignment2
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws InterruptedException
    {
        Boolean verbose = false;

        final Exit exit = new Exit();

        String address = null;
        Options cliOptions = new Options();
        cliOptions.addOption("a", true, "web address");
        cliOptions.addOption("v", "Verbose logging");
        CommandLineParser cmdParse = new DefaultParser();
        Elder elder = new Elder();
        
        Runtime runtime = Runtime.getRuntime();
        runtime.addShutdownHook(new Thread()
        {
            public void run()
            {
                System.out.println("Shutting Down");
                exit.exit = true;
            }
        });
        
        try
        {
            CommandLine cliSwitches = cmdParse.parse(cliOptions, args);
            
            if (cliSwitches.hasOption("v"))
            {
                verbose = true;
                System.out.println("Verbose switch specified");
            }
            
            if (cliSwitches.hasOption("a"))
            {
                address = cliSwitches.getOptionValue("a");
                System.out.println("Web address provided");
            }
            else
            {
                System.out.println("No web address provided");
                System.exit(1);
            }
        }
        catch (ParseException ex)
        {
            ex.printStackTrace();
        }
        
        while (exit.exit == false)
        {
            //Listen for request from client
            Communications.BullRoarer bullRoarer = new BullRoarer(elder.getTimestamp());
            bullRoarer.listenForClient();
            
            //Make request on behalf of client
            InetAddress addressObject = null;
            if (InetAddresses.isInetAddress(address))
            {
                addressObject = elder.getIPAddressFromIpString(address);
            }
            else
            {
                addressObject = elder.getIPAddressFromDomain(address);
            }
            
            Communications.MessageStick messageStick = new Communications.MessageStick(addressObject, verbose, elder.getTimestamp());
            
            //connect to destination server
            Boolean result = messageStick.connectToServer(address);
            
            // image holder variable
            byte[] receivedImage = new byte[0];
            Boolean isImage = false;
            
            //handle initial connection received data
            if (result)
            {
                //Remove client request from buffer
                String receivedData = bullRoarer.readClientRequest();
                
                //update received request
                receivedData = elder.updateRequest(receivedData, addressObject.getHostAddress());
                
                // send request to destination server
                if (!receivedData.isBlank())
                {
                    messageStick.sendQueryToServer(receivedData);
                    receivedData = messageStick.retrieveText();
                }
                
                if (receivedData.isBlank())
                {
                    System.out.println("No web page found");
                }
                else
                {
                    //check content and make required changes
                    receivedData = elder.checkContent(receivedData, address);
                    
                    //send response to client
                    bullRoarer.sendResponse(receivedData);
                    
                    //wait 120 milliseconds for client to process
                    sleep(120);
                }
                
            }
            
            //deal with any additional requests, if none close connections
            while(true)
            {
                if (!bullRoarer.checkClientConnected())
                {
                    bullRoarer.closeConnection();
                    messageStick.closeConnection();
                    break;
                }
                else
                {
                    String receivedData = bullRoarer.readClientRequest();
                    receivedData = elder.repairET(receivedData);
//                    receivedData = elder.buildRequest(receivedData, addressObject.getHostAddress());
                    receivedData = elder.updateRequest(receivedData, addressObject.getHostAddress());
                    
                    System.out.println("received data contents:\n" + receivedData);
                    //send request to destination server and receive response
                    messageStick.sendQueryToServer(receivedData);
                    
                    
                    if (elder.requestedImageFile(receivedData))
                    {
                        System.out.println("retrieving image file");
                        isImage = true;
                        receivedImage = messageStick.retrieveImage();
                    }
                    else
                    {
                        isImage = false;
                        receivedData = messageStick.retrieveText();
                    }
                    
                    //check the content
                    if (!isImage)
                    {
                        receivedData = elder.checkContent(receivedData, address);
                    }
                    
                    //send response to client
                    if (isImage)
                    {
                        bullRoarer.sendResponse(receivedImage);
                    }
                    else
                    {
                        bullRoarer.sendResponse(receivedData);
                    }
                    
                    //wait 120 milliseconds for client to process
                    sleep(120);
                }
            }
        }
    }
    
    private static class Exit
    {
        public Boolean exit = false;
    }
    
}


This post has been edited by pheonixfire: 10 June 2021 - 03:41 AM

Was This Post Helpful? 0
  • +
  • -

#8 g00se   User is offline

  • D.I.C Lover
  • member icon

Reputation: 3737
  • View blog
  • Posts: 17,104
  • Joined: 20-September 08

Re: 1-to-1 proxy using sockets

Posted 10 June 2021 - 03:52 AM

Quote

yes, the browser talks to my proxy which in turn talks to the webserver

In that case, it's even more important that you follow my comment. In fact it would be useful for you also to post an example of a 'run' of the correct protocol for handling http proxy so that those answering here can see if your code is actually doing what's necessary
Was This Post Helpful? 0
  • +
  • -

#9 NormR   User is offline

  • D.I.C Lover
  • member icon

Reputation: 870
  • View blog
  • Posts: 6,679
  • Joined: 25-December 13

Re: 1-to-1 proxy using sockets

Posted 10 June 2021 - 04:01 AM

Thanks for posting all that. However it uses too many classes that are not in Java SE for me to compile for testing.
Was This Post Helpful? 0
  • +
  • -

#10 pheonixfire   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 34
  • Joined: 26-July 17

Re: 1-to-1 proxy using sockets

Posted 12 June 2021 - 05:15 AM

I've stripped it back to minimise dependencies, it now only depends on guava-30
while I am compiling it against jdk 16 I suspect it can probably compile against as low as jdk 1.8

Best Regards
pheonixfire

package assignment2;
import Communications.BullRoarer;
import com.google.common.net.InetAddresses;
import static java.lang.Thread.sleep;
import java.net.InetAddress;

/**
 *
 * @author James
 */
public class Assignment2
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws InterruptedException
    {
        Boolean verbose = false;

        final Exit exit = new Exit();

        String address = null; //destination server address goes here
        Elder elder = new Elder();
        
        Runtime runtime = Runtime.getRuntime();
        runtime.addShutdownHook(new Thread()
        {
            public void run()
            {
                System.out.println("Shutting Down");
                exit.exit = true;
            }
        });
        
        if (address == null)
        {
            System.out.println("address value needs updating to proceed");
            System.exit(0);
        }
        else
        {
            System.out.println("Proxy Started");
        }
        
        
        while (exit.exit == false)
        {
            //Listen for request from client
            Communications.BullRoarer bullRoarer = new BullRoarer(elder.getTimestamp());
            bullRoarer.listenForClient();
            
            //Make request on behalf of client
            InetAddress addressObject = null;
            if (InetAddresses.isInetAddress(address))
            {
                addressObject = elder.getIPAddressFromIpString(address);
            }
            else
            {
                addressObject = elder.getIPAddressFromDomain(address);
            }
            
            Communications.MessageStick messageStick = new Communications.MessageStick(addressObject, verbose, elder.getTimestamp());
            
            //connect to destination server
            Boolean result = messageStick.connectToServer(address);
            
            // image holder variable
            byte[] receivedImage = new byte[0];
            Boolean isImage = false;
            
            //handle initial connection received data
            if (result)
            {
                //Remove client request from buffer
                String receivedData = bullRoarer.readClientRequest();
                
                //update received request
                receivedData = elder.updateRequest(receivedData, addressObject.getHostAddress());
                
                // send request to destination server
                if (!receivedData.isBlank())
                {
                    messageStick.sendQueryToServer(receivedData);
                    receivedData = messageStick.retrieveText();
                }
                
                if (receivedData.isBlank())
                {
                    System.out.println("No web page found");
                }
                else
                {
                    //check content and make required changes
                    receivedData = elder.checkContent(receivedData, address);
                    
                    //send response to client
                    bullRoarer.sendResponse(receivedData);
                    
                    //wait 120 milliseconds for client to process
                    sleep(120);
                }
                
            }
            
            //deal with any additional requests, if none close connections
            while(true)
            {
                if (!bullRoarer.checkClientConnected())
                {
                    bullRoarer.closeConnection();
                    messageStick.closeConnection();
                    break;
                }
                else
                {
                    String receivedData = bullRoarer.readClientRequest();
                    receivedData = elder.repairET(receivedData);
                    receivedData = elder.updateRequest(receivedData, addressObject.getHostAddress());
                    
                    System.out.println("received data contents:\n" + receivedData);
                    //send request to destination server and receive response
                    messageStick.sendQueryToServer(receivedData);
                    
                    
                    if (elder.requestedImageFile(receivedData))
                    {
                        System.out.println("retrieving image file");
                        isImage = true;
                        receivedImage = messageStick.retrieveImage();
                    }
                    else
                    {
                        isImage = false;
                        receivedData = messageStick.retrieveText();
                    }
                    
                    //check the content
                    if (!isImage)
                    {
                        receivedData = elder.checkContent(receivedData, address);
                    }
                    
                    //send response to client
                    if (isImage)
                    {
                        bullRoarer.sendResponse(receivedImage);
                    }
                    else
                    {
                        bullRoarer.sendResponse(receivedData);
                    }
                    
                    //wait 120 milliseconds for client to process
                    sleep(120);
                }
            }
        }
    }
    
    private static class Exit
    {
        public Boolean exit = false;
    }
    
}



package assignment2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Hashtable;
import java.util.Map;

/**
 *
 * @author 
 */
public class Elder
{
    private Hashtable<String, String> CapChange = new Hashtable<>();
    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/mm/yyyy HH:mm:ss");
    String destinationServer;
    
    public Elder()
    {
        createCapChangeDict();
    }
    
    /**
     * Populates the capital city change dictionary with a one-to-one mapping between
     * the original city name and the replacement city name
     */
    private void createCapChangeDict ()
    {
        CapChange.put("Canberra", "Jervis Bay");
        CapChange.put("Brisbane", "Longreach");
        CapChange.put("Darwin", "Alice Springs");
        CapChange.put("Sydney", "Queanbeyan");
        CapChange.put("Melbourne", "Albury");
        CapChange.put("Adelaide", "Coober Pedy");
        CapChange.put("Perth", "Geraldton");
        CapChange.put("Hobart", "Launceston");
    }
    
    /**
     * Takes a canonical web address and then returns INetAddress which is capable of
     * providing an IP address
     * @param String canonical web address
     * @return InetAddress 
     */
    public InetAddress getIPAddressFromDomain (String url)// throws UnknownHostException
    {
        try
        {
            String trimmedAddress;
            if (url.charAt(url.length() - 1) == '/')
            {
                trimmedAddress = url.substring(7, url.length() - 1);
            }
            else
            {
                trimmedAddress = url.substring(7);
            }
            
            destinationServer = InetAddress.getByName(trimmedAddress).getHostAddress();
            return InetAddress.getByName(trimmedAddress);
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    public InetAddress getIPAddressFromIpString (String ipString)
    {
        try
        {
            return InetAddress.getByName(ipString);
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * Receives a string containing the webpage content, this is then sent to the replaceCaps and
     * updateLinks functions before returning the string to the caller
     * @param webContent String containing the webpage content
     * @param address string containing the canonical web address
     * @return webContent string containing the modified web page content
     */
    public String checkContent(String webContent, String address)
    {
//        webContent = replaceCaps(webContent);
//        webContent = updateLinks(webContent, address);
        webContent = updateContentLength(webContent);
        return webContent;
    }
    
    /**
     * updates the content length to reflect the changes to the capital city names and urls
     * @param webcontent
     * @return 
     */
    private String updateContentLength (String webcontent)
    {
        try
        {
            Integer length = webcontent.length();            
            Integer substring = webcontent.indexOf("<!doctype html>");
            if (substring != -1)
            {
                length = length - webcontent.substring(0, substring).length();
                BufferedReader bufStringRead = new BufferedReader(new StringReader(webcontent));
                String returnContent = new String();
                String line;
                while ((line = bufStringRead.readLine()) != null)
                {
                    if (line.contains("Content-Length: "))
                    {
                        line = new String("Content-Length: " + length + "\n");
                        returnContent = returnContent.concat(line);
                    }
                    else
                    {
                        returnContent = returnContent.concat(line).concat("\n");
                    }
                }
                return returnContent;
            }
            else
            {
                return webcontent;
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return webcontent;
        }
    }
    
    /**
     * replaceCaps goes through the webContent string and replaces all occurrences of city names with
     * their designated replacement name as defined by the capChange Dictionary/HashMap
     * @param webContent string containing the web page content
     * @return webContent string containing the web page with capital city names replaced
     */
//    private String replaceCaps(String webContent)
//    {
//        Integer capChanges = 0;
//        for (Map.Entry element : CapChange.entrySet())
//        {
//            webContent = webContent.replace(element.getKey().toString(), element.getValue().toString());
//            capChanges += StringUtils.countMatches(webContent, element.getValue().toString());
//        }
//        System.out.println(dateFormatter.format(getTimestamp()) + ": Text changes: " + capChanges);
//        return webContent;
//    }
    
    /**
     * updateLinks takes a string containing the webpage contents, then replaces the canonical address with
     * the proxy servers ip address
     * @param webContent String containing the web page contents
     * @param address String containing the canonical address of the original webserver
     * @return webContent String with the web address replaced
     */
//    public String updateLinks(String webContent, String address)
//    {
//        String localAddress = getLocalAddress().concat("/");
//        webContent = webContent.replace(address, localAddress);
//        System.out.println(dateFormatter.format(getTimestamp()) +": Link rewrites, not including relative links: " + StringUtils.countMatches(webContent, localAddress));
//        return webContent;
//    }
    
    /**
     * updates the received request to have the destination servers ip address instead of the proxy/mirrors
     * ip address
     * @param request
     * @return 
     */
    public String updateRequest(String request, String newDestinationAddress)
    {
        try
        {
            request = request.replace(InetAddress.getLocalHost().getHostAddress(), newDestinationAddress);
            request = request.replace("3310", "80");
            request = request.replace("Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0", "comp3310/1.0");
            return request;
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * Returns a string containing the ip address of the proxy server
     * @return String containing ip address
     */
//    private String getLocalAddress()
//    {
//        try
//        {
//            InetAddress localAddress = InetAddress.getLocalHost();
//            return localAddress.getHostAddress();
//        }
//        catch (UnknownHostException ex)
//        {
//            ex.printStackTrace();
//            return "127.0.0.1";
//        }
//    }
    
    /**
     * Returns a LocalDateTime object containing the current date time timestamp
     * @return LocalDateTime object
     */
    public LocalDateTime getTimestamp()
    {
        LocalDateTime currentDateTime = LocalDateTime.now();
        return currentDateTime;
    }
    
    public String repairET(String query)
    {
        if (query.contains("ET"))
        {
            return query.replace("ET", "GET");
        }
        else
        {
            return query;
        }
    }
    
    public Boolean requestedImageFile (String request)
    {
        if (request.contains(".jpg"))
        {
            return true;
        }
        else if (request.contains(".png"))
        {
            return true;
        }
        else if (request.contains(".gif"))
        {
            return true;
        }
        else if (request.contains(".ico"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}



package Communications;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * handles all interaction between the client and the 
 * @author 
 */
public class BullRoarer
{
    ServerSocket servSock;
    Socket responseSock;
    LocalDateTime currentTime;
    PrintWriter printWriter;
    OutputStream outStream;
    InputStream inStream;
    InputStreamReader inStreamReader;
    BufferedReader bufRead;

    public BullRoarer(LocalDateTime currentTime)
    {
        this.currentTime = currentTime;
    }
    
    /**
     * Listens for a client connection request, then acts on behalf of the client for connections
     */
    public void listenForClient()
    {
        try
        {
            servSock = new ServerSocket(3310);
            responseSock = servSock.accept();
            inStream = responseSock.getInputStream();
            outStream = responseSock.getOutputStream();
            inStreamReader = new InputStreamReader(inStream, Charset.forName("UTF-8"));
            bufRead = new BufferedReader(inStreamReader);
            printWriter = new PrintWriter(outStream, true);
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
    
    /**
     * checks if the client is still connected to the proxy/mirror
     * @return 
     */
    public Boolean checkClientConnected()
    {
        try
        {
            if (inStream.read() == -1)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
   }
    
    /**
     * retrieves the next client request and sends it to the caller
     * @return 
     */
    public String readClientRequest()
    {
        try
        {
            StringBuilder receivedRequest = new StringBuilder();
            String temp;
            while ((temp = bufRead.readLine()) != null)
            {
                if (temp.contains("GET / HTTP"))
                {
                    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/mm/yyyy HH:mm:ss");
                    System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                }
                
                receivedRequest.append(temp).append("\r\n");
                if (temp.isBlank())
                {
                    receivedRequest.append("\n");
                    break;
                }
            }
            return receivedRequest.toString();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return new String();
        }
    }
    
    
    /**
     * sends response to client containing text file
     * @param response 
     */
    public void sendResponse(String response)
    {
        printWriter.println(response);
    }
    
    /**
     * sends response to client containing image file
     * @param imageData 
     */
    public void sendResponse(byte[] imageData)
    {
        printWriter.println(imageData);
    }
    
    /**
     * Closes connection to the client
     */
    public void closeConnection()
    {
        try
        {
            printWriter.close();
            responseSock.close();
            servSock.close();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}



package Communications;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * handles all interaction between the proxy/mirror and the destination webserver
 * @author 
 */
public class MessageStick
{
    InetAddress address;
    private Boolean verbose;
    private LocalDateTime currentTime;
    private Socket sock;
    private PrintWriter printWriter;
    private BufferedReader bufRead;
    private OutputStream outStream;
    private InputStream inStream;
    private DataInputStream dataStream;
    
    public MessageStick(InetAddress address, Boolean verbose, LocalDateTime currentTime)
    {
        this.address = address;
        this.verbose = verbose;
        this.currentTime = currentTime;
    }
    
    /**
     * handles the initial process of establishing a connection to the destination server
     * @param query
     * @return 
     */
    public Boolean connectToServer (String query)
    {
        try
        {
            sock = new Socket(address.getHostAddress(), 80);
            outStream = sock.getOutputStream();
            printWriter = new PrintWriter(outStream, true);
            inStream = sock.getInputStream();
            dataStream = new DataInputStream(inStream);
            bufRead = new BufferedReader(new InputStreamReader(inStream, Charset.forName("UTF-8")));
            return true;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
    }
    
    /**
     * retrieves a image file from destination server and passes it to caller
     * @return 
     */
    public byte [] retrieveImage ()
    {
        try
        {
            byte[] receivedImage = dataStream.readAllBytes();
//            byte[] receivedImage = byte[dataStream.];
            System.out.println("number of bytes in receivedImage: " + receivedImage.length);
            for (byte imgByte : receivedImage)
            {
                System.out.println(imgByte);
            }
            return receivedImage;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * retrieves text files from web server
     * @return 
     */
    public String retrieveText()
    {
        try
        {
            StringBuilder result = new StringBuilder();
            String temp = new String();
            DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/mm/yyyy HH:mm:ss");
            while ((temp = bufRead.readLine()) != null)
            {
                if (verbose)
                {
                    System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                }
                else
                {
                    if (temp.contains("GET / HTTP"))
                    {
                        System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                    }
                    else if (temp.contains("HTTP"))
                    {
                        System.out.println(dateFormatter.format(currentTime) + ": " + temp);
                    }
                }
                result = result.append(temp).append("\n");
                if (temp.contains("</html>"))
                {
                    result = result.append("\n");
                    break;
                }
            }
            return result.toString();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    /**
     * takes care of sending a request to the web server
     * @param query
     * @return 
     */
    public void sendQueryToServer(String query)
    {
        System.out.println("query being sent to server: \n" + query);
        printWriter.println(query);
    }
    
    /**
     * closes all connections to the web server and any related object
     */
    public void closeConnection()
    {
        try
        {
            bufRead.close();
            printWriter.close();
            sock.close();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}


Was This Post Helpful? 0
  • +
  • -

#11 NormR   User is offline

  • D.I.C Lover
  • member icon

Reputation: 870
  • View blog
  • Posts: 6,679
  • Joined: 25-December 13

Re: 1-to-1 proxy using sockets

Posted 12 June 2021 - 05:59 AM

I get a Compiler error:

Quote

error: package com.google.common.net does not exist


Can you explain how you want to use this program and how you want it to work?
I am confused by this line in the source:
String address = null; //destination server address goes here

How do you set your browser to use the proxy?
What url do you enter in the browser?
What does your program do when the browser connects to it?

This post has been edited by NormR: 12 June 2021 - 06:15 AM

Was This Post Helpful? 0
  • +
  • -

#12 pheonixfire   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 34
  • Joined: 26-July 17

Re: 1-to-1 proxy using sockets

Posted 14 June 2021 - 05:09 AM

sorry, that was a multitasking fail on my part
that line was originally set with a command line switch argument, just replace it with a web address

When it's running it can be accessed by a browser using the ip address and port 3310
effectively it forwards all requests on to the specified web server

the error is probably due to a missing dependency, did you add the guava-30 as a dependency?

hopefully I've answered all your queries
pheonixfire
Was This Post Helpful? 0
  • +
  • -

#13 NormR   User is offline

  • D.I.C Lover
  • member icon

Reputation: 870
  • View blog
  • Posts: 6,679
  • Joined: 25-December 13

Re: 1-to-1 proxy using sockets

Posted 14 June 2021 - 05:26 AM

Quote

add the guava-30 as a dependency
I do not use any software that supports adding a dependency.
My editor has a commandline that I can add jar files to. Why is guava-30 needed for the program?

What value should be assigned to address?
The code gives an error when I set address to my test server at 127.0.0.1:8080

Quote

java.net.UnknownHostException: 127.0.0.1:8080: invalid IPv6 address
at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1331)
at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1288)
at java.base/java.net.InetAddress.getByName(InetAddress.java:1238)
at OneToOneProxy2$Elder.getIPAddressFromIpString(OneToOneProxy2.java:276)
at OneToOneProxy2.main(OneToOneProxy2.java:97)
Exception in thread "main" java.lang.NullPointerException
at OneToOneProxy2$MessageStick.connectToServer(OneToOneProxy2.java:636)
at OneToOneProxy2.main(OneToOneProxy2.java:107)
Shutting Down

0 error(s)


Quote

it forwards all requests on to the specified web server

So your code does not expect the browser to be using a proxy.

One possible problem is not having a new thread to process the Socket returned by the accept method.

This post has been edited by NormR: 14 June 2021 - 05:57 AM

Was This Post Helpful? 0
  • +
  • -

#14 g00se   User is offline

  • D.I.C Lover
  • member icon

Reputation: 3737
  • View blog
  • Posts: 17,104
  • Joined: 20-September 08

Re: 1-to-1 proxy using sockets

Posted 14 June 2021 - 05:53 AM

As a general rule - if you want to give your code to someone to run where it contains dependencies, it's best to use a a build tool. For instance, if using Maven, you would just have given your pom.xml file in addition to your source and all would be well
Was This Post Helpful? 0
  • +
  • -

#15 pheonixfire   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 34
  • Joined: 26-July 17

Re: 1-to-1 proxy using sockets

Posted 15 June 2021 - 07:15 PM

Quote

Why is guava-30 needed for the program?

it provides address translation e.g fqdn -> ip address

Quote

What value should be assigned to address?

I have only used the local address with the port 3310
e.g. 192.168.1.1:3310

Quote

So your code does not expect the browser to be using a proxy.

not in the traditional sense, you connect to it like a normal website it will then forward all requests onto the destination server

Quote

One possible problem is not having a new thread to process the Socket returned by the accept method.

This wasn't necessary, the original assignment spec specified that it only needed to handle one connection at a time
I was considering how to handle multiple connections if I got it all working correctly though

Quote

As a general rule - if you want to give your code to someone to run where it contains dependencies, it's best to use a a build tool. For instance, if using Maven, you would just have given your pom.xml file in addition to your source and all would be well

I prefer to use ant over maven or gradle, I find it a lot simpler to add dependencies with it in Netbeans

Best Regards
pheonixfire
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2