Linux - RAW 套接字 - 数据包有错误的 tcp 和 ip 校验和
Linux - RAW socket - packet has bad tcp and ip checksum
原始套接字数据包有问题。
基于 Vivek Ramachandran 和 Sukumar Nandi 的 想法(https://www.researchgate.net/publication/221160823_Detecting_ARP_Spoofing_An_Active_Technique)我正在尝试创建一个 TCP SYN 数据包来检查发送 ARP 响应的主机是否是真实的并且 ARP 没有被欺骗。
我在 C 中编写了这段代码,以便在收到 ARP 回复时发送 TCP SYN 数据包,但不幸的是,在 wireshark 上,TCP 和 IP 校验和无效。
我试图弄清楚为什么校验和无效但没有成功,这是代码(请不要评判我......这是我的第一个程序):
#include <stdio.h>
#include <errno.h>
#include <pcap.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <linux/if_packet.h>
#define ARP_REPLY 2
struct pseudoPack {
uint32_t srcAddr;
uint32_t dstAddr;
uint8_t zero;
uint8_t protocol;
uint16_t TCP_len;
};
struct arp_header {
u_int16_t htype; /* Hardware Type */
u_int16_t ptype; /* Protocol Type */
u_char hlen; /* Hardware Address Length */
u_char plen; /* Protocol Address Length */
u_int16_t oper; /* Operation Code */
u_char sha[6]; /* Sender hardware address */
u_char spa[4]; /* Sender IP address */
u_char tha[6]; /* Target hardware address */
u_char tpa[4]; /* Target IP address */
};
struct ether_header *eth_h;
struct arp_header *arp_h;
struct sockaddr_in sa;
unsigned short arp_checksum(unsigned short *ptr,int nbytes) {
long sum;
unsigned short oddbyte;
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);
}
void packet_analyzer(u_char *args , const struct pcap_pkthdr *header, const u_char *packet){
char *dev = (char *)args;
struct ifreq ifreq_i;
struct ifreq ifreq_c;
struct ifreq ifreq_ip;
struct sockaddr_ll sadr_ll;
struct pseudoPack PP;
char *pseudo_packet;
char sendbuff[1024];
uint32_t SeqNum = 1138083240; //!TO CHANGE TO RANDOM!
char *data;
int raw_sock, i, total_len = 0, sPort = 8080, dPort = 8081; //!TO CHANGE TO RANDOM!
eth_h = (struct ethernet_header *) packet;
arp_h = (struct arp_header *)(packet+14);
printf("\nPakcet recived");
if(ntohs(eth_h->ether_type) == ETHERTYPE_ARP && ntohs(arp_h->oper) == ARP_REPLY && ntohs(arp_h->ptype) == 0x0800){
printf("\n\nARP RECIVED!");
if((raw_sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_TCP)) == -1) {
perror("\nERROR CREATING SOCKET FOR ARP CHECK");
return;
}
memset(&ifreq_i,0,sizeof(ifreq_i));
strncpy(ifreq_i.ifr_name,dev,IFNAMSIZ-1);
if((ioctl(raw_sock,SIOCGIFINDEX,&ifreq_i))<0){
perror("ERROR READING INDEX OF DEVICE: ");
return;
}
memset(&ifreq_c,0,sizeof(ifreq_c));
strncpy(ifreq_c.ifr_name,dev,IFNAMSIZ-1);
if((ioctl(raw_sock,SIOCGIFHWADDR,&ifreq_c))<0){
perror("ERROR GETTING MAC OF DEVICE");
return;
}
memset(&ifreq_ip,0,sizeof(ifreq_ip));
strncpy(ifreq_ip.ifr_name,dev,IFNAMSIZ-1);
if(ioctl(raw_sock,SIOCGIFADDR,&ifreq_ip)<0){
perror("ERROR GETTING IP OF DEVICE");
return;
}
memset(sendbuff,0,sizeof(sendbuff));
sa.sin_family = AF_INET;
sa.sin_port = htons(dPort);
sa.sin_addr.s_addr = inet_addr("192.168.1.67");
struct ethhdr *eth = (struct ethhdr *)(sendbuff);
struct iphdr *iph = (struct iphdr*)(sendbuff + sizeof(struct ethhdr));
struct tcphdr *tcph = (struct tcph *)(sendbuff + sizeof(struct iphdr) + sizeof(struct ethhdr));
data = (char *) (sendbuff + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr));
eth->h_source[0] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]);
eth->h_source[1] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]);
eth->h_source[2] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]);
eth->h_source[3] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]);
eth->h_source[4] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]);
eth->h_source[5] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]);
for(i=0;i<5;i++){
eth->h_dest[i] = eth_h->ether_shost[i];
}
eth->h_proto = htons(ETH_P_IP);
total_len =+ sizeof(struct ethhdr);
iph->ihl = 5;
iph->version = 4;
iph->tos = 16;
//iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)) /**+ strlen(data)**/;
iph->id = htons(10201);
iph->ttl = 64;
iph->protocol = 6;
iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
iph->daddr = inet_addr("192.168.1.254");
total_len =+ sizeof(struct iphdr);
tcph->source = htons(sPort);
tcph->dest = htons(dPort);
tcph->seq = htonl(SeqNum++);
tcph->ack_seq = 0x0;
tcph->doff = 5;
tcph->res1 = 0;
tcph->urg = 0;
tcph->ack = 0;
tcph->psh = 0;
tcph->rst = 0;
tcph->syn = 1;
tcph->fin = 0;
tcph->window = htons(155);
tcph->check = 0;
tcph->urg_ptr = 0;
//iph->tot_len = htons(total_len - sizeof(struct ethhdr));
PP.srcAddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
PP.dstAddr = inet_addr("192.168.1.254");
PP.zero = 0;
PP.protocol = 6;
PP.TCP_len = sizeof(struct tcphdr);//htons(sizeof(struct tcphdr) + strlen(data));
pseudo_packet = (char *) malloc((int) (sizeof(struct pseudoPack) + sizeof(struct tcphdr) + strlen(data)));
memset(pseudo_packet, 0, sizeof(struct pseudoPack) + sizeof(struct tcphdr) + strlen(data));
memcpy(pseudo_packet, (char *) &PP, sizeof(struct pseudoPack));
memcpy(pseudo_packet + sizeof(struct pseudoPack), tcph, sizeof(struct tcphdr) + strlen(data));
tcph->check = arp_checksum((unsigned short *) sendbuff,sizeof(struct tcphdr));
iph->check = arp_checksum((unsigned short *) sendbuff, sizeof(struct iphdr) + sizeof(struct tcphdr))/**iph->tot_len**/;
sadr_ll.sll_ifindex = ifreq_i.ifr_ifindex;
sadr_ll.sll_halen = ETH_ALEN;
for(i=0;i<5;i++){
sadr_ll.sll_addr[i] = eth_h->ether_shost[i];
}
int arp_sendpack = sendto(raw_sock,sendbuff,1024,0,(const struct sockaddr*)&sadr_ll,sizeof(struct sockaddr_ll));
if(arp_sendpack>0){
printf("\nSended...");
return;
}
else{
perror("\nError sending packet: ");
return;
}
close(raw_sock);
}
}
int main(int argc,char* argv[]){
int sock, i = 0;
char *dev, errbuf[PCAP_ERRBUF_SIZE], filter_exp[24] = "dst host ";
pcap_t *handle;
struct ifreq ifr;
struct pcap_pkthdr header;
struct bpf_program fp;
bpf_u_int32 mask;
bpf_u_int32 net;
const u_char *packet;
if(argc>2){
printf("\nToo many arguments.\nUSAGE: ViEmme [interface]\n");
return(1);
}
else if(argc==2){
dev = argv[1];
printf("\nStarting with device %s\n", dev);
}
else{
dev = pcap_lookupdev(errbuf);
if(dev==NULL){
perror("\nCouldn't find default device: \n");
return(1);
}
printf("\nDefault device %s selected...\n", dev);
}
sock = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
ioctl(sock, SIOCGIFADDR, &ifr);
close(sock);
strcat(filter_exp, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Can't get netmask for device %s\n", dev);
net = 0;
mask = 0;
}
handle = pcap_open_live(dev, BUFSIZ, 0, 1000, errbuf);
if(handle==NULL){
perror("\nCouldn't open selected device: \n");
return(1);
}
if(pcap_compile(handle, &fp, filter_exp, 0, net) == -1){
perror("\nCouldn't parse filter: \n");
return(1);
}
if(pcap_setfilter(handle, &fp) == -1){
perror("\nCouldn't set filters: \n");
return(1);
}
printf("\nStart sniffing...\n");
pcap_loop(handle, 0, packet_analyzer, (u_char *)dev);
printf("\n\nStopping\n\n");
pcap_close(handle);
return(0);
}
这里是校验和错误的截图:
screenshot
您正在将整个 frame/packet 传递给 arp_checksum
函数。看你调用arp_checksum
的那两行。第一个参数不应是 send buffer
,而是发送缓冲区中相关 header 的偏移量,否则您将在计算中包括以太网 header。您可能应该在那里使用 iph
和 tcph
(分别)。
原始套接字数据包有问题。
基于 Vivek Ramachandran 和 Sukumar Nandi 的 想法(https://www.researchgate.net/publication/221160823_Detecting_ARP_Spoofing_An_Active_Technique)我正在尝试创建一个 TCP SYN 数据包来检查发送 ARP 响应的主机是否是真实的并且 ARP 没有被欺骗。
我在 C 中编写了这段代码,以便在收到 ARP 回复时发送 TCP SYN 数据包,但不幸的是,在 wireshark 上,TCP 和 IP 校验和无效。
我试图弄清楚为什么校验和无效但没有成功,这是代码(请不要评判我......这是我的第一个程序):
#include <stdio.h>
#include <errno.h>
#include <pcap.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <linux/if_packet.h>
#define ARP_REPLY 2
struct pseudoPack {
uint32_t srcAddr;
uint32_t dstAddr;
uint8_t zero;
uint8_t protocol;
uint16_t TCP_len;
};
struct arp_header {
u_int16_t htype; /* Hardware Type */
u_int16_t ptype; /* Protocol Type */
u_char hlen; /* Hardware Address Length */
u_char plen; /* Protocol Address Length */
u_int16_t oper; /* Operation Code */
u_char sha[6]; /* Sender hardware address */
u_char spa[4]; /* Sender IP address */
u_char tha[6]; /* Target hardware address */
u_char tpa[4]; /* Target IP address */
};
struct ether_header *eth_h;
struct arp_header *arp_h;
struct sockaddr_in sa;
unsigned short arp_checksum(unsigned short *ptr,int nbytes) {
long sum;
unsigned short oddbyte;
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);
}
void packet_analyzer(u_char *args , const struct pcap_pkthdr *header, const u_char *packet){
char *dev = (char *)args;
struct ifreq ifreq_i;
struct ifreq ifreq_c;
struct ifreq ifreq_ip;
struct sockaddr_ll sadr_ll;
struct pseudoPack PP;
char *pseudo_packet;
char sendbuff[1024];
uint32_t SeqNum = 1138083240; //!TO CHANGE TO RANDOM!
char *data;
int raw_sock, i, total_len = 0, sPort = 8080, dPort = 8081; //!TO CHANGE TO RANDOM!
eth_h = (struct ethernet_header *) packet;
arp_h = (struct arp_header *)(packet+14);
printf("\nPakcet recived");
if(ntohs(eth_h->ether_type) == ETHERTYPE_ARP && ntohs(arp_h->oper) == ARP_REPLY && ntohs(arp_h->ptype) == 0x0800){
printf("\n\nARP RECIVED!");
if((raw_sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_TCP)) == -1) {
perror("\nERROR CREATING SOCKET FOR ARP CHECK");
return;
}
memset(&ifreq_i,0,sizeof(ifreq_i));
strncpy(ifreq_i.ifr_name,dev,IFNAMSIZ-1);
if((ioctl(raw_sock,SIOCGIFINDEX,&ifreq_i))<0){
perror("ERROR READING INDEX OF DEVICE: ");
return;
}
memset(&ifreq_c,0,sizeof(ifreq_c));
strncpy(ifreq_c.ifr_name,dev,IFNAMSIZ-1);
if((ioctl(raw_sock,SIOCGIFHWADDR,&ifreq_c))<0){
perror("ERROR GETTING MAC OF DEVICE");
return;
}
memset(&ifreq_ip,0,sizeof(ifreq_ip));
strncpy(ifreq_ip.ifr_name,dev,IFNAMSIZ-1);
if(ioctl(raw_sock,SIOCGIFADDR,&ifreq_ip)<0){
perror("ERROR GETTING IP OF DEVICE");
return;
}
memset(sendbuff,0,sizeof(sendbuff));
sa.sin_family = AF_INET;
sa.sin_port = htons(dPort);
sa.sin_addr.s_addr = inet_addr("192.168.1.67");
struct ethhdr *eth = (struct ethhdr *)(sendbuff);
struct iphdr *iph = (struct iphdr*)(sendbuff + sizeof(struct ethhdr));
struct tcphdr *tcph = (struct tcph *)(sendbuff + sizeof(struct iphdr) + sizeof(struct ethhdr));
data = (char *) (sendbuff + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr));
eth->h_source[0] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]);
eth->h_source[1] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]);
eth->h_source[2] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]);
eth->h_source[3] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]);
eth->h_source[4] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]);
eth->h_source[5] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]);
for(i=0;i<5;i++){
eth->h_dest[i] = eth_h->ether_shost[i];
}
eth->h_proto = htons(ETH_P_IP);
total_len =+ sizeof(struct ethhdr);
iph->ihl = 5;
iph->version = 4;
iph->tos = 16;
//iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)) /**+ strlen(data)**/;
iph->id = htons(10201);
iph->ttl = 64;
iph->protocol = 6;
iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
iph->daddr = inet_addr("192.168.1.254");
total_len =+ sizeof(struct iphdr);
tcph->source = htons(sPort);
tcph->dest = htons(dPort);
tcph->seq = htonl(SeqNum++);
tcph->ack_seq = 0x0;
tcph->doff = 5;
tcph->res1 = 0;
tcph->urg = 0;
tcph->ack = 0;
tcph->psh = 0;
tcph->rst = 0;
tcph->syn = 1;
tcph->fin = 0;
tcph->window = htons(155);
tcph->check = 0;
tcph->urg_ptr = 0;
//iph->tot_len = htons(total_len - sizeof(struct ethhdr));
PP.srcAddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
PP.dstAddr = inet_addr("192.168.1.254");
PP.zero = 0;
PP.protocol = 6;
PP.TCP_len = sizeof(struct tcphdr);//htons(sizeof(struct tcphdr) + strlen(data));
pseudo_packet = (char *) malloc((int) (sizeof(struct pseudoPack) + sizeof(struct tcphdr) + strlen(data)));
memset(pseudo_packet, 0, sizeof(struct pseudoPack) + sizeof(struct tcphdr) + strlen(data));
memcpy(pseudo_packet, (char *) &PP, sizeof(struct pseudoPack));
memcpy(pseudo_packet + sizeof(struct pseudoPack), tcph, sizeof(struct tcphdr) + strlen(data));
tcph->check = arp_checksum((unsigned short *) sendbuff,sizeof(struct tcphdr));
iph->check = arp_checksum((unsigned short *) sendbuff, sizeof(struct iphdr) + sizeof(struct tcphdr))/**iph->tot_len**/;
sadr_ll.sll_ifindex = ifreq_i.ifr_ifindex;
sadr_ll.sll_halen = ETH_ALEN;
for(i=0;i<5;i++){
sadr_ll.sll_addr[i] = eth_h->ether_shost[i];
}
int arp_sendpack = sendto(raw_sock,sendbuff,1024,0,(const struct sockaddr*)&sadr_ll,sizeof(struct sockaddr_ll));
if(arp_sendpack>0){
printf("\nSended...");
return;
}
else{
perror("\nError sending packet: ");
return;
}
close(raw_sock);
}
}
int main(int argc,char* argv[]){
int sock, i = 0;
char *dev, errbuf[PCAP_ERRBUF_SIZE], filter_exp[24] = "dst host ";
pcap_t *handle;
struct ifreq ifr;
struct pcap_pkthdr header;
struct bpf_program fp;
bpf_u_int32 mask;
bpf_u_int32 net;
const u_char *packet;
if(argc>2){
printf("\nToo many arguments.\nUSAGE: ViEmme [interface]\n");
return(1);
}
else if(argc==2){
dev = argv[1];
printf("\nStarting with device %s\n", dev);
}
else{
dev = pcap_lookupdev(errbuf);
if(dev==NULL){
perror("\nCouldn't find default device: \n");
return(1);
}
printf("\nDefault device %s selected...\n", dev);
}
sock = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
ioctl(sock, SIOCGIFADDR, &ifr);
close(sock);
strcat(filter_exp, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Can't get netmask for device %s\n", dev);
net = 0;
mask = 0;
}
handle = pcap_open_live(dev, BUFSIZ, 0, 1000, errbuf);
if(handle==NULL){
perror("\nCouldn't open selected device: \n");
return(1);
}
if(pcap_compile(handle, &fp, filter_exp, 0, net) == -1){
perror("\nCouldn't parse filter: \n");
return(1);
}
if(pcap_setfilter(handle, &fp) == -1){
perror("\nCouldn't set filters: \n");
return(1);
}
printf("\nStart sniffing...\n");
pcap_loop(handle, 0, packet_analyzer, (u_char *)dev);
printf("\n\nStopping\n\n");
pcap_close(handle);
return(0);
}
这里是校验和错误的截图:
screenshot
您正在将整个 frame/packet 传递给 arp_checksum
函数。看你调用arp_checksum
的那两行。第一个参数不应是 send buffer
,而是发送缓冲区中相关 header 的偏移量,否则您将在计算中包括以太网 header。您可能应该在那里使用 iph
和 tcph
(分别)。