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!\n");
        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\n");
        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\n");
        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!\n");
        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\n");
        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\n");
        return -1;
    }


    while (1)
    {
        printf("Waiting for data from sender \n");
        count = recvfrom(sk, rec_buf, MAX_LEN, 0, (struct sockaddr*)&rem_addr, &rem_addr_len);
        //printf("%s %d\n", rec_buf,count);
        if(count==-1)
        {
            printf("receive data failure\n");
            return -1;
        }

        addr.s_addr = rem_addr.sin_addr.s_addr;
        printf("Receive info: %s from %s %d\n", 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 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM