/**
 * HttpSniff.java
 *
 * @author Wanderson C. Bragança <wanderson.wbc@gmail.com>
 * @link http://www.wanderson.wordpress.com
 * @copyright Copyright © 2009
 * @version  11/04/2009
 */

import java.io.*;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.JOptionPane;
import jpcap.*;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;

public class HttpSniff implements PacketReceiver
{
    public static class Pair
    {

        public String key;
        public String value;

        public Pair(String s, String s1)
        {
            key = s;
            value = s1;
        }
    }


    private static SimpleDateFormat fmtLog = new SimpleDateFormat("[dd-MM-yyyy HH:mm:ss]");
    private int port;
    private boolean skipMediaRequest;
    private boolean skipGoogleToolbarQuery;
    private boolean skipHeader;
    private boolean skipResponse;
    private boolean printCookie;
    private boolean ignoreLocalhost;
    private String localhost;
    private JpcapCaptor captor;
    private Thread thread;
    private List listeners;
    private HashMap logMap;
    private HashMap followWriteMap;
    private HashMap followReadMap;
    private HashMap pairMap;
    private List skipPorts;
    public String url;

    public HttpSniff()
        throws IOException
    {
        port = 80;
        skipMediaRequest = true;
        skipGoogleToolbarQuery = true;
        skipHeader = true;
        skipResponse = true;
        printCookie = false;
        ignoreLocalhost = false;
        captor = null;
        thread = null;
        listeners = Collections.synchronizedList(new ArrayList());
        logMap = new HashMap();
        followWriteMap = new HashMap();
        followReadMap = new HashMap();
        pairMap = new HashMap();
        skipPorts = new ArrayList();
        localhost = InetAddress.getLocalHost().getHostAddress();
        if(localhost.equals("127.0.0.1"))
        {
            //System.err.println("Cancelado n?o pode capturar localhost");
            System.exit(1);
        }
    }

    public void addSniffListener(HttpSniffListener httpsnifflistener)
    {
        if(!listeners.contains(httpsnifflistener))
        {
            listeners.add(httpsnifflistener);
        }
    }

    public void removeSniffListener(HttpSniffListener httpsnifflistener)
    {
        listeners.remove(httpsnifflistener);
    }

    public void receivePacket(Packet packet)
    {
        try
        {
            if(packet instanceof TCPPacket)
            {
                TCPPacket tcppacket = (TCPPacket)packet;
                processTCPPacket(tcppacket);
            }
        }
        catch(Throwable throwable)
        {
            throwable.printStackTrace();
        }
    }

