raw socket编程。

运行第一段代码,发送ip数据报,第二段代码接收ip数据报。需要运行第二段代码,否则将无法接收数据报。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
 
struct iphead{   
    unsigned char ip_hl:4, ip_version:4;  //ip_hl,ip_version各占四个bit位。
    unsigned char ip_tos;
    unsigned short int ip_len;   
    unsigned short int ip_id;
    unsigned short int ip_off;  
    unsigned char ip_ttl;
    unsigned char ip_pro;
    unsigned short int ip_sum;
    unsigned int ip_src;
    unsigned int ip_dst;
};
 
struct icmphead{  //该结构体模拟ICMP报文首部
    unsigned char icmp_type;
    unsigned char icmp_code;
    unsigned short int icmp_sum;
    unsigned short int icmp_id;
    unsigned short int icmp_seq;
};
 
unsigned short int cksum(char buffer[], int size){   //计算校验和,具体的算法可自行百度,或查阅资料
    unsigned long sum = 0;
    unsigned short int answer;
    unsigned short int *temp;
    temp = (short int *)buffer;
    for( ; temp<buffer+size; temp+=1){
        sum += *temp;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return answer;
}
 
int main(){
   
    int sockfd;
    struct sockaddr_in conn;
    struct iphead *ip;
    struct icmphead *icmp;
    unsigned char package[sizeof(struct iphead) + sizeof(struct icmphead)];  //package存储IP数据报的首部和数据
    memset(package, 0, sizeof(package));
 
    ip = (struct iphead*)package;
    icmp = (struct icmphead*)(package+sizeof(struct iphead)); //IP数据报数据字段仅仅包含一个ICMP首部
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); //创建套接字
    if(sockfd < 0){
        printf("Create socket failed\n");
        return -1;
    }
    conn.sin_family = AF_INET;
    conn.sin_addr.s_addr = inet_addr("192.168.230.135");
    int one = 1;
    if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0){  //设置套接字行为,此处设置套接字不添加IP首部
        printf("setsockopt failed!\n");
        return -1;
    }
    /*设置IP首部各个字段的值*/  
    ip->ip_version = 4; 
    ip->ip_hl = 5;
    ip->ip_tos = 0;
    ip->ip_len = htons(sizeof(struct iphead) + sizeof(struct icmphead)); //关于htons()、htonl()的作用,可自行百度    
    ip->ip_id = htons(1);
    ip->ip_off = htons(0x4000);
    ip->ip_ttl = 10;
    ip->ip_pro = IPPROTO_ICMP;
    ip->ip_src = htonl(inet_addr("192.168.230.135"));
    ip->ip_dst = htonl(inet_addr("192.168.230.135"));
    printf("ipcksum : %d\n", cksum(package, 20)); 
    ip->ip_sum = cksum(package, 20);  // 计算校验和,应当在其他字段之后设置(实验中发现检验和会被自动添加上)
    
    /*设置ICMP首部各字段值*/
    icmp->icmp_type = 8;
    icmp->icmp_code = 0;
    icmp->icmp_id = 1;
    icmp->icmp_seq = 0;
    icmp->icmp_sum = (cksum(package+20, 8));
    /*接下来发送IP数据报即可*/
    if(sendto(sockfd, package, htons(ip->ip_len), 0,(struct sockaddr *)&conn, sizeof(struct sockaddr)) < 0){
    printf("send failed\n"); 
    return -1;
    }
    printf("send successful\n");    
    return 0;
}

第二段程序

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <linux/if_ether.h>

unsigned short int cksum(char buffer[], int size){  //校验函数
    unsigned long sum = 0;
    unsigned short int answer;
    unsigned short int *temp;
    temp = (short int *)buffer;
    for( ; temp<buffer+size; temp+=1)
        sum += *temp;
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return answer;
}

int main(){
    unsigned char buffer[1024];
    
  //  int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);//不知为啥,无法设置原始套接字在网络层抓IP数据报
    int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); //此处,利用原始套接字在数据链路层抓取MAC帧,去掉
    if(sockfd < 0){                                            //14个字节的MAC帧首部即可
        printf("create sock failed\n");
    return -1;
    }    
    int n = recvfrom(sockfd, buffer, 1024, 0, NULL, NULL); //接收MAC帧

    printf("receive %d bytes\n", n);
    for(int i=14; i<n; i++){      //去掉MAC帧首部,直接输出IP数据报每个字节的数据
    if((i-14) % 16 == 0)
        printf("\n");
    printf("%d ",buffer[i]);
    }
    printf("\n");
    printf("ipcksum: %d\n", cksum(buffer+14, 20)); //此处再次校验时,应当输出0
    return 0;
}

这是之前参考
Referenced from:https://blog.csdn.net/nice_wen/article/details/53416063

本文链接地址:https://const.net.cn/569.html

标签: socket

添加新评论