c - Socket:sendto函数根据ip头长度值改变发送的数据
问题描述
我正在研究数据包伪造并使用原始套接字发送它
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
我有几个问题。我伪造的数据包(以及我在网上找到的每个指南)都是从 iphdr 开始的。sendto 函数会自动将 ethhdr 添加到其中。由于我没有添加它,我无法更改它。
第一个问题是,有什么办法可以操纵 ethhdr.
其次,在 iphdr 中,我的 sendto 根据 iph->ihl 的值执行不同的操作。如果我将它设置为 5(通常是),它会改变
- 我的校验和值
- iph->tot_len 到大端
- 如果设置为 0.0.0.0,则 iphdr 中的源地址值到我的计算机 ip
但是,对于任何其他值,它都可以让数据包顺利通过而无需任何更改。
这是 iph->ihl 设置为 3(不是 5)的屏幕截图[完全相同]
这是 iph->ihl 设置为 5 的屏幕截图 [已更改]
以下是脚本:
接收文件
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/ioctl.h>
#include<net/if.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/if_ether.h>
#include<netinet/udp.h>
#include<linux/if_packet.h>
#include<arpa/inet.h>
#define min(x,y) (x<y)?x:y
void pkt_hex_dump(uint8_t *data, size_t len)
{
int rowsize = 16;
int i, l, linelen, remaining;
int li = 0;
uint8_t ch;
printf("\nPacket hex dump:\n");
printf("Packet Size = %ld\n", len);
remaining = len;
for (i = 0; i < len; i += rowsize) {
printf("%06d\t", li);
linelen = min(remaining, rowsize);
remaining -= rowsize;
for (l = 0; l < linelen; l++) {
ch = data[l];
printf("%02X ", (uint32_t) ch);
}
data += linelen;
li += 10;
printf("\n");
}
}
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 sock_r = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if (sock_r == -1) {
printf("error in socket");
return -1;
}
unsigned char* buffer = (unsigned char *)malloc(65536);
memset(buffer,0,65536);
while(1)
{
int saddr_len, buflen;
struct sockaddr saddr;
saddr_len = sizeof saddr;
buflen = recvfrom(sock_r, buffer, 65536, 0, &saddr, (socklen_t *)&saddr_len);
printf("\n[NEW PACKET]\n");
unsigned char* data = buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
if(buflen<0)
{
printf("error in reading recvfrom function\n");
return -1;
}
union ipv4
{
__be32 src;
uint8_t ip[4];
};
struct iphdr *iph = (struct iphdr *)(buffer + sizeof(struct ethhdr));
union ipv4 src_ip;
src_ip.src = iph->saddr;
struct udphdr *udph = (struct udphdr *)(buffer + sizeof(struct ethhdr) + sizeof(struct iphdr));
printf("Source = %d.%d.%d.%d\n",(int)src_ip.ip[0],(int)src_ip.ip[1],(int)src_ip.ip[2],(int)src_ip.ip[3]);
printf("Checksum Value : %d\n",(int)iph->check);
printf("Checksum UDP : %d\n",(int)udph->check);
printf("Data Received:\n%s\n",data);
pkt_hex_dump((uint8_t *)iph,buflen - sizeof(struct ethhdr));
//recheck csum values
iph->check = 0;
udph->source = 0;
udph->dest = 0;
udph->len = 0;
udph->check = 0;
printf("\nRechecking Checksum:%4X\n\n",csum((unsigned short *)iph,iph->tot_len));
}
close(sock_r);
}
发送.c
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h> //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/ip.h> //Provides declarations for ip header
#define min(x,y) (x<y)?x:y
void pkt_hex_dump(uint8_t *data, size_t len)
{
int rowsize = 16;
int i, l, linelen, remaining;
int li = 0;
uint8_t ch;
printf("\nPacket hex dump:\n");
printf("Packet Size = %ld\n", len);
remaining = len;
for (i = 0; i < len; i += rowsize) {
printf("%06d\t", li);
linelen = min(remaining, rowsize);
remaining -= rowsize;
for (l = 0; l < linelen; l++) {
ch = data[l];
printf("%02X ", (uint32_t) ch);
}
data += linelen;
li += 10;
printf("\n");
}
}
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
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 (void)
{
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
if(s == -1)
{
perror("Failed to create raw socket");
exit(1);
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr ("10.0.2.15");
char *datagram = (char*)malloc(4096);
memset (datagram, 0, 4096);
struct iphdr *iph = (struct iphdr *)datagram;
char* data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
strcpy(data,"Hello I am here.\n");
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
iph->id = htonl (85492);
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
iph->check = 0; //Set to 0 before calculating checksum
//iph->saddr = inet_addr ( "1.2.3.4" ); //Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct iphdr));
udph->source = htons (6666);
udph->dest = htons (8622);
udph->len = htons(8 + strlen(data));
udph->check = 0; //leave checksum 0 now, filled later by pseudo header
struct pseudo_header psh;
psh.source_address = inet_addr( "1.2.3.4" );
psh.dest_address = sin.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
unsigned char *pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + strlen(data));
udph->check = csum( (unsigned short*) pseudogram , psize);
//while (1)
{
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
else
{
printf ("Packet Send. Length : %d \n" , iph->tot_len);
printf("Checksum Value : %d\n",(int)iph->check);
printf("Checksum UDP : %d\n",(int)udph->check);
pkt_hex_dump(datagram,iph->tot_len);
}
}
close(s);
return 0;
}
PS任何人都可以指出为什么数据包被发送两次,因为我在脚本中只有一次sendto函数。
解决方案
推荐阅读
- networking - omnet 可以比 express 模式运行得更快吗?
- python - 如何计算列表中子列表的出现次数并将其显示为 dict
- c - 将节点添加到列表的问题
- flutter - Flutter Webview - 键盘不会自动关闭
- apache-kafka - 覆盖 KStreams 默认序列化器 (ByteArraySerializer)
- php - 我无法在其创建过程中自动添加用户 ID - Symfony 5
- spring-batch - Spring Batch:这有模式吗?
- javascript - AJAX PHP 调用请求无响应
- python - 根据字符串生成数字
- unit-testing - 允许 jest 模拟从测试文件外部调用的函数的幕后发生了什么?