Набросал прогу, которая должна отправлять TCP пакет, но sendto() возвращает ошибку 10022. TCP-checksum вроде считал как в RFC написано, IP-checksum ОС поидее должна сама высчитываться. Непонятно в чем проблема..
Компилирую на VC++ .NET
----send_tcp.c----
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32")
typedef struct ip_header {
unsigned char ip_verlen; // IP version & length
unsigned char ip_tos; // IP type of service
unsigned short ip_totallength; // Total length
unsigned short ip_id; // Unique identifier
unsigned short ip_offset; // Fragment offset field
unsigned char ip_ttl; // Time to live
unsigned char ip_protocol; // Protocol(TCP,UDP etc)
unsigned short ip_sum; // IP checksum
unsigned int ip_srcaddr; // Source address
unsigned int ip_destaddr; // Destination address
} IPHDR;
typedef struct tcp_header {
unsigned short int tcp_sport; //
unsigned short int tcp_dport; //
unsigned int tcp_seq; //
unsigned int tcp_ack;
unsigned char tcp_x2:4, th_off:4;
unsigned char tcp_flags;
unsigned short int tcp_win;
unsigned short int tcp_sum;
unsigned short int tcp_urp;
} TCPHDR;
#define FROM_IP "127.0.0.1"
#define TO_IP "127.0.0.1"
// подсчет чексуммы взял из статьи "Программирование raw сокетов под bsd", xaoc ezine #1
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum +=(UCHARbuffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
void main() {
WSADATA wd;
SOCKET s;
IN_ADDR addr;
int optret,ret;
BOOL bopt;
IPHDR iphdr;
TCPHDR tcphdr;
unsigned short tsz,tcpsum,chksum;
char buf[4096], *ptr;
struct sockaddr_in s_in;
if (WSAStartup(MAKEWORD(2,2),&wd))
printf("WSAStartup() failed\n");
addr.S_un.S_addr = inet_addr(FROM_IP);
s = socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
if (s == INVALID_SOCKET)
printf("socket() failed\n");
bopt = TRUE;
optret = setsockopt(s,IPPROTO_IP,IP_HDRINCL,(char *)&bopt,sizeof(bopt));
if (optret == SOCKET_ERROR)
printf("setsockopt() failed\n");
tsz = sizeof(IPHDR) + sizeof(TCPHDR);
iphdr.ip_verlen = (4 << 4) | (sizeof(iphdr) / sizeof(unsigned long));
iphdr.ip_tos = 0;
iphdr.ip_totallength = htons(tsz);
iphdr.ip_id = 0;
iphdr.ip_offset = 0;
iphdr.ip_ttl = 128;
iphdr.ip_protocol = 0x06;
iphdr.ip_sum = 0;
iphdr.ip_srcaddr = inet_addr(FROM_IP);
iphdr.ip_destaddr = inet_addr(TO_IP);
tcphdr.tcp_sport = htons(666);
tcphdr.tcp_dport = htons(999);
tcphdr.tcp_seq = 555;
tcphdr.tcp_ack = 777;
tcphdr.tcp_flags = 0x10; // ACK
tcphdr.tcp_win = htons(6666);
ptr = buf;
ZeroMemory(buf,sizeof(buf));
tcpsum = 0;
memcpy(ptr,&iphdr.ip_srcaddr,sizeof(iphdr.ip_srcaddr));
ptr += sizeof(iphdr.ip_srcaddr);
tcpsum += sizeof(iphdr.ip_srcaddr);
memcpy(ptr,&iphdr.ip_destaddr,sizeof(iphdr.ip_destaddr));
ptr += sizeof(iphdr.ip_destaddr);
tcpsum += sizeof(iphdr.ip_destaddr);
memcpy(ptr,&iphdr.ip_destaddr,sizeof(iphdr.ip_destaddr));
ptr += sizeof(iphdr.ip_destaddr);
tcpsum += sizeof(iphdr.ip_destaddr);
ptr++;
tcpsum++;
memcpy(ptr,&iphdr.ip_protocol,sizeof(iphdr.ip_protocol));
ptr += sizeof(iphdr.ip_protocol);
tcpsum += sizeof(iphdr.ip_protocol);
memcpy(ptr,&tcphdr,sizeof(tcphdr));
ptr += sizeof(tcphdr);
tcpsum += sizeof(tcphdr);
tcphdr.tcp_sum = checksum((USHORT *)&buf,tcpsum);
ZeroMemory(buf,4096);
ptr = buf;
memcpy(ptr,&iphdr,sizeof(iphdr));
ptr += sizeof(iphdr);
memcpy(ptr,&tcphdr,sizeof(tcphdr));
s_in.sin_family = AF_INET;
s_in.sin_port = htons(666);
s_in.sin_addr.s_addr = inet_addr(TO_IP);
ret = sendto(s,&buf,tsz,0,(struct sockaddr *)&s_in,sizeof(s_in));
if (ret == SOCKET_ERROR)
printf("sendto() failed: %d\n",WSAGetLastError());
}
------eof------- ---
|