2016-08-29 9 views
2

У меня есть Разветвляющихся HTTP прокси реализованный на моем Ubuntu 14.04 x86_64 со следующей схемой (Я сообщаю существенный код и псевдокод просто, чтобы показать концепцию):Как видеть заголовки TCP, IP в моем HTTP-прокси?

  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; что касается второго, я бы просто сделал +1 на счетчике каждый раз, когда char buffer[1500] заполняется данными, когда я send() или recv() полный пакет.

Я понял, что это неверно: SOCK_STREAM не имеет понятия пакета, это просто непрерывный поток байтов! char buffer[1500] Я использую в точках 7. и 8. имеет полезную статистику, я могу установить ее емкость 4096 байт, и все же я не мог отслеживать переданные или полученные TCP-пакеты, поскольку TCP имеет сегменты, а не пакеты ,

Я не смог разобрать char buffer[], ища флаг SYN в заголовке TCP, потому что заголовки IP и TCP удалены из заголовка (из-за уровня, над которым я работаю, указанного с флагом IPPROTO_TCP), и, если я хорошо понимал, char buffer[] содержит только полезную нагрузку, бесполезную для меня.

Так что, если я работаю на слишком высоком уровне, я должен идти ниже: как только я увидел простой raw сокетов сниффер, где unsigned char buffer[65535] низвержен на struct ethhdr, iphdt, tcphdr и он мог видеть все флаги всех заголовки, все статистические данные, которые меня интересуют!

После радости разочарование: начиная с raw сокеты работают на низком уровне, у них нет некоторых понятий, жизненно важных для моего прокси; raw розетки не могут bind, listen и accept; мой прокси-сервер прослушивает фиксированный порт, но raw сокеты не знают, что такое порт, он относится к уровню TCP и bind к указанному интерфейсу с setsockopt.

Так что, если я бы socket(PF_INET, SOCK_RAW, ntohs(ETH_P_ALL)) я должен быть в состоянии разобрать буфер, где я recv() и send() на .7 и .8, но я должен использовать recvfrom() и sendto() ... но все это звучит довольно грязно, и envolves хороший рефакторинг моего кода.

Как сохранить целостность структуры моего прокси-сервера (bind, listen, accept на фиксированный порт и интерфейс) и увеличить мою линию видимости для заголовков IP и TCP?

+0

платформа ......? – pm100

+0

Я отредактирую вопрос для получения более подробной информации. – elmazzun

+0

Очень маловероятно, что вы получаете UDP с прокси-сервером HTTP вообще. –

ответ

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. Вы захотите отфильтровать эти пакеты.