    protected void processTCPPacket(TCPPacket tcppacket)
        throws IOException
    {
        if(tcppacket.src_port != port && tcppacket.dst_port != port)
        {
            return;
        }
        boolean flag = tcppacket.src_port == port;
        String s = tcppacket.src_ip.getHostAddress();
        String s1 = tcppacket.dst_ip.getHostAddress();
        String s2 = flag ? (new StringBuilder()).append(s).append(":").append(tcppacket.dst_port).toString() : (new StringBuilder()).append(s1).append(":").append(tcppacket.src_port).toString();
        if(ignoreLocalhost && (s.equals(localhost) || s1.equals(localhost)))
        {
            return;
        }
        if(tcppacket.psh || tcppacket.ack && tcppacket.data.length > 0)
        {
            if(tcppacket.data.length == 0)
            {
                return;
            }
            if(tcppacket.src_port == port)
            {
                if(!tcppacket.psh)
                {
                    Object obj = (List)followReadMap.get(Integer.valueOf(tcppacket.dst_port));
                    if(obj == null)
                    {
                        obj = new ArrayList();
                        followReadMap.put(Integer.valueOf(tcppacket.dst_port), obj);
                    }
                    ((List) (obj)).add(tcppacket.data);
                    return;
                }
                if(tcppacket.psh && tcppacket.ack)
                {
                    List list = (List)followReadMap.get(Integer.valueOf(tcppacket.dst_port));
                    if(list != null)
                    {
                        int i = 0;
                        for(Iterator iterator = list.iterator(); iterator.hasNext();)
                        {
                            byte abyte2[] = (byte[])iterator.next();
                            i += abyte2.length;
                        }

                        byte abyte0[] = new byte[i];
                        int k = 0;
                        for(Iterator iterator2 = list.iterator(); iterator2.hasNext();)
                        {
                            byte abyte4[] = (byte[])iterator2.next();
                            System.arraycopy(abyte4, 0, abyte0, k, abyte4.length);
                            k += abyte4.length;
                        }

                        tcppacket.data = abyte0;
                        followReadMap.remove(Integer.valueOf(tcppacket.dst_port));
                    }
                }
                if(tcppacket.data[0] == 72 && tcppacket.data[1] == 84 && tcppacket.data[2] == 84 && tcppacket.data[3] == 80)
                {
                    processHttpResponse(tcppacket);
                }
            } else
            if(tcppacket.dst_port == port)
            {
                if(!tcppacket.psh)
                {
                    Object obj1 = (List)followWriteMap.get(Integer.valueOf(tcppacket.src_port));
                    if(obj1 == null)
                    {
                        obj1 = new ArrayList();
                        followWriteMap.put(Integer.valueOf(tcppacket.src_port), obj1);
                    }
                    ((List) (obj1)).add(tcppacket.data);
                    return;
                }
                if(tcppacket.psh && tcppacket.ack)
                {
                    List list1 = (List)followWriteMap.get(Integer.valueOf(tcppacket.src_port));
                    if(list1 != null)
                    {
                        int j = 0;
                        for(Iterator iterator1 = list1.iterator(); iterator1.hasNext();)
                        {
                            byte abyte3[] = (byte[])iterator1.next();
                            j += abyte3.length;
                        }

                        byte abyte1[] = new byte[j];
                        int l = 0;
                        for(Iterator iterator3 = list1.iterator(); iterator3.hasNext();)
                        {
                            byte abyte5[] = (byte[])iterator3.next();
                            System.arraycopy(abyte5, 0, abyte1, l, abyte5.length);
                            l += abyte5.length;
                        }

                        tcppacket.data = abyte1;
                        followWriteMap.remove(Integer.valueOf(tcppacket.src_port));
                    }
                }
                if(tcppacket.data[0] == 80 && tcppacket.data[1] == 79 && tcppacket.data[2] == 83 && tcppacket.data[3] == 84 || tcppacket.data[0] == 71 && tcppacket.data[1] == 69 && tcppacket.data[2] == 84)
                {
                    processHttpRequest(tcppacket);
                } else
                {
                    System.out.println((new StringBuilder()).append("[Pacote Invalido] ").append(new String(tcppacket.data)).toString());
                }
            }
        }
    }

    private int getHeaderLength(byte abyte0[])
    {
        for(int i = 0; i < abyte0.length - 4; i++)
        {
            if(abyte0[i + 0] == 13 && abyte0[i + 1] == 10 && abyte0[i + 2] == 13 && abyte0[i + 3] == 10)
            {
                return i;
            }
        }

        return abyte0.length;
    }

    protected void processHttpResponse(TCPPacket tcppacket)
    {
        TCPPacket tcppacket1 = (TCPPacket)pairMap.get(Integer.valueOf(tcppacket.dst_port));
        if(skipPorts.contains(Integer.valueOf(tcppacket.dst_port)))
        {
            return;
        }
        if(skipResponse)
        {
            return;
        }
        int i = getHeaderLength(tcppacket.data);
        String s = new String(tcppacket.data, 0, i);
        Properties properties = new Properties();
        Scanner scanner = new Scanner(s);
        do
        {
            if(!scanner.hasNextLine())
            {
                break;
            }
            String s1 = scanner.nextLine();
            int j = s1.indexOf(":");
            if(j != -1)
            {
                String s3 = s1.substring(0, j);
                String s4 = s1.substring(j + 1).trim();
                properties.setProperty(s3, s4);
            }
        } while(true);
        scanner.close();
        String s2 = properties.getProperty("Server");
        if(skipGoogleToolbarQuery && s2 != null && s2.startsWith("GWS/"))
        {
            return;
        }
        System.out.println((new StringBuilder()).append("[Resposta] ").append(tcppacket.data.length).append(" bytes").append(tcppacket1 != null ? " pair" : "").toString());
        if(!skipHeader)
        {
            System.out.println(new String(tcppacket.data, 0, i));
            System.out.println();
        }
    }

