Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.114.94] |
|
Сообщ.
#1
,
|
|
|
Уважаемые форумчане, подскажите пожалуйста кто сталкивался с такой проблемой или хотя бы в каком месте копать.
Суть проблемы такова. Пытаюсь выдавать ICMP пакеты. Написал класс, использующий функции библиотеки winsock2.h. Сам метод класса не стал пока выкладывать. Дело в том, ошибку возвращает функция sendto, в том случае, если раскомментировать закоментированные строчки кода. Т.е. если я пытаюсь отдать ей данные, веденные с формы. Как это связано я просто не могу понять. Среда C++Builder5. Думал может старый компилятор. Поставил Borland2007, перекинул исходники класса, ничего не меняя. Создал такую же форму с Edit и кнопочками, в общем повторил интерфейс полностью. И все заработало! Ну я подумал, проблема решена, но сегодня опять столкнулся с ошибкой функции sendto и опять по непонятной причине, но теперь уже ошибку вызывает объект Label на форме. Если он обновляется, то функция выдает ошибку, если его не трогать, то не выдает. Ошибку выдает 10013 - это в Borland2007 в пятом не помню, возможно такая же. Компилировал на другом компе - сначала не выдавал ошибку, потом что то на форме добавил - стал выдавать. Короче полная для меня неясность, если кто в курсе просветите! //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonClick(TObject *Sender) { tICMP ICMP1; unsigned char DataOut[512]; // unsigned char d = StrToInt(EditDataOut->Text); for (int i=0; i<100; i++) { DataOut[i] = 0x55; // DataOut[i] = d; } AnsiString Res = ICMP1.SendData("192.168.1.1", DataOut, 100); if (Res != "OK") { ShowMessage(Res); return; } } //----------------------------------------------------------------- Добавлено Еще кое что вспомнил! Ошибка вылетает даже если раскоментировать только верхнюю строчку, т.е. где объявляется переменная char и ей присваивается значение из объекта Edit. Таким образом связь этих двух событий вообще становится непонятной.. |
Сообщ.
#2
,
|
|
|
Columbo
Цитата WSAEACCES 10013 (0x271D) An attempt was made to access a socket in a way forbidden by its access permissions. Файрволл, антивирус случайно не блокируют твою программу? Какой-нибудь новый софт недавно устанавливал? |
Сообщ.
#3
,
|
|
|
Цитата Columbo @ Еще кое что вспомнил! Ошибка вылетает даже если раскоментировать только верхнюю строчку, т.е. где объявляется переменная char и ей присваивается значение из объекта Edit. Практически сразу возникает вопрос - а что будет, если: //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonClick(TObject *Sender) { tICMP ICMP1; unsigned char DataOut[512]; // unsigned char d = StrToInt(EditDataOut->Text); unsigned char d = 0x55; for (int i=0; i<100; i++) { DataOut[i] = d; } AnsiString Res = ICMP1.SendData("192.168.1.1", DataOut, 100); if (Res != "OK") { ShowMessage(Res); return; } } //--------------------------------------------------------------------------- Сомнительно выглядит возврат функции строкой. Достаточно вернуть NO_ERROR (=0), но это дело вкуса. |
Сообщ.
#4
,
|
|
|
Как всегда, форум не программистов, в экстрасенсов. Автор, где тобой написанный класс для ицмп?
Примеров в сети два вагона, не пойму в чем проблема взять готовое http://tangentsoft.net/wskfaq/examples/dllping.html ? |
Сообщ.
#5
,
|
|
|
Спасибо за участие, коллеги!
Итак начну отвечать в режиме LIFO: Цитата nemez @ Автор, где тобой написанный класс для ицмп? Примеров в сети два вагона, не пойму в чем проблема взять готовое http://tangentsoft.net/wskfaq/examples/dllping.html ? Дело в том, что я хочу использовать ICMP пакеты для обмена данными, а в библиотеке ICMP.dll функция SendEchoRequest кажется ждет ответа без искажения данных, т.е. что послал - то и принял. А мне надо послал одно - принял что то другое. Вот метод класса: AnsiString tICMP::SendData(char* ip_addres, unsigned char* OutBuf, size_t num) { sockAddrLocal.sin_addr.S_un.S_addr = inet_addr(ip_addres); sockAddrLocal.sin_family = AF_INET; pIcmpHeader = (struct icmp *) IcmpSendPacket; // Point at the data area pIcmpHeader->icmp_type = ICMP_ECHO; // then fill in the data. pIcmpHeader->icmp_code = 0; // Use the Sockman instance pIcmpHeader->icmp_id = hInstance; // handle as a unique ID. pIcmpHeader->icmp_seq = 0; // It's important to reset pIcmpHeader->icmp_cksum = 0; // the checksum to zero. iPacketSize = ICMP_HEADERSIZE + num; for (size_t i=ICMP_HEADERSIZE, j=0; j<num; i++, j++) { IcmpSendPacket[i] = OutBuf[j]; } pIcmpHeader->icmp_cksum = InternetChksum((LPWORD)pIcmpHeader, iPacketSize); if (pIcmpHeader->icmp_cksum !=0 ) { iSentBytes = sendto(hSocket, (LPSTR) IcmpSendPacket, iPacketSize, NO_FLAGS, (LPSOCKADDR) &sockAddrLocal, sizeof(sockAddrLocal)); if (iSentBytes == SOCKET_ERROR) { int err = WSAGetLastError(); return "Error.\r\nThe sendto() function returned a socket error: " + IntToStr(err); } if (iSentBytes != iPacketSize) { return "Error.\r\nWrong number of bytes sent: " + IntToStr(iSentBytes); } } return "OK"; } Повторюсь еще раз, программа работает, если не используется объект Edit, при этом не важно что записывается в массив: константа или переменная. Как строка из Edit влияет на функцию sendto - для меня тайна покрытая мраком. На другом компиляторе программа заработала и с Edit, но потом начала глючить при использовании объекта Label, причем зависит от того какая строка выводится на экран. Добавлено Цитата ЫукпШ @ Сомнительно выглядит возврат функции строкой Ну просто так удобнее выводить на экран и придумывать коды не надо. По поводу Вашего примера реализации - будет работать, Edit же не используется. Добавлено Цитата Pacific @ Файрволл, антивирус случайно не блокируют твою программу? Какой-нибудь новый софт недавно устанавливал? Нет ничего такого не делал. Опять повторюсь - пакеты высылаются, но при определенных обстоятельствах возникает облом. |
Сообщ.
#6
,
|
|
|
Есть ли уверенность, что размер (массива ?)"IcmpSendPacket"
действительно не меньше "iPacketSize = ICMP_HEADERSIZE + num" ? |
Сообщ.
#7
,
|
|
|
Кстати такой вопрос.
Вы испытываете свой проект в режиме дебага или делаете автономный экзешник (релиз)? |
Сообщ.
#8
,
|
|
|
Он значительно больше - 1024 байта. Но будь он меньше, как бы это объясняло данную проблему? В массив кладутся байты, какая разница откуда они берутся?
|
Сообщ.
#9
,
|
|
|
Oleg2004 в режиме дебага
|
Сообщ.
#10
,
|
|
|
Цитата Columbo @ Он значительно больше - 1024 байта. Но будь он меньше, как бы это объясняло данную проблему? В массив кладутся байты, какая разница откуда они берутся? Если бы он был меньше, то в этом цикле for (size_t i=ICMP_HEADERSIZE, j=0; j<num; i++, j++) { IcmpSendPacket[i] = OutBuf[j]; } будет выход за границы массива. С любыми последствиями. |
Сообщ.
#11
,
|
|
|
Цитата Columbo @ в режиме дебага Сетевые приложения так не отлаживаются. Режим дебага зачастую - практически во всех средах разработки - достаточно трудно работает со стеком TCP/IP. Это вам не поиск в базе данных отлаживать. Потому я всегда требую от студентов делать релиз. Практика показала глючность режима дебага для сетевых приложений. |
Сообщ.
#12
,
|
|
|
ЫукпШ это понятно... но тогда бы выход за пределы был всегда и почти всегда приводил бы к краху программы с соответствующими сообщениями. А тут ошибку возвращает функция, ничего не рушится, а если не использовать компонент Edit, то вообще все ок...
Добавлено Oleg2004 Ваше замечание мне кажется наиболее точно объясняет такое поведение. Обязательно проверю это! |
Сообщ.
#13
,
|
|
|
Цитата Columbo @ ничего не рушится, а если не использовать компонент Edit, то вообще все ок... Во во... плавающий глюк вполне может быть именно в дебаге. |
Сообщ.
#14
,
|
|
|
Цитата Columbo @ ЫукпШ это понятно... но тогда бы выход за пределы был всегда и почти всегда приводил бы к краху программы с соответствующими сообщениями. Нет. Это как повезёт. Поведение приложения типа "что-то глючит" как раз хорошо подходит под гипотезу о выходе за пределы массива. |
Сообщ.
#15
,
|
|
|
Итак...
На всякий случай увеличил размер массива до 2 кб, а потом до 4 - программа стала просто зависать при отправке. Сделал релиз - вываливает ту же ошибку. Переписал exe-шники в одельную папку (до этого запускал просто из билдера): релиз, релиз с библиотеками, дебаг - все программы зависают на передаче. Раскоментировал закоментированное в следующем коде: AnsiString tICMP::Startup() { WSAStartup(0x0101, &wsaData); sockAddrHost.sin_family = AF_INET; sockAddrHost.sin_port = htons(0); sockAddrHost.sin_addr.s_addr = 0; if ((lpProtocolEntry = getprotobyname("icmp")) == NULL) { nProtocol = IPPROTO_ICMP; } else { nProtocol = lpProtocolEntry->p_proto; } if ((hSocket = socket(PF_INET, SOCK_RAW, nProtocol)) == INVALID_SOCKET) { return "Error.\r\nCould not create a RAW socket."; } /* int err = bind(hSocket, (sockaddr*)&sockAddrHost, sizeof(struct sockaddr_in)); if(err == SOCKET_ERROR) { closesocket(hSocket); return "Error in bind(): " + IntToStr(err); } const char a = 1; if (setsockopt(hSocket, SOL_SOCKET, SO_BROADCAST, &a, 1) == SOCKET_ERROR) { closesocket(hSocket); return "Error in setsockopt"; } */ return "OK"; } Ошибка перестала вываливаться программа стала передавать, ну и принимать естественно данные веденные с формы. Другая программа с похожими симптомами тоже перестала вываливать ошибку. Вот только меня терзают сомнения, что я уже это делал раньше. И почему биндинг сокета при использовании компонента Edit нужен, а без использования не нужен остается для меня загадкой. Какая разница откуда берутся данные? Причем тут броадкаст тоже не понятно, хотя я где то читал что для RAW сокетов эта опция нужна. В любом случае как говорится "будем посмотреть!" Завтра проверю на работе. |
Сообщ.
#16
,
|
|
|
Цитата Columbo @ Переписал exe-шники в одельную папку (до этого запускал просто из билдера): релиз, релиз с библиотеками, дебаг - все программы зависают на передаче. Стабильность ошибки позволяет надеяться на ее локализацию. Цитата Columbo @ Причем тут броадкаст тоже не понятно, хотя я где то читал что для RAW сокетов эта опция нужна. Нет. Эта опция совершенно не нужна. Зачем? |
Сообщ.
#17
,
|
|
|
Columbo, попробуй так:
... int err = bind(hSocket, (sockaddr*)&sockAddrHost, sizeof(sockAddrHost)); ... |
Сообщ.
#18
,
|
|
|
Нашел где то в кодах такую идею:
sendto(s, buf, sizeof(ICMP_HDR)+32, 0, (SOCKADDR *)&dest, sizeof(dest)); |
Сообщ.
#19
,
|
|
|
Цитата Columbo @ Вот метод класса: ну, господа туманные ежи.. Мы работаем с raw sockets. Это автоматически обозначает, что мы должны формировать заголовок ip, потом все остальное ipheader = (struct ip_header*)packet; icmp = (struct icmp_echo*)(packet+sizeof(struct ip_header)); ну и далее, ipheader->ver = 4; /*IPv4*/ ipheader->hl = 5; /* This is the smallest possible value, our IP header is only 20 bytes */ ipheader->tos = 0; ipheader->totl = sizeof(struct ip_header)+sizeof(struct icmp_echo); и понеслась по кочкам метла, в свою очередь, Цитата icmp->type = 8; /* icmp echo */ icmp->code = 0; /* only valid value for echo or echo reply */ icmp->identifier = 0x1337; icmp->sequence = ... ну и естественно, заполнить датой и посчитать чексумму, и будет полный порядок. Ро Сокет не знает в твоей ситуации, куда и что там нужно отправлять. Ты ему даешь охинею из байтов, от которой у винды несварение даты. Возьми нормальный базовый пример и исходя из него, строй приложение. Добавлено вот пример icmp под мелкософт если чо http://www.vijaymukhi.com/security/network/rawsockets.htm попробуй сначала собери консольную аппликацию под студией или своим древним как говно мамонта борландом, потом переходи к формам-кнопкам, иначе будешь неделю какать кирпичами и соберешь на форуме вокруг себя толпу телепатов (что уже сделано) |
Сообщ.
#20
,
|
|
|
nemez а я думал ip заголовок формируется автоматически... Ну если это не так, почему все же удается посылать и принимать пакеты, ну за исключением описаных мною ситуаций, когда функция возвращает ошибку?
Добавлено ЫукпШ, Oleg2004 не помогло.. На другом компе фокус с биндингом и броадкастом не удался.. еще хуже стало - просто зависает программа. |
Сообщ.
#21
,
|
|
|
Цитата Columbo @ ЫукпШ, Oleg2004 не помогло.. На другом компе фокус с биндингом и броадкастом не удался.. еще хуже стало - просто зависает программа. Где-то выход за границы массива или портится стек. Или вместе. Это может быть где угодно в программе, а проявиться именно в этом месте. Легче начать другой проект сначала и по-проще - какой-нибудь консольный вариант исключительно для отладки класса. И двигаться мелкими шажками. |
Сообщ.
#22
,
|
|
|
ЫукпШ Вот я убрал из прогаммы обновление Label->Caption, точнее даже не убрал а просто убрал пару строк оттуда и прекрасно обменивался пакетами без ошибок. И какова вероятность того что в консольном варианте, где нет ничего лишнего все будет работать? Я думаю 100%. Так куда двигаться в такой ситуации?
Попробую как рекомендует nemez сделать, только вот как можно на другой стороне принять мой пакет причем с анализом контрольной суммы и размер наверняка учитывается а айпи заголовке, если я его не формирую мне также не понятно... а он тем временем принимается без ошибок. |
Сообщ.
#23
,
|
|
|
Цитата Columbo @ nemez а я думал ip заголовок формируется автоматически... Так оно и есть, если не применяется опция IP_HDRINCL. А идеологически я согласен с ЫукпШ |
Сообщ.
#24
,
|
|
|
Oleg2004 я уже понял
|
Сообщ.
#25
,
|
|
|
nemez я не нашел где формируется заголовок айпи в коде по твоей ссылке..
main(int argc, char **argv) { d = WSAStartup (MAKEWORD(2,1),&ws); printf("WSAStartup Return Value=%d\n",d); s = WSASocket(AF_INET,SOCK_RAW, IPPROTO_ICMP ,NULL, 0,0); printf("Socket Return Value=%d\n",s); hp = gethostbyname(argv[1]); memcpy(&dest.sin_addr,hp->h_addr,hp->h_length); dest.sin_family = hp->h_addrtype; printf("hp=%x Ip Address=%s\n",hp,inet_ntoa(dest.sin_addr)); pIcmpHeader = (IcmpHeader *) malloc(sizeof(IcmpHeader)); pIcmpHeader->i_type = 8; pIcmpHeader->i_code = 0; pIcmpHeader->i_id = (USHORT)GetCurrentProcessId(); pIcmpHeader->i_cksum = 0; pIcmpHeader->i_seq = 326; memset(pIcmpHeader->data ,'A', 32); pIcmpHeader->timestamp = GetTickCount(); pIcmpHeader->i_cksum = checksum((USHORT *)pIcmpHeader,sizeof(IcmpHeader)); d = sendto(s,(char *)pIcmpHeader,sizeof(IcmpHeader),0,(struct sockaddr*)&dest,sizeof(dest)); printf("Sentto return value=%d\n",d); dummy = sizeof(dest); d = recvfrom(s ,databuf,1024,0,(struct sockaddr*)&dest,&dummy); printf("recvfrom return value=%d\n",d); pIpHeader = (struct IpHeader *)databuf; printf("len=%x TOS=%d Total length %d %d\n",pIpHeader->lenver,pIpHeader->tos,pIpHeader->totallen , htons(pIpHeader->totallen)); printf("ident=%d Frag=%d TTL=%d Protocol=%d\n",pIpHeader->ident, pIpHeader->fragandflags,pIpHeader->ttl,pIpHeader->proto); printf("CheckSum=%d %d\n",pIpHeader->checksum , checksum((USHORT *)databuf,20+32+12)); printf("Source IP=%s Dest Ip=%s\n",inet_ntoa(pIpHeader->sourceIP),inet_ntoa(pIpHeader->destIP)); printf("dest=%s\n",inet_ntoa(dest.sin_addr)); int size = pIpHeader->lenver & 0x0f; size = size * 4; size = size - 20; printf("Size of IP headers %d\n",size); if ( size > 0) { struct ipopt *pipopt; pipopt = (struct ipopt *)(databuf + 20); printf("code=%d len=%d ptr=%d\n",pipopt->code,pipopt->len,pipopt->ptr); int noofstr; noofstr = (pipopt->ptr/4) - 1; printf("No of addr's=%d\n",noofstr); for ( i = 0 ; i < noofstr ; i++) { struct in_addr a; a.S_un.S_addr = pipopt->addr[i]; printf("%s\n",inet_ntoa(a)); } } } структура заголовка заполняется уже после принятия пакета, это другая история, а перед отправкой - нет. |
Сообщ.
#26
,
|
|
|
Цитата Columbo @ ЫукпШ Вот я убрал из прогаммы обновление Label->Caption, точнее даже не убрал а просто убрал пару строк оттуда и прекрасно обменивался пакетами без ошибок. Размеры программы изменились, возможно изменилось расположение кодов относительно данных. По прежнему что-то портится, только в другом месте и в этой точке приложения не проявляется. |
Сообщ.
#27
,
|
|
|
Цитата Columbo @ nemez я не нашел где формируется заголовок айпи в коде по твоей ссылке.. ipopt.code = 7; ipopt.ptr = 4; ipopt.len = 39; setsockopt (s, IPPROTO_IP, IP_OPTIONS,(char *)&ipopt, sizeof(ipopt)); ..... вот тебе пдфочка http://www.beknowledge.com/wp-content/uplo...2010/09/892.pdf см. поиском функцию (<Ctrl-f>) void DecodeIPOptions(char *buf, int bytes) Через структуру (struct ipopt в том исходнике что ты смотрел) через setsockopt передаются параметры заголовка ip. зы. Собери консольный пинг с примера рабочий, это тебе облегчит задачу |
Сообщ.
#28
,
|
|
|
пошел собирать...
|
Сообщ.
#29
,
|
|
|
Предлагаю вместо
unsigned char d = StrToInt(EditDataOut->Text); unsigned int d = StrToInt(EditDataOut->Text); |
Сообщ.
#30
,
|
|
|
Цитата Columbo @ //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonClick(TObject *Sender) { tICMP ICMP1; unsigned char DataOut[512]; // unsigned char d = StrToInt(EditDataOut->Text); for (int i=0; i<100; i++) { DataOut[i] = 0x55; // DataOut[i] = d; } AnsiString Res = ICMP1.SendData("192.168.1.1", DataOut, 100); if (Res != "OK") { ShowMessage(Res); return; } } //----------------------------------------------------------------- Что за говнокод? Сплошной хардкодинг. Это неприемлемо в коммерческом коде, отсюда ошибки. |
Сообщ.
#31
,
Сообщение отклонено: Oleg2004 -
|
Сообщ.
#32
,
|
|
|
Это не дает ответа на мой вопрос
|
Сообщ.
#33
,
|
|
|
Думаю, что
(EditDataOut == NULL) |
Сообщ.
#34
,
|
|
|
Очень интересно)
|