我正在编程软件,可以将tcp数据包发送到主机。
我能够创建一个包含IP头,TCP标头和数据的数据包,但我无法管理如何添加MSS,NOP,STACK,窗口缩放或时间戳等TCP选项。
我的意思是我无法向TCP标头添加选项,计算正确的校验和以向主机发送一个好的TCP数据包。
我可以在没有TCP选项的情况下发送正确的TCP数据包。
你认为我正在使用正确的补丁吗?有人可以帮帮我吗?
/* TCP Header structure */
struct tcphdr
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t th_ack; /* acknowledgement number */
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t th_x2:4; /* (unused) */
u_int8_t th_off:4; /* data offset */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
u_int8_t th_off:4; /* data offset */
u_int8_t th_x2:4; /* (unused) */
#endif
u_int8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
# define TH_ECE 0x40
# define TH_CWR 0x80
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
struct tcp_option_mss
{
uint8_t kind; /* 2 */
uint8_t len; /* 4 */
uint16_t mss;
} __attribute__((packed));
struct tcphdr_mss
{
struct tcphdr tcphdr;
struct tcp_option_mss mss;
};
/* IP Header structure */
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
# define IP_RF 0x8000 /* reserved fragment flag */
# define IP_DF 0x4000 /* dont fragment flag */
# define IP_MF 0x2000 /* more fragments flag */
# define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
int send_packet(int sock, long dest_ip , long source_ip, long port, u_int8_t th_flags, unsigned long seq, unsigned long ack, unsigned long port1, unsigned char * data, unsigned long data_i)
{
char * packet;
struct ip * pkt_ip;
struct tcphdr * pkt_tcp;
struct tcphdr_mss * tcp_header;
struct sockaddr_in sin;
packet = malloc(sizeof(struct ip) + sizeof(struct tcphdr_mss) + data_i);
if (packet == NULL)
{
if (ECHO)
fprintf(stderr, "Error in allocating memory\n");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(struct ip) + sizeof(struct tcphdr_mss));
pkt_ip = (struct ip *) packet;
pkt_tcp = (struct tcphdr *) (packet + sizeof(struct ip));
pkt_tcp->th_sport = htons(port1);
pkt_tcp->th_dport = htons(port);
pkt_tcp->th_seq = htonl(seq);
pkt_tcp->th_ack = htonl(ack);
pkt_tcp->th_off = sizeof(struct tcphdr) / 4 + 1;
pkt_tcp->th_flags = th_flags;
pkt_tcp->th_win = htons(32768);
pkt_tcp->th_sum = 0;
tcp_header = malloc(sizeof(struct tcphdr));
tcp_header->tcphdr = *pkt_tcp;
tcp_header->mss.kind = 2;
tcp_header->mss.len = 4;
tcp_header->mss.mss = htons(32000);
pkt_ip->ip_v = 4;
pkt_ip->ip_hl = sizeof(struct ip) >> 2;
pkt_ip->ip_tos = 0;
pkt_ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + data_i);
if (ipid > 65000)
ipid = 0;
ipid++;
pkt_ip->ip_id = ipid;
pkt_ip->ip_off = 0;
pkt_ip->ip_ttl = 64;
pkt_ip->ip_p = IPPROTO_TCP ;
pkt_ip->ip_sum = 0;
pkt_ip->ip_src.s_addr = source_ip;
pkt_ip->ip_dst.s_addr = dest_ip;
pkt_ip->ip_sum = checksum((unsigned short*)pkt_ip, sizeof( struct ip) );
pkt_tcp->th_sum = in_cksum_tcp(pkt_ip->ip_src.s_addr, pkt_ip->ip_dst.s_addr, (unsigned short *) pkt_tcp, sizeof(struct tcphdr_mss), data, data_i);
memcpy(((char *)pkt_tcp + sizeof(struct tcphdr_mss)), data, data_i);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = pkt_ip->ip_dst.s_addr;
if (sendto(sock, packet, sizeof(struct ip) + sizeof(struct tcphdr_mss) + data_i, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0)
{
perror("sendto");
free(packet);
return -1;
}
free(packet);
return 0;
}
答案 0 :(得分:1)
在行中:
pkt_tcp->th_sum = in_cksum_tcp(pkt_ip->ip_src.s_addr, pkt_ip->ip_dst.s_addr, (unsigned short *) pkt_tcp, sizeof(struct tcphdr_mss), data, data_i);
根据我在野外看到的in_cksum_tcp函数:
unsigned short in_cksum_tcp(int src, int dst, unsigned short *addr, int len, unsigned char * data, int data_i)
您传递的是选项标头的大小(sizeof(struct tcphdr_mss)),而不是整个TCP标头的大小(sizeof(tcphdr)+ sizeof(tcphdr_mss))。我认为这可能是问题(你没有正确计算TCP校验和)。
检查wich的一个好方法是创建原始数据包的问题是使用libpcap将数据包保存到pcap文件并使用wireshark打开。您可以轻松检查数据包的完整性。
答案 1 :(得分:1)
下面是一个计算数据包正确校验和的函数
unsigned short csum(unsigned short * ptr, int nbytes) {
register long sum;
unsigned short oddbyte;
register short answer;
sum = 0;
while (nbytes > 1) {
sum += * ptr++;
nbytes -= 2;
}
if (nbytes == 1) {
oddbyte = 0; * ((u_char * ) & oddbyte) = * (u_char * ) ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum = sum + (sum >> 16);
answer = (short)~sum;
return (answer);
}
调用该函数获取ip和tcp的校验和。 除此之外,为了使用像MSS,NOP,STACK这样的选项,您需要在TCP标头中声明所有这些。当你在程序中使用所有这些时,你必须相应地设置th_off的值