zoukankan      html  css  js  c++  java
  • Linux下实现修改IP选项字段

    一:linux下实现UDP通信

    二:实验目的

    (一)在IP头部“选项”字段如何添加自定义的信息,作为自定义的匹配字段用

    例如对UDP报文添加一个序列号,使得接收方按照序列进行一定操作。则需要在IP的包头选项字段中进行自定义字段

    (二)实现思路

    1.修改Linux网络源码---目前有点困难

    2.利用现有的一些Linux网络编程函数,进行修改,这里选用setsockopt()----就是这个思路

    三:推文

    setsockopt 设置socket 详细用法

    setsockopt

    四:代码实现

    客户端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    
    #define MAX_LEN 1000
    //#define LOC_PORT 9090    //本地监听端口
    //#define REM_PORT 8080    //远程发送端口
    
    //#define SER_IP "10.0.0.1"
    #define MAXSIZE 40
    
    #define IPOPT_TAG 0x21        //IP选项标志字段
    #define IPOPT_LEN 8            //IP选项长度字段
    
    
    int str_to_number(const char* str);
    
    int main(int argc, char** argv)
    {
        char rec_buf[MAX_LEN];                                        //接受信息
        char snd_buf[MAX_LEN];                                        //发送信息
    
        int sk;                                                        //socket句柄
        struct sockaddr_in loc_addr;                                //用于指定本地监听信息
        struct sockaddr_in rem_addr;                                //获取远程地址信息
        int loc_addr_len,rem_addr_len;
    
        int count,ret;
        struct in_addr addr;                                        //用于获取地址信息
        int optval = 1;
        unsigned int SeqID=0;
    
        int LOC_PORT,REM_PORT;                                        //指定本地端口,和服务器端口
        char *SER_IP;                                                //用于获取服务器IP
         //构造自定义的TCP选项
         //unsigned char opt[MAXSIZE];
         //opt[0] = IPOPT_TAG;
         //opt[1] = IPOPT_LEN;
        unsigned char opt[MAXSIZE];
        opt[0] = 0x21;    
        opt[1] = IPOPT_LEN;
    
        //检查传参
        if(argc != 4)                                                //第一个是程序名,第二个是本地端口,第三个是服务器ip,第四个是服务器端口
        {
            printf("Error: Number of Input Argv must be 4!
    ");
            return -1;
        }
        LOC_PORT = str_to_number(argv[1]);
        REM_PORT = str_to_number(argv[3]);
        SER_IP = argv[2];
    
        bzero(&loc_addr, sizeof(loc_addr));
        loc_addr.sin_family = AF_INET;
        loc_addr.sin_addr.s_addr = htonl(INADDR_ANY);                //作为服务器,可能有多块网卡,设置INADDR_ANY,表示绑定一个默认网卡进行监听
        loc_addr.sin_port = htons(LOC_PORT);
        loc_addr_len = sizeof(loc_addr);
    
        bzero(&rem_addr, sizeof(rem_addr));
        rem_addr.sin_family = AF_INET;
        rem_addr.sin_addr.s_addr = inet_addr(SER_IP);                //作为服务器,可能有多块网卡,设置INADDR_ANY,表示绑定一个默认网卡进行监听
        rem_addr.sin_port = htons(REM_PORT);
        rem_addr_len = sizeof(loc_addr);
    
        sk = socket(AF_INET, SOCK_DGRAM, 0);
        if(sk<0)
        {
            printf("socket create failure
    ");
            return -1;
        }
        setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));    //设置地址复用
    
        ret = bind(sk, (struct sockaddr*)&loc_addr, loc_addr_len);
        if(ret < 0)
        {
            printf("socket bind failure
    ");
            return -1;
        }
    
        while (1)
        {
            printf("Input info:>>>");
            scanf("%s", snd_buf);
            if (!strcmp(snd_buf, "quit"))
                break;
                 //写入选项数据
            *(int *)(opt + 2) = htonl(++SeqID);  
            setsockopt(sk,IPPROTO_IP,IP_OPTIONS,(void *)opt,IPOPT_LEN);
            sendto(sk, snd_buf, strlen(send_buf)+1, 0, (struct sockaddr*)&rem_addr, rem_addr_len);
        }
    
        close(sk);
    
        return 0;
    }
    
    int str_to_number(const char* str)
    {
        int i,len, num = 0;
        len= strlen(str);
    
        for (i = 0; i < len;i++)
            num = num * 10 + str[i] - '0';
    
        return num;
    }

    int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

    sockfd:标识一个套接口的描述字。

    level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。

    optname:需设置的选项。

    optval:指针,指向存放选项待设置的新值的缓冲区。

    optlen:optval缓冲区长度。

    #define MAXSIZE 40
    
    #define IPOPT_TAG 0x21        //IP选项标志字段
    #define IPOPT_LEN 8            //IP选项长度字段
     
    unsigned char opt[MAXSIZE];    
    opt[0] = 0x21;        
    opt[1] = IPOPT_LEN;    注意:第二个字节必须是IP选项长度
    
    setsockopt(sk,IPPROTO_IP,IP_OPTIONS,(void *)opt,IPOPT_LEN);
    IPPROTO_IP,IP_OPTIONS   表示修改的是IP层的IP选项字段
    (void *)opt,IPOPT_LEN   表示传输的选项数据和IP选项长度  

    注意:虽然首部长度是4字节的倍数,但是选项字段的长度必须是8的倍数,不足8字节倍数,则会填充0。所以设置为IPOPT_LEN是8的倍数

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    
    #define MAX_LEN 1000
    #define MAX_SIZE 40
    #define IPOPT_LEN 8
    //#define LOC_PORT 8080                                                        //本地监听端口
    
    int str_to_number(const char* str);
    
    int main(int argc, char** argv)
    {
        char rec_buf[MAX_LEN];                                                    //接受信息
        char snd_buf[MAX_LEN];                                                    //发送信息
    
        int sk;                                                                    //socket句柄
        struct sockaddr_in loc_addr;                                            //用于指定本地监听信息
        struct sockaddr_in rem_addr;                                            //获取远程地址信息
        int loc_addr_len,rem_addr_len;
    
        int count,ret,i,opt_len=MAX_SIZE;
        struct in_addr addr;                                                    //用于获取地址信息
        int optval = 1;
    
        int LOC_PORT;
    
        unsigned char opt[MAX_SIZE];
        //opt[0] = 0x21;    
        //opt[1] = IPOPT_LEN;
    
        //检查传参
        if(argc != 2)                                                            //第一个是程序名,第二个是本地端口
        {
            printf("Error: Number of Input Argv must be 2!
    ");
            return -1;
        }
    
        LOC_PORT = str_to_number(argv[1]);
    
        bzero(&loc_addr, sizeof(loc_addr));
        loc_addr.sin_family = AF_INET;
        loc_addr.sin_addr.s_addr = htonl(INADDR_ANY);                            //作为服务器,可能有多块网卡,设置INADDR_ANY,表示绑定一个默认网卡进行监听
        loc_addr.sin_port = htons(LOC_PORT);
        loc_addr_len = sizeof(loc_addr);
    
        sk = socket(AF_INET, SOCK_DGRAM, 0);
        if(sk<0)
        {
            printf("socket create failure
    ");
            return -1;
        }
        setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));            //设置地址复用
    
        ret = bind(sk, (struct sockaddr*)&loc_addr, loc_addr_len);
        if(ret < 0)
        {
            printf("socket bind failure
    ");
            return -1;
        }
    
    
        while (1)
        {
            printf("Waiting for data from sender 
    ");
            count = recvfrom(sk, rec_buf, MAX_LEN, 0, (struct sockaddr*)&rem_addr, &rem_addr_len);
            //printf("%s %d
    ", rec_buf,count);
            if(count==-1)
            {
                printf("receive data failure
    ");
                return -1;
            }
    
            addr.s_addr = rem_addr.sin_addr.s_addr;
            printf("Receive info: %s from %s %d
    ", rec_buf,inet_ntoa(addr),rem_addr.sin_port);
        }
    
        close(sk);
    
        return 0;
    }
    
    int str_to_number(const char* str)
    {
        int i,len, num = 0;
        len= strlen(str);
    
        for (i = 0; i < len;i++)
            num = num * 10 + str[i] - '0';
    
        return num;
    }

    抓包查看:

    因为查看的是第二条消息,故接收的报文选项字段数据为2 
  • 相关阅读:
    #include <boost/scoped_ptr.hpp>
    #include <boost/function.hpp>
    #include <boost/bind.hpp>
    8.4散列表查找
    #include <boost/array.hpp>
    异常
    lambda
    #include <amp.h>
    #include <bitset>
    #include <hash_set>
  • 原文地址:https://www.cnblogs.com/ssyfj/p/12179675.html
Copyright © 2011-2022 走看看