2016-08-29 5 views
2

나는 다음과 같은 기법 (난 그냥 개념을 보여주기 위해 필수 코드와 의사를보고있어) 내 우분투 14.04 x86_64의에 구현 된 포크 (fork) HTTP 프록시 있습니다HTTP 프록시에서 TCP, IP 헤더를 보는 방법은 무엇입니까?

  1. socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)을;
  2. bind(socketClient,(struct sockaddr*)&addr, sizeof(addr));
  3. listen(socketClient, 50);
  4. newSocket = accept(socketClient, (struct sockaddr*)&cliAddr, sizeof(cliAddr));
  5. 클라이언트로부터 요청을 받아 IP 주소에서 요청 된 호스트 이름을 분석합니다.
  6. fork() 원격 서버에 대한 연결을 열어 요청을 처리하십시오.
  7. 자식 프로세스 : GET 요청 인 경우 원래 요청을 서버로 보내고 서버가 데이터를 보내는 동안 서버에서 클라이언트로 데이터를 보냅니다.
  8. 자식 프로세스 : else CONNECT 요청 인 경우 200 ok 문자열을 클라이언트에 보내고 클라이언트 소켓 설명자와 서버 소켓 설명자를 모두 select()으로 폴링합니다. 서버 소켓에서 데이터를 읽으면이 데이터를 클라이언트에 보냅니다. 그렇지 않으면 클라이언트 소켓에서 데이터를 읽으면이 데이터를 서버로 보냅니다.

좋은 점은이 프록시가 작동한다는 것입니다. 나쁜 점은 이제 통계를 수집해야한다는 것입니다. 관심이있는 데이터를 얻을 수없는 수준에서 작업하고 있기 때문에 나쁘다. 페이로드는 신경 쓰지 않고 IP 및 TCP 헤더를 확인해야한다.

예를 들어, 내가 관심 :

  • 연결 추적;
  • 보내고받은 패킷 수입니다.

TCP 헤더에서 SYN 플래그, SYN/ACK 및 마지막 ACK를 확인합니다. 두 번째 경우, 나는 char buffer[1500]이 전체 패킷 일 때마다 send() 또는 recv() 일 때마다 +1 카운터를 수행 할 것입니다.

나는 이것이 올바르지 않다는 것을 깨달았습니다 : SOCK_STREAM은 패킷의 개념을 가지고 있지 않습니다. 단지 연속 된 바이트 스트림입니다! char buffer[1500] 제가 유용한 정보를 가지고 있습니다. 유용한 통계가 있습니다. 4096 바이트까지 용량을 설정할 수 있지만, TCP가 세그먼트 이 아니라이 아니기 때문에 보내거나받은 TCP 패킷을 추적 할 수 없었습니다. .

IPPROTO_TCP 플래그로 지정되어 있기 때문에 IP 헤더와 TCP 헤더가 헤더에서 제거되었으므로 (TCP 헤더에서 SYN 플래그를 찾는) char buffer[]을 구문 분석 할 수 없습니다. 잘 이해하고, char buffer[]은 페이로드 만 포함하고 있기 때문에 쓸모가 없습니다. 내가 unsigned char buffer[65535]struct ethhdr, iphdt, tcphdr에 캐스팅됐다 간단한 raw 소켓 스니퍼를보고하면 그것은 모든모든의 플래그를 을 볼 수 있었다 : 나는 너무 높은 수준에서 일하고 있어요 경우

그래서, 나는 낮은 가야한다 헤더, 내가 관심있는 모든 통계!

기쁨을 얻은 후 실망 : raw 소켓이 낮은 수준에서 작동하기 때문에 프록시에 중요한 개념이 없습니다. raw 소켓은 bind, listenaccept이 될 수 없습니다. 내 프록시는 고정 포트에서 수신 대기 중이지만 raw 소켓은 포트가 무엇인지 모르고 TCP 레벨에 속하며 bind은 지정된 인터페이스에 setsockopt으로 지정됩니다. 내가 socket(PF_INET, SOCK_RAW, ntohs(ETH_P_ALL))을했다면

그래서, 나는 recv()과 0.7 및 0.8에서 send(),하지만 난 recvfrom()sendto()를 사용해야 버퍼를 구문 분석 할 수 있어야합니다 ...하지만이 모든 아주 지저분한 소리, 그리고 내 코드를 훌륭하게 리팩토링한다.

프록시 (고정 포트 및 인터페이스에 bind, listen, accept)의 구조를 그대로 유지하고 IP 및 TCP 헤더에 대한 내 비전을 늘리려면 어떻게해야합니까?

+0

플랫폼 ......? – pm100

+0

자세한 내용은 질문을 편집하겠습니다. – elmazzun

+0

HTTP 프록시가있는 UDP를 전혀 얻지 못할 가능성이 있습니다. –

답변

2

내 제안은 예를 들어, 응용 프로그램의 다른 스레드에서 원시 소켓을 여는 것입니다. 모든 트래픽을 감지하고 주소 및 포트 번호별로 관련 패킷을 필터링하십시오. 기본적으로 당신은 당신의 자신의 패킷 스니퍼를 구현하려는 : 당신이 인터페이스는 프록시의 트래픽을 사용하는 것입니다 알고 있다면 당신은 또한 특정 인터페이스에 그 원시 소켓을 바인딩 할 수 있습니다

int sniff() 
{ 
    int sockfd; 
    int len; 
    int saddr_size; 
    struct sockaddr saddr; 
    unsigned char buffer[65536]; 

    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 
    if (sockfd < 0) { 
     perror("socket"); 
     return -1; 
    } 
    while (1) { 
     saddr_size = sizeof(saddr); 
     len = recvfrom(sockfd, buffer, sizeof(buffer), 0, &saddr, &saddr_size); 
     if (len < 0) { 
      perror("recvfrom"); 
      close(sockfd); 
      return -1; 
     } 

     // ... do the things you want to do with the packet received here ... 
    } 
    close(sockfd); 
    return 0; 
} 

. 예를 들어, "eth0를"에 바인딩 :

setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 4); 

사용 getpeername()getsockname() 기능은 TCP 연결의 로컬 및 원격 주소와 포트 번호를 찾기 위해 호출합니다. 패킷을 필터링하여 필터링 할 수 있습니다.

관련 문제