    protected void processHttpRequest(TCPPacket tcppacket)
        throws IOException
    {
        int i = getHeaderLength(tcppacket.data);
        String s = new String(tcppacket.data, 0, i);
        Scanner scanner = new Scanner(s);
        String s1 = scanner.nextLine();
        String s2 = s1.split(" ")[0];
        String s3 = s1.split(" ")[1];
        if(skipMediaRequest)
        {
            String s4 = s3.toLowerCase();
            if(s4.endsWith(".jpg") || s4.endsWith(".gif") || s4.endsWith(".jpeg") || s4.endsWith(".png") || s4.endsWith(".swf") || s4.endsWith(".css") || s4.endsWith(".bmp"))
            {
                skipPorts.add(Integer.valueOf(tcppacket.src_port));
                return;
            }
        }
        Properties properties = new Properties();
        ArrayList arraylist = new ArrayList();
        do
        {
            if(!scanner.hasNextLine())
            {
                break;
            }
            String s5 = scanner.nextLine();
            int j = s5.indexOf(":");
            if(j != -1)
            {
                String s8 = s5.substring(0, j);
                String s10 = s5.substring(j + 1).trim();
                properties.setProperty(s8, s10);
                arraylist.add(new Pair(s8, s10));
            }
        } while(true);
        scanner.close();
        String s6 = properties.getProperty("Host");
        if(s6 == null)
        {
            s6 = tcppacket.dst_ip.getHostAddress();
        }
        if(skipGoogleToolbarQuery && s6 != null && s6.equals("toolbarqueries.google.co.kr"))
        {
            skipPorts.add(Integer.valueOf(tcppacket.src_port));
            return;
        }
        String s7 = tcppacket.src_ip.getHostAddress();
        String s9 = String.format("[ %s ] %s http://%s%s", new Object[] {
            s7, s2, s6, s3
        });
//        JOptionPane.showMessageDialog(null,s9);
//        System.out.println(s9);
        url = s9;
        PrintWriter printwriter = (PrintWriter)logMap.get(s7);
        if(printwriter == null)
        {
            (new File("weblogs")).mkdir();
            File file = new File("weblogs", String.format("http-%s.txt", new Object[] {
                s7
            }));
            printwriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file, true)), true);
        }
        printwriter.println(String.format("%s %s http://%s%s", new Object[] {
            fmtLog.format(new Date()), s2, s6, s3
        }));
        if(!skipHeader)
        {
            properties.list(System.out);
            System.out.println();
        }
        if(printCookie)
        {
            String s11 = properties.getProperty("Cookie");
            if(s11 != null)
            {
                System.out.println((new StringBuilder()).append("Cookie: ").append(s11).toString());
                System.out.println();
            }
        }
        for(Iterator iterator = listeners.iterator(); iterator.hasNext();)
        {
            HttpSniffListener httpsnifflistener = (HttpSniffListener)iterator.next();
            try
            {
                httpsnifflistener.httpRequested(s2, s6, s3, properties, arraylist);
            }
            catch(Throwable throwable)
            {
                throwable.printStackTrace();
            }
        }

    }

    public void startCapture(NetworkInterface networkinterface)
        throws IOException
    {
        if(captor != null)
        {
            throw new IllegalStateException("Sniffer ja esta em execuçao");
        } else
        {
            captor = JpcapCaptor.openDevice(networkinterface, 2000, false, 50);
            captor.loopPacket(-1, HttpSniff.this);     

            return;
        }
    }

    public void stopCapture()
    {
        if(captor != null)
        {
            captor.breakLoop();
            captor = null;          
        }
    }

    public void run()
        throws Exception
    {
        int i = 3;        
        NetworkInterface anetworkinterface[] = JpcapCaptor.getDeviceList();
        this.startCapture(anetworkinterface[i]);        
    }


}
