재미있는 코드가 있어서 소개를 할까 합니다. Java 기반의 HTTP decoder입니다.
출처 : http://xeraph.com/5226932
주석 달아 봤습니다. C 언어와 같은 imperative programming에 익숙한 사람에게 유익할 듯 싶습니다.
public class NetworkForensicPuzzle {
public static void main(String[] args) throws IOException { // C언어의 main 과 비슷.
try {
EthernetDecoder eth = new EthernetDecoder(); // Ethernet 환경에서 패킷 분석을 하기 위한 decodet entry point 클래스
IpDecoder ip = new IpDecoder();
TcpDecoder tcp = new TcpDecoder(new TcpSessionTracker());
HttpDecoder http = new HttpDecoder();
HttpCallback callback = new HttpCallback(); // 사용부터 하고 선언은 뒤에 해도 되네요. 우왕ㅋ굳ㅋ
eth.register(EthernetType.IPV4, ip); // register라는 메소드는 모든 Decoder의 부모 클래스에서 virtual로 선언을 하고
// 각각의 하부 클래스에서 implementation(override)한 듯 보임.
// register의 처음 인자는 조건, 두번째 인자는 그 다음 Decoder인 듯.
ip.register(InternetProtocol.TCP, tcp);
tcp.register(80, http);
tcp.getSegmentCallbacks().register(callback); // tcp segment는 뭘까나? 아무래도 TCP Data 패킷이 잡혔을 때
// 발생시키는 callback을 의미하는 것 같은데... 맞나?
http.register(callback); // 상기 Decoder와 register 메세지의 형태가 좀 다르네요.
// register가 callback 클래스까지 명시해 줄 수 있도록 overload된 듯.
PacketInputStream is = new PcapFileInputStream(new File("evidence03.pcap")); // 파일로부터 읽어 들여서 stream 생성.
while (true) {
PcapPacket packet = is.getPacket(); // 패킷 읽어 들이고(end of file의 경우에는 exception이 일어 나는 듯)
eth.decode(packet); // eth라는 객체에 디코딩을 함(위에서 열거한 클래스를 따라 줄줄이 분석이 됨)
}
} catch (EOFException e) {
}
}
}
public class HttpCallback implements HttpProcessor, TcpSegmentCallback {
private TcpSegment segment = null;
// TcpSegmentCallback 클래스에서 override해야 하는 메소드로 보임. 뭘 뜻하는지는 잘 모르겠음.
// TcpSession은 TCP 통신의 송신자, 수신자의 값으로 유일하게 결정되는(may srcIP, dstIP, srcPort, dstPort를 key로 하는) 객채 정보이고
// TcpSegment는 아마도 하나의 TCP Data 패킷으로 예상이 됨(아님 말구 ㅋㅋ).
// Direction은 session상에서 보내는 거냐, 아니면 반대로 받는 거냐를 나타내는 인자인듯.
@Override
public void getSegment(TcpSession session, TcpSegment segment, Direction direction) {
this.segment = segment;
}
// 이놈은 어느 클래스에서 override한 것일까? 나도 모름. 어떤 놈이 파일을 요구하는 겨? ㅋㅋㅋ
@Override
public void getFile(String fileName, byte[] fileContent) {
}
// HttpDecoder 클래스의 decode 메소드 내부에서 HTTP request가 탐지되면 발생하는 callback. 맞나? ㅋㅋ
@Override
public void onRequest(HttpRequest request) {
}
// HttpDecoder 클래스의 decode 메소트 내부에서 HTTP request 및 HTTP response가 모두 탐지되었을 때 발생하는 callback.
@Override
public void onResponse(HttpRequest request, HttpResponse response) {
String contentType = response.getHeaderValue("Content-Type");
if (contentType.startsWith("image")) // Java에서 String 클래스는 startWith 라는 메소드도 존재하는 듯. 아, 부러워~
return;
System.out.printf("Content-Type: %s, User-Agent: %s:, Query String: %s\n", contentType, request
.getHeaderValue("User-Agent"), request.getQueryString());
}
}
HTTP 통신 과정에서 Content-Type이 "image"인 것을 제외한 나머지 HTTP request에 대한 정보를 출력해 주는 프로그램 같습니다. 제가 알고 있기로 Java는 클래스가 원래 기본적으로 pointer 라서 C++과 같이 포인터 type과 일반 type을 구분해 줄 필요가 없다는 얘기를 들었는데, 코드가 확실히 깔끔한 것 같네요. 하기야 C++에서도 reference type를 사용하면 되겠지만, 원래 C/C++ 프로그래머들이 pointer에 대한 직관적인 interface를 좋아해서리...
아, 그리고 역시나 Java의 garbage collection 의 강력함을 보는 것 같군요, 역시 객체 해제하는 코드는 없어도 되는군요. ㅎㅎ 아무튼 상기과 같은 방식으로의 HTTP Packet Sniffer도 디자인될 수 있다고 생각하시면 될 것 같습니다.
객체의 이벤트를 설정해 주는 방법은 언어에 따라 선호하는 방식이 많이 틀린 듯 합니다.
1. C : callback function의 pointer를 넘긴다.
2. C++ : 클래스 자체에서 virtual로 선언하고 그 하위 클래스에서 override를 시킨다. 실제 사용은 하위 클래스 객체를 생성해서 사용.
3. Pascal(Delphi) : event method도 결국 property이다. property 설정을 해 줘서 call을 하도록 한다.
4. Java : 상기와 같이 event method 들만을 모아서 별도의 클래스를 만들고 콜백 설정은 메소드 설정이 아닌 그 객체 설정으로 처리한다.
그래서 C++에서 Delphi의 매소드포인터를 구현해 놓은 Delegate 라이브러리들이 존재하죠..
이건 한국인이 만든것.
Ps. 그것때문인지 Java에서는 한 함수에 다 몰아놓고 Case로 구분하더군요 =_=;
Delegate 라이브러리라... 한번 분석을 해 봐야 겠네. 이런거 만드는 사람은 머리 속에 뭐가 들었을까나? ㅎㅎ
Case로 구분을 한다... 쉽게 말해서 델파이에서 Sender의 실제 Instance를 체크해 보는 것과 비스무리하다고 보면 되나? 우왕 굳. 근데 썩 좋은 방법은 아닐 듯 하구나.
Anderson은 이 모든 것들을 미리 간파를 하고 VCL을 설계했던 것이었나? 델파이 1.0 만들때 쯤 보니 Andersion 나이가 30대 중반이었던데...
에고.. 나는 지금 뭐하고 있는 건지... ㅜㅜ
음.. 생각을 해 봤는데 Event(Callback)을 별도의 클래스로 처리하는 경우 문제가 발생할 수도 있겠다는 생각이 듭니다.
델파이를 예로 들자면 Form1(TForm) 위에 Button1(TButton)을 올려 놓습니다.
그리고 Form1의 OnClick 이벤트와 Button1의 OnClick 이벤트를 각각 다르게 처리하고 싶다고 가정을 합니다.
이 경우 Form1과 Button1의 OnClick 이벤트(virtual function)이 생김새가 같은데,
C++의 경우 다중 상속에 의해서 골때리는 현상이 발생할 것 같고(ambiguity warning or error)
만약에 Callback 들이 interface(pure abstract function)로 구성되어 있다 해도 ambiguity 컴파일 에러가 날 것 같네요.