准确地说,我想构建一个自定义TCP数据包,并手动设置syn / ack值。
代码:
/*
Raw TCP packets
Silver Moon (m00n.silv3r@gmail.com)
*/
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h> //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include <arpa/inet.h>
#include<errno.h> //For errno - the error number
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h> //Provides declarations for ip header
/*
96 bit (12 bytes) pseudo header needed for tcp header checksum calculation
*/
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t tcp_length;
};
/*
Generic checksum calculation function
*/
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);
}
int main (int argc, char *argv[])
{
if(argc < 6 || argc > 6){
printf("Usage: ./sendtcp [Source IP] [Source port] [Destination IP] [Destination Port] [Packet Data]\n");
return -1;
}
char sourceip [32];
char sourceports [10];
char destinationip [32];
char destinationports [10];
int sourceport = 2000;
int destinationport = 2000;
strcpy(sourceip, argv[1]);
strcpy(sourceports, argv[2]);
strcpy(destinationip, argv[3]);
strcpy(destinationports, argv[4]);
sscanf(sourceports, "%d", &sourceport);
sscanf(destinationports, "%d", &destinationport);
printf("[Sending] from %s:%d To: %s:%s\n", sourceip, sourceport, destinationip,destinationports);
//Create a raw socket
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
if(s == -1)
{
//socket creation failed, may be because of non-root privileges
perror("Failed to create socket");
exit(1);
}
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//TCP header
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in sin;
struct pseudo_header psh;
//Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
strcpy(data , argv[5]);
//some address resolution
strcpy(source_ip , sourceip);
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr (destinationip);
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
iph->id = htonl (54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_TCP;
iph->check = 0; //Set to 0 before calculating checksum
iph->saddr = inet_addr ( source_ip ); //Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//TCP Header
tcph->source = htons (sourceport);
tcph->dest = htons (destinationport);
tcph->seq = 1;
tcph->ack_seq = 6;
tcph->doff = 5; //tcp header size
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 1;
tcph->urg = 0;
tcph->window = htons (5840); /* maximum allowed window size */
tcph->check = 0; //leave checksum 0 now, filled later by pseudo header
tcph->urg_ptr = 0;
//Now the TCP checksum
psh.source_address = inet_addr( source_ip );
psh.dest_address = sin.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct tcphdr) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));
tcph->check = csum( (unsigned short*) pseudogram , psize);
//IP_HDRINCL to tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
{
perror("Error setting IP_HDRINCL");
exit(0);
}
//loop if you want to flood :)
while (1)
{
//Send the packet
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
//Data send successfully
else
{
printf ("Packet Send. Length : %d \n" , iph->tot_len);
}
sleep(2);
}
return 0;
}
仅供参考: tcph->seq = 1; tcph->ack_seq = 6;
是您设置syn / ack值的地方。
问题在于,即使我已将Syn=1
和Ack=6
设置为wireshark,它似乎也是seq=4227858432 Ack=100663297
。
如果您能告诉我这些数字是如何存储的,以及如何将自己的自定义值设置为syn/ack
值,我将非常感谢。
答案 0 :(得分:0)
好的问题是,当我将syn的值设置为tcph->seq = 1;
时,它实际上将值设置为位。
因此,为了让我设置不同的值,应该使用网络语言完成,您可以使用htons() or htonl()
完成它。
如此恰当的方式就像:tcph->seq = htonl(20); tcph->ack_seq = htonl(num);
这就是我想要做的事情:)