Вопрос по mbuf+pfil
весито ужас
не весит а вешает
Это можно сделать, но не средствами pfil. То есть в обработчике pfil ты можешь аллоцировать новый mbuf chain, создать пакет и отправить его. Но только нельзя его отправлять напрямую, то есть вызывать ip_output или ip_input это приведёт к куче скрытых проблем, таких как LOR или рекурсия. Правильно сделать это через netisr_dispatch.
Я так понимаю он весит хук на интерфейсНе на интерфейс, а на весь IP input и весь IP output.
Спасибо за ответ в понедельник почитаю маны что это такое =)
выходящий пакет(сниф с помощью вайршарка) IP header:
45 00 00 41 2c ba 40 00 40 06 89 7d c0 a8 02 02 c0 a8 01 2d
Пакет который получает пфил IP header
45 00 41 00 2C BA 00 40 40 06 89 7D C0 A8 02 02 C0 A8 01 2D
Кто-нибудь может объяснить сей еффект?(жирные числа перевернуты)
ntohs делается до поступления в pfil.
Шлю 2 пакета с клиента(сервет просто ожидает ресив и на экран выводит)
packet1: TestMessage.
packet2: 2nd message
применяю простейший код для модификации длины: struct mbuff** m
data это просто указатель на содержание пакета в мбуфф.
Код апплаится только на 1й пакет.
TEST[0]='G';
TEST[1]='\0';
int res=m_append(*m,2,TEST);
m_fixhdr(*m);
printf("res cames from m_append:%d \n",res);
printf("new data string is %s \n",data);
iph->ip_len+=2;//modifying IP header length
Затем пересчитываю чексуммы и заменяю их.
Сервер получает "Test Message.G\0d message" И отвечает с аск+25. (т.е пакет дошел чексуммы корректные) но число символов такое же как пакет1+пакет2. Нет дополнительных 2х символов
Выглядит как-будто я просто по чужой памяти пишу но не могу понять, в чем ошибка.
Спасибо
Непонятно объясняешь. Местами не ясно о каком пакете речь о mbuf или о TCP? Также непонятно о каком заголовке речь mbuf или TCP. Приведи больший кусок кода и объясни что хотел получить.
Генерирую следующий TCP обмен между клиент -сервер.
C --- SYN --->S
C<---SYN,ACK---S
C----ACK--->S
C----push, data="Test message." --->S
C----push,fin, data="2nd message" --->S
C<---- ACK+=25 ----- S
На каждый ТСР пакет вызывается pfil filter(struct mbuf **m,...). Вот об этой функции я и говорил.
Я проверяю что пакет меня интересующий и пробую менять поле data с пересчетом TCP & IP chtcksum. Если не менять длину пакета, то всё работает как я хочу.
Пытаюсь изменить длину пакета с data="Test message." следующим кодом(только на этот пакет)
TEST[0]='G';
TEST[1]='\0';
int res=m_append(*m,2,TEST);
m_fixhdr(*m);
printf("res cames from m_append:%d \n",res);
printf("new data string is %s \n",data);
iph->ip_len+=2;//modifying IP header length
И получаю странные результаты. На сервер приходит "Test Message.G\0d message"
Как правильно изменить длину фрейма?
Приведи больше кода, будет понятнее.
static int
filter_first(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,struct inpcb *inp)
{
pointer = (**m).m_hdr.mh_data;
iph = (struct ip *char*)pointer;
if (iph->ip_p!=6) return 0; //ignore all non TCP segments
if (!(
iph->ip_src.s_addr==ip1) && (iph->ip_dst.s_addr==ip2 ||
iph->ip_src.s_addr==ip2) && (iph->ip_dst.s_addr==ip1
return 0; //ignore all non ip1-ip2 segments
//lets do 3 way connection packets
tcph = (struct tcphdr*char*)iph + sizeof(struct ip;
unsigned char tf=tcph->th_flags;
//SYN&ACK (client initiated connection)
if (tf&TH_SYN && tf&TH_ACK)
{
server_seq=server_ack=client_seq=client_ack=0;
start_seq=tcph->th_seq;
start_ack=tcph->th_ack;
printf("connection between %u and %u established\n",iph->ip_src.s_addr,iph->ip_dst.s_addr);
printf("connection ip1<->ip2 established with seq=%u ack=%u\n",start_seq,start_ack);
}
if (tf&TH_PUSH)
{
//ok lets try dup packet
printf("calling dup\n");
ilen = (/*htons*/(iph->ip_len) - iph->ip_hl*4) + (tcph->th_off*4;
char * data=(char*char*)tcph + (tcph->th_off*4;
if (data[0]){};
if (ilen>0)// && data[0]=='T')
{
printf("test message packet detected\n");
printf("next %ld nextpkt %ld\n"quad_t*m)->m_hdr.mh_nextquad_t*m)->m_hdr.mh_nextpkt);
int len = iph->ip_hl*4;
printf("dumping packet len is %d\n",len);
for (int i=0;i<len;i++) printf("%02X "unsigned char)pointer[i]);
printf("\n");
unsigned short* ips=(unsigned short*) pointer;
//unsigned short ocs=ips[5];
printf("old IP checksum was %04X\n",ips[5]);
tcp_cksum(iph,tcph,data);
//Modifying Packet
// Вот тут я пытаюсь изменить длину первого пакета(начинается с Т)
if (data[0]=='T')
{
TEST[0]='G';
TEST[1]='G';
int res=m_append(*m,2,TEST);
m_fixhdr(*m);
printf("res cames from m_append:%d \n",res);
printf("new data string is %s \n",data);
iph->ip_len+=2;
}
//тут я тестил что просто изменение содержания пакетов работает(так тестил чексуммы)
//data[0]='Q';
//Restoring(recalculating) IP TCP checksums lengths and stuff
//lets recalculate ilen first
ilen = (/*htons*/(iph->ip_len) - iph->ip_hl*4) + (tcph->th_off*4;
ips[5]=0;
unsigned short ncs=cksum(pointer,iph->ip_hl*4);
printf("new IP checksum %02X\n",ncs);
ips[5]=ncs;
// Корявый код нужно переделать
printf("old TCP cksum was %04X\n",tcph->th_sum);
tcph->th_sum=0; //get rid of old checksum
memcpy(TEST,tcph,32);
memcpy(TEST+32,data,ilen);
for (int i=0;i<4;i++)
{
src_addr[i]=pointer[i+12];
dst_addr[i]=pointer[i+16];
}
for (int i=0;i<ilen+32;i++) tbuff2[i]=TEST[i];
unsigned short tsum=tcp_sum_calc(ilen+32, src_addr,dst_addr, ilen%2 , tbuff2);
printf("new TCP checksum %04X\n",htons(tsum;
tcph->th_sum=htons(tsum);
//data[0]='Q';
//struct mbuf* temp = (*m)->m_hdr.mh_nextpkt;
//(*m)->m_hdr.mh_nextpkt=mc2;
//mc2->m_hdr.mh_nextpkt=temp;
}
}
return 0;
}
Во-первых, ты не проверяешь, а если в mbuf данные нужной тебе длины вообще. Во-вторых, не проверяешь есть ли они в первом буфере цепочки, а ведь только в этом случае будет работать mtod. Конечно, IP стек уже позаботился о том, чтобы IP заголовок был там. Но вот о TCP заголовке он не позаботился. Поэтому нужно делать проверку и если условие не выполняется, то делать m_pullup. И конечно проверять не вернуло ли оно NULL.
Далее:
pointer = (**m).m_hdr.mh_data;
iph = (struct ip *char*)pointer;
iph = mtod(*m, struct ip *);
if (iph->ip_p!=6) return 0; //ignore all non TCP segments
!= IPPROTO_TCP
tcph = (struct tcphdr*char*)iph + sizeof(struct ip;
В заголовке могут быть ip options, поэтому:
*m = m_pullup(*m, iph->ip_hl << 2 + sizeof(struct tcphdr;
проверить что *m != NULL
tcph = (struct tcphdr *mtod(*m, char *) + iph->ip_hl << 2);
(кстати далее ты ilen вычисляешь правильно)
char * data=(char*char*)tcph + (tcph->th_off*4;
Вот тут уже могут начаться большие проблемы с тем, что данные идут не в первом члене цепочки mbuf, и более того, m_pullup может не удастся так, чтобы весь пакет был единым последовательным куском памяти. Поэтому, для того, чтобы эта программа была полноценной, придётся написать ещё много кода, который будет шариться по цепочкам mbuf. Пока же, на коротких пакетах всё будет работать и так. Но хотя бы надо пытаться сделать m_pullup на нужную тебе величину.
int res=m_append(*m,2,TEST);
m_fixhdr(*m);
AFAIK, m_fixhdr здесь излишний. m_append пересчитывает длину.
P.S. Смотрю дальше.
Шлю 2 пакета с клиента(сервет просто ожидает ресив и на экран выводит)Конечно так и должно быть. Ведь th_seq ты не увеличил на 2 в следующем сегменте. Вот получатель и прочитал из второго сегмента не с самого начала, а с третьего октета, ведь предыдущие два он уже получил в первом сегменте.
packet1: TestMessage.
packet2: 2nd message
...
Сервер получает "Test Message.G\0d message" И отвечает с аск+25. (т.е пакет дошел чексуммы корректные) но число символов такое же как пакет1+пакет2. Нет дополнительных 2х символов
Ты конечно можешь увеличить th_seq во втором сегменте, и наверное даже это получится. Но только в вакууме. Как только изменятся размеры пакетов, тайминги, появятся потери, то всё это перестанет работать. И не забываем о том, что mbuf может быть не contigous и m_pullup не сможет выполниться. Короче говоря, для реализации этой задачи нужно написать мини-tcp-стек. И если ты хочешь что бы он работал всегда и безглючно, то размер его будет приближаться к полноценному стеку. Поэтому такие задачи намного лучше решать в userland. Там сокеты уже позаботились о contigous memory и о том, чтобы ты не знал что такое фрагментация, потери, повторная пересылки и дупликаты.
Задача которая стоит сейчас написать прогрумму которая будет достаточно быстро просматривать трафик идущий через нее и модфицировать трафик(блочить изменять добавлять новые пакеты). Разве есть подобные решения в userspace?
Просто не могу найти нормальную документацию вот и тыкаюсь как котёнок. Не подскажете откуда вы это всё знаете?Во-первых, man 9 mbuf.
И также читать исходники. Например нам интересно, как правильно разбирать ip заголовок. На эту тему можно почитать sys/netinet/ip_input.c функцию ip_input. Также в системе есть три пакетных фильтра, и все они тоже разбирают ip заголовок. Значит можно почитать и их: sys/netinet/ipfw/ip_fw2.c, функция ipfw_chk sys/contrib/pf/net/pf.c функция pf_test.
Задача которая стоит сейчас написать прогрумму которая будет достаточно быстро просматривать трафик идущий через нее и модфицировать трафик(блочить изменять добавлять новые пакеты). Разве есть подобные решения в userspace?Если речь о модификации TCP, то только безумец будет делать это в ядре. Если не безумец, то это должен быть человек(команда) готовый к написанию своего TCP стека.
Поэтому лучше сразу делать в user land. Если речь идёт о каком-то контент-фильтре, то скорее всего сама контент-фильтрация будет самой тяжёлой функцией, а вовсе не пересылка данных из приложения в ядро и назад. Поэтому не стоит париться по поводу производительности сокетов.
лучше сразу делать в user land. Если речь идёт о каком-то контент-фильтре, то скорее всего сама контент-фильтрация будет самой тяжёлой функцией, а вовсе не пересылка данных из приложения в ядро и назад. Поэтому не стоит париться по поводу производительностиВы можете назвать(посоветовать) готовые решения? Просто производительность важна так как будет примерно трафик от активных 1-2х тысяч соединений. Или что почитать о userland спобах решениях. Не до конца представляю как можно сделать в userland контроль трафика который идет не тебе
http://www.snort.org/, либо http://www.juniper.net/us/en/products-services/security/isg-...
Если http, то либо http://www.citrix.com/English/ps2/products/product.asp?conte... , либо http://www.f5.com/products/big-ip/product-modules/local-traf...
Какая то конечная цель?
Если под фильтрацией подразумевается защита от вирусов, то это либо Если http, то либо http://www.citrix.com/English/ps2/products/product.asp?conte... , либо http://www.f5.com/products/big-ip/product-modules/local-traf...
Какая то конечная цель?
Это называется transparent proxy. С помощью ipfw fwd (например) трафик попадает локальному приложению вместо нормального назначения, приложение устанавливает соединение с нормальным назначением и прокачивает трафик через себя.
пытаюсь сделать следующий код(m - mbuf**) на интересующий меня фрейм:
struct mbuf* myown = m_dup*mM_DONTWAIT);
(**m).m_hdr.m_nextpkt = myown;
iph->ip_id++; //change id of previous frame
//recalc all checksums
Но если повесить tcpdump на эту машину видно что дополнительного фрейма не возникает.
Поглядел в ip_input.c и не нанешл обработки поля (*m).mhdr.m_nextpkt (смотрел ниже кода
if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_IN, NULL) != 0)
return;
if (m == NULL) /* consumed by filter */
return;
Получается, чтобы сгенерировать дополнительный фрейм нужно менять ядро? Или есть более простые способы?
PS читаю ман по netisr(9)
О том, как посылать сгенерированные в пакетном фильтре пакеты, я писал в одном из первых постов.
Пропустил. спасибо. Сейчас как раз про netisr и читаю
if data[0]=='A') && (dd==0
{
dd=1;
printf("got non zero A type PUSH frame trying to dupe\n");
//struct mbuf* myown = m_get(M_WAIT,EXT_CLUSTER);
//printf("alloc returns %ud\n"unsigned long)myown);
//*************** MYOWN frame ******************
myown=m_dup*mM_DONTWAIT);
printf("alloc returns %lu\n"unsigned long)myown);
unsigned char* pointer_ = (*myown).m_hdr.mh_data;
struct ip* iph_ = (struct ip *char*)pointer_;
struct tcphdr* tcph_ = (struct tcphdr*char*)iph_ + sizeof(struct ip;
int ilen_ = (/*htons*/(iph_->ip_len) - iph_->ip_hl*4) + (tcph_->th_off*4;
unsigned char * data_=(char*char*)tcph_ + (tcph_->th_off*4;
printf("my own length is %d with %c\n",ilen_,data_[0]);
data_[0]='C';
//recheck IP checksum
unsigned short* ips_=(unsigned short*) pointer_;
ips_[5]=0; //delete old_checksum(IP)
unsigned short ncs_=cksum(pointer_,iph_->ip_hl*4);
ips_[5]=ncs_;
//recheck TCP checksum
printf("old TCP cksum was %04X\n",tcph_->th_sum);
tcph_->th_sum=0; //get rid of old checksum
tcph_->th_seq+=100;
//tcph_->th_ack+=100;
iph_->ip_id+=1;
memcpy(TEST,tcph_,32);
memcpy(TEST+32,data_,ilen_);
for (int i=0;i<4;i++)
{
src_addr[i]=pointer_[i+12];
dst_addr[i]=pointer_[i+16];
}
for (int i=0;i<ilen+32;i++) tbuff2[i]=TEST[i];
unsigned short tsum_=tcp_sum_calc(ilen+32, src_addr,dst_addr, ilen_%2 , tbuff2);
printf("new TCP checksum %04X\n",htons(tsum_;
tcph_->th_sum=htons(tsum_);
int res = netisr_dispatch(NETISR_IP,myown);
//int res = netisr_queue(NETISR_IP,myown);
printf("netisr_dispatch returns %d\n",res);
//return 0;
//***************** OLD FRAME **************************
//mark and modifying packet
data[0]='B'; //fixed
//recheck IP checksum
unsigned short* ips=(unsigned short*) pointer;
ips[5]=0; //delete old_checksum(IP)
unsigned short ncs=cksum(pointer,iph->ip_hl*4);
ips[5]=ncs;
//recheck TCP checksum
printf("old TCP cksum was %04X\n",tcph->th_sum);
tcph->th_sum=0; //get rid of old checksum
memcpy(TEST,tcph,32);
memcpy(TEST+32,data,ilen);
for (int i=0;i<4;i++)
{
src_addr[i]=pointer[i+12];
dst_addr[i]=pointer[i+16];
}
for (int i=0;i<ilen+32;i++) tbuff2[i]=TEST[i];
unsigned short tsum=tcp_sum_calc(ilen+32, src_addr,dst_addr, ilen%2 , tbuff2);
printf("new TCP checksum %04X\n",htons(tsum;
tcph->th_sum=htons(tsum);
//ncs=ncs_;
}
Не проверяю много вещей(выделение памяти и т.п. пока всё еще пытаюсь разобраться в целом как это работает.
Вот делаю так, на сервер не приходит доп фрейм, я как то неправильно копирую цепочку mbuf?
Доходит только обычный фрейм измененный( я хочу изменить один на B и отправить дополнительный на C) длина фрейма 100.
PS неправильно длину заголовка считаю, пока это не так важно так как опций нет.
Смотри tcpdumpом на самой машине с пакетным фильтром, а не на сервере. Кстати надо делать netisr_queue потому что dispatch может приводит к рекурсивному выполнению IP стека.
UPD вру при queue происходит чтото странное, буду разбираться
Оставить комментарий
Gunsleader
Кто-нибудь пробовал использовать PFIL для обработки пакетов? Я так понимаю он весит хук на интерфейс и дает доступ к мбуф, Таким образом можно менять трафик. Но кто-нибудь пробовал создать новый фрейм для посылки(сгенерить лишний фрейм в сетевом обмене)? Возможно ли это средствами pful+mbuf?Ось Фрибсд