一.项目流程图

二.环境搭建

主机:

Ubuntu:

设置网络:

开发板:
设置IP:ifconfig eth0 192.168.2.1 netmask 255.255.255.0
设置网关:route add  default gw 192.168.2.2

实践:

主机与虚拟机相互ping

成功:

开发板与主机相互ping

失败:(因为是不同网段)

ok,完成

最后,运行我们写的路由器代码后,主机与开发板可以在不同网段下通信

开发板与主机相互ping

成功:

三.遇到的问题

1.默认网关有问题,导致开发板ping不通wind主机,后重启开发板后重新添加默认网关解决

异常(ping不通)

正常(可ping通)

2.wind的默认网关填错,导致ping不通开发板,这里的默认网关是根据虚拟机里面网卡来填的,需要灵活变动。

3.在虚拟机里面是需要2个网卡都能使用,在virtualbox只能有一个网卡可以down和up,所以环境一直有问题

成功互相ping通

四.代码如下:

Makefile

CC=gcc
target=main
$(target):main.o get_interface.o link.o -lpthread
	$(CC) main.o get_interface.o link.o -o $(target) -lpthread
%*.o:%*.c
	$(CC) -c $^ -o $@
clean:
	rm -rf *.o $(target)

main.c

#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/ether.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include "get_interface.h"
#include "link.h"


MY_ROU * roulink_head = NULL;
MY_ARP * arplink_head = NULL;
int sockfd = 0;
//*************************人机交互线程**********************************
void *callback1(void *arg)
{ 
    while(1)
    {  
        printf("输入相应的序号,实现对应功能\n");
        int usercmd = -1;
        scanf("%d", &usercmd);
        switch (usercmd)
        {
        case 0:
            getchar();
            title();
            break;
        case 2:                    
            getchar();//接收输入2的回车
            roulink_head=rou_pTailInsert(roulink_head);
            break;        
        case 3:
            getchar();
            roulink_head=rou_pDeleteLink(roulink_head);
            break;
        case 4:
            getchar();
            rou_print_link(roulink_head);/*将指针pHead传入输出函数遍历输出*/           
            printf("链表打印完毕!\n");
            break;        
        case 5:
            arp_print_link(arplink_head);
            break;
        case 10:
            printf("10:退出路由器,释放IP、ARP链表\n");
            getchar();
            arp_freeLink(arplink_head);
            rou_freeLink(roulink_head);//释放链表
            exit(1);
            break;
        }
    }
    pthread_exit(NULL);
}
//*************************人机交互线程**********************************


//*************************ARP应答的IP和MAC存入缓存链表线程【开始】**************//
void * callback2_arp(void *arg)
{
    arp_mac_ip *p = (arp_mac_ip*)arg;
    
    //printf("将 ARP 应答的 IP 和 MAC 存入缓存链\n");
    //printf("### %s\n", p->stc_ip);
    if(arp_searcharpLink(arplink_head, p->stc_ip) == 0)
    {
        printf("插入链表中没有的ARP 应答 IP 和 MAC\n");
        arplink_head = arp_pTailInsert( arplink_head, p->stc_mac ,p->stc_ip);
    }

    pthread_exit(NULL);
}
//*************************ARP应答的IP和MAC存入缓存链表线程【结束】***************//


//*************************IP包转发线程【开始】**********************************//
void *callback3_ip(void *arg)
{
    
    //发送接口的结构体
    struct sockaddr_ll sll;
    ip_buf *pthread_ip_buf = (ip_buf *)arg;
  

    unsigned char * ip_head= pthread_ip_buf->buf + 14;
    char dst_ip[16] = "";

    inet_ntop(AF_INET, ip_head + 16, dst_ip, 16);
    printf("IP包转发线程中 目的 dst_ip = %s\n", dst_ip);


    int i = 0;
    for (i = 0; i < 16; i++)
    {
       
        unsigned char ip[16]=""; 
        inet_ntop(AF_INET,net_interface[i].ip, ip, 16);//get_interface文件中得到的都是32位无符号整形数据(计算机数据),现转成成点分十进制(人能够书别的)

        //---------------------[调试]----------------------------------------//
        //printf("设置网卡循环进入次数 i = %d\n", i);
        //printf("检索到的所有网卡名字net_interface[i].name = %s\n", net_interface[i].name);
        //printf("net_interface[i].ip = %s\n",ip);
        //---------------------[调试]----------------------------------------//

        if(strncmp(ip,  dst_ip, 9) == 0)//根据目标网段 查找活跃网卡
        {   
            //网卡结构体
            struct ifreq ethreq;
            strncpy(ethreq.ifr_name, net_interface[i].name , IFNAMSIZ);//指定网卡名字
            printf("网卡名字:%s\n", ethreq.ifr_name);
            
            if(ioctl(sockfd, SIOCGIFINDEX, &ethreq) == -1)//获取网卡接口地址
            {
                return 0;
            }

            bzero(&sll, sizeof(sll));
            sll.sll_ifindex = ethreq.ifr_ifindex;//将网卡的接口类型赋值给发送接口
            break;
        }
        else
        {
            //printf("找不到网段对应的网卡,继续查\n");
            continue;
        }
    }

    //--------------------------------------------拿到网卡,开始检索对应网卡所有数据,对比【开始】------------------------------------------------------//
    if(strcmp(dst_ip + strlen(dst_ip) - 3, "255") == 0)//是 否为广 播地址
    {
       // printf("是广播地址, 退出线\n"); 
        return;              
    }
    else
    {
        //printf("不是广播地址,判断是否为回 环地址\n");
        if(strcmp("127.0.0.1",  dst_ip) == 0)
        {
            //printf("是回 环地址, 退出线\n");
            return;                      
        }
        else
        {
            //printf("查找ARP缓存表 对应 MAC\n");
            //指定目的MAC地址
            //可以在链表中找到目的IP,组ICMP包的目的MAC就可以了
            //之所以这样,是因为在网络中的ICMP包里,变化的只有目的MAC,源MAC、IP都不会发生变动
            if(arp_searcharpLink(arplink_head, dst_ip) == 1)
            {  
                //1网段中 指定目标IP是主机的IP、MAC
                //2C-4D-54-57-04-7F
                //printf("****icmp****\n");
                if(strncmp("192.168.1.49", dst_ip, 9) == 0)
                {
                    pthread_ip_buf->buf[0]=0x2C;
                    pthread_ip_buf->buf[1]=0x4D;
                    pthread_ip_buf->buf[2]=0x54;
                    pthread_ip_buf->buf[3]=0x57;
                    pthread_ip_buf->buf[4]=0x04;
                    pthread_ip_buf->buf[5]=0x7F;//目标
                    int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));

                    //-------------------[调试]------------------------//
                    //printf("****1 网段 icmp缓存表****\n");   
                    // printf("send_len ICMP 1 = %d\n", send_len);
                    //-------------------[调试]------------------------//

                }
                //2网段中 指定目标IP是开发板的IP、MAC
                //  00:53:50:00:01:33
                else if(strncmp("192.168.2.100", dst_ip, 9) == 0)
                {                   
                    pthread_ip_buf->buf[0]=0x00;
                    pthread_ip_buf->buf[1]=0x53;
                    pthread_ip_buf->buf[2]=0x50;
                    pthread_ip_buf->buf[3]=0x00;
                    pthread_ip_buf->buf[4]=0x59;
                    pthread_ip_buf->buf[5]=0x12;
                   
                    //发送给套接字的数据长度,是实际传送过来的长度(main中的IP包有收到具体长度信息)
                    int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));

                    //-------------------[调试]------------------------//
                    //printf("****2 网段 icmp缓存表****\n");   
                    // printf("send_len ICMP 2 = %d\n", send_len);
                    //-------------------[调试]------------------------//
                }
            }
            else
            {//没在链表中没有找到目的IP,需要重新组arp包才行

                //printf("***************组ARP包\n");
                int i = 0;
                for(; i < 3; i++)
                {     
                    //printf("%s\n",dst_ip);  
                    //比对到1网段的数据             
                    if(strstr(dst_ip,"192.168.1") != 0)                      
                    {
                        printf("发送网段1arp包\n");
                        unsigned char arp_buf[42] = {
                        0xff,0xff,0xff,0xff,0xff,0xff,//目的mac,广播的形式发出去,等待目的IP恢复后覆盖
                        0x00,0x0c,0x29,0xfa,0x7c,0x9e,//源mac
                        0x08, 0x00,//协议类型
                        0, 1,//硬件类型
                        6,
                        4,
                        0, 1,//op
                        0x00,0x0c,0x29,0xfa,0x7c,0x9e,//源mac(网卡1 ech0的MAC)
                        192,168,1,88,//源IP是路由器1网段的网关,通过它发送到2网段
                        0x00,0x00,0x00,0x00,0x00,0x00,//目的mac,等待目的IP恢复后覆盖
                        0,0,0,0
                        //192,168,1,49,
                        };
                        int int_ip=0;
                        inet_pton(AF_INET, dst_ip, &int_ip);
                        unsigned char *intp=(char *)&int_ip;
                        arp_buf[38]=intp[0];
                        arp_buf[39]=intp[1];
                        arp_buf[40]=intp[2];
                        arp_buf[41]=intp[3];
                        int send_len = sendto(sockfd, arp_buf, sizeof(arp_buf), 0, (struct sockaddr *)&sll, sizeof(sll));
                        printf("send_len 11 = %d\n",send_len);

                    }
                    //网卡2,ech1的MAC:00:0c:29:fa:7c:a8
                    else if(strstr(dst_ip,"192.168.2") != 0)                      
                    {
                        printf("发送网段2arp包\n");
                        unsigned char arp_buf[42] = {
                        0xff,0xff,0xff,0xff,0xff,0xff,//目的mac
                        0x00,0x0c,0x29,0xfa,0x7c,0xa8,//源mac
                        0x08, 0x00,//协议类型
                        0, 1,//硬件类型
                        6,
                        4,
                        0, 1,//op
                        0x00,0x0c,0x29,0xfa,0x7c,0xa8,//源mac
                        192,168,2,89,//源IP是路由器2网段的网关,通过它发送到1网段
                        0x00,0x00,0x00,0x00,0x00,0x00,//目的mac
                        192,168,2,100,
                        };
                        int send_len = sendto(sockfd, arp_buf, sizeof(arp_buf), 0, (struct sockaddr *)&sll, sizeof(sll));
                        printf("send_len 22 = %d\n",send_len);

                    }

                    if(arp_searcharpLink(arplink_head, dst_ip) == 1)
                    {
                        //1
                        //2C-4D-54-57-04-7F
                        if(strncmp("192.168.0.11", dst_ip, 9) == 0)
                        {
                            pthread_ip_buf->buf[0] =  0xA8;
                            pthread_ip_buf->buf[1] =  0x5E;
                            pthread_ip_buf->buf[2] =  0x45;
                            pthread_ip_buf->buf[3] =  0xC1;
                            pthread_ip_buf->buf[4] =  0x8B;
                            pthread_ip_buf->buf[5] =  0x99;
                            int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));
                            //-------------------[调试]------------------------//
                            //printf("****3次发ARP过程中检索到ICMP包 1 网段****\n");   
                            // printf("send_len ICMP 1 = %d\n", send_len);
                            //-------------------[调试]------------------------//
                        }
                        //2
                        // 开发板MAC(每次启动都会变化):1C:59:74:81:4A:43
                          1C:59:74:81:4A:43

                        else if(strncmp("192.168.1.1", dst_ip, 9) == 0)
                        {
                            pthread_ip_buf->buf[0] =  0x1c;
                            pthread_ip_buf->buf[1] =  0x59;
                            pthread_ip_buf->buf[2] =  0x74;
                            pthread_ip_buf->buf[3] =  0x81;
                            pthread_ip_buf->buf[4] =  0x4A;
                            pthread_ip_buf->buf[5] =  0x43;
                            int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));
                            //-------------------[调试]------------------------//
                            //printf("****3次发ARP过程中检索到ICMP包 2 网段****\n");   
                            // printf("send_len ICMP 2 = %d\n", send_len);
                            //-------------------[调试]------------------------//

                        }
                        break;
                    }
                }
            }

            return;

        }
    } 
    //--------------------------------------------拿到网卡,开始检索对应网卡所有数据,对比【结束】------------------------------------------------------//


    pthread_exit(NULL);

}
//*************************建IP包转发线程【结束】**********************************//

int main()
{
    //创建原始套接字,接收发送方的网卡信息
    sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if(sockfd<0)
    {
        perror("sockfd:");
        return 0;
    }
    getinterface();//拿取网卡信息(虚拟机的所有网卡,包括回环网卡)

    pthread_t pth;
    pthread_create(&pth, NULL, callback1, NULL);//人机交互线程,这里可以放在main里面

    int len = 0;

    char recv_buff[RECV_SIZE]="";//原始套接字数据包大约为1500个字节
	ssize_t recv_len=0;
    while(1)
    {              
        //开始接收其他人的网卡信息
        bzero(recv_buff,sizeof(recv_buff));
       
        //[recv_len]设置成全局变量,让线程可以共用数据
        recv_len = recvfrom(sockfd, recv_buff, sizeof(recv_buff), 0,  NULL, NULL);
        if(recv_len<=0||recv_len>RECV_SIZE)
        {
		    perror("recvfrom");
			continue;
		}
        //printf("链路层截取数据包长度 recv_len=%d\n",recv_len);

        //MAC包类型
        unsigned short mac_type = 0;
        mac_type = ntohs( *((unsigned short *)(recv_buff + 12)));
        if(mac_type == 0x0800)
        {
            //printf("-----------ip数据包------------\n");
            unsigned char *ip_head = recv_buff + 14; 
            unsigned char dst_ip[16] ="";
            inet_ntop(AF_INET, ip_head + 16, dst_ip, 16);

            //IP包的类型
            if(ip_head[9] == 1)
            {
                //printf("-----ICMP数据包\n");
                //查找过滤IP链表中存在我们指定的目的IP吗
                if(rou_searcharpLink(roulink_head, dst_ip) == 0)
                {
                    static int i=0;
                          
                    //-----------调试,打印原始套接字接收到的数据内容是否是空--------------------//           
                    //printf("i=%d   IP包中的目的IP = %d\n",++i, strlen(recv_buff + 30));                             
                    // printf("Rvfbuf=%p\n",recv_buff);
                    // int kk=0;
                    // while(kk<98)
                    // {
                    //     printf("Rvfbuf[%d]=%d\n",kk,recv_buff[kk]);
                    //     kk++;

                    // }
                    //----------------------------[调试]---------------------------------------//

                    usleep(1000); 
                    ip_buf *recv = (ip_buf *)malloc(sizeof(ip_buf));
                    recv->my_buf_date_len = recv_len;
                    memcpy(recv->buf, recv_buff, recv_len);

                    //线程的创建放在满足它的条件中,while循环,满足就进来创建一个,切记不要放到条件外面创建线程,否则只会创建一个,导致所有情况共用一个线程
                    pthread_t pth2;
                    //最后数据包是ICMP的整包
                    pthread_create(&pth2, NULL, callback3_ip, (void*)recv);
                    pthread_detach(pth2);
                }

            }

        }
        else if(mac_type == 0x0806)
        {           
            arp_mac_ip * head_mac_ip = NULL;//保存目的MAC\IP的结构体,安全措施,防止栈空间释放导致给线程传参为空,失败
            head_mac_ip = (arp_mac_ip *)malloc(sizeof(arp_mac_ip ));
            
            
            unsigned char *arp_head = recv_buff + 14;
            unsigned char * arp_src_mac =  arp_head + 8;//跳过[4.硬件类型、5.协议类型、6.硬件地址长度、7.协议地址长度、8.OP,拿到源MAC地址首地址信息]
            unsigned char stc_mac[18] = "";
            sprintf(stc_mac, "%02x:%02x:%02x:%02x:%02x:%02x", arp_src_mac[0],\
                arp_src_mac[1],\
                arp_src_mac[2], \
                arp_src_mac[3],\
                arp_src_mac[4], \
                arp_src_mac[5]);
            strcpy(head_mac_ip->stc_mac, stc_mac);
                   
            unsigned char src_ip[16]  = "";
            inet_ntop(AF_INET, arp_head + 14, src_ip, 16);//拿到源IP           
            strcpy(head_mac_ip->stc_ip, src_ip);

            //-----------------------------------[调试]-----------------------------------//   
            //printf("-----------arp数据包------------\n");
            //printf("arp 源mac:%s\n",head_mac_ip->stc_mac);        
            //printf("arp 源IP:src_ip = %s  \n", src_ip); 
            //-----------------------------------[调试]-----------------------------------//  

            //线程中只保存源ARP的MAC、IP,目的主机的MAC、IP,在IP线程中指定(写死)
            pthread_t pth1;
            pthread_create(&pth1, NULL, callback2_arp, (void*)head_mac_ip);
            pthread_detach(pth1);
        }


    }

    return 0;
}

link.c

#include "link.h"

void title()
{
    printf("[人机交互线程的全部功能]\n");
    printf("2:设置过滤 IP \n");
    printf("3:删除过滤 IP \n");
    printf("4:查看过滤 IP \n");
    printf("5:查看 arp 缓存 \n");
    printf("10:退出路由器\n");
}


//*************************过滤链表******************************
//尾插
MY_ROU *rou_pTailInsert(MY_ROU *head)
{
    //申请一个待插入的空间
    MY_ROU *pi=(MY_ROU*)malloc(sizeof(MY_ROU));
    pi->next=NULL;
    printf("输入过滤ip:");
    //向空间中插入数据
    scanf("%s",pi->ip);
    //判断是否有数据
    if(head==NULL)
    {
        head=pi;
    }
    else
    {
        //寻找插入的节点
        MY_ROU *p1=head;
        while(p1->next!=NULL)
        {
            p1=p1->next;
        }
        //插入
        p1->next=pi;
    }
    printf("设置完成\n");
    return head;
}

//遍历
void rou_print_link(MY_ROU *head)
{
    if(head==NULL)
    {
        printf("没有数据\n");
    }
    else
    {
        while(head!=NULL)
        {
            printf("ip:%s\n",head->ip);
            head=head->next;
        }
    }
    return;
}

//释放链表
MY_ROU* rou_freeLink(MY_ROU *head)
{
    MY_ROU *pd;
    pd=head;
    while(head!=NULL)
    {
        head=pd->next;
        free(pd);
        pd=head;
    }
    printf("过滤链表释放完毕\n");
    return head;
}

//查找ip
int rou_searcharpLink(MY_ROU *head,char *ip)
{
    int i=0;
    while(head!=NULL)
    {
        if(strcmp(ip,head->ip)==0)
        {
            i++;
            //printf("存在相同ip\n");
            return 1;
        }
        head=head->next;
    }
    if(0==i)
    {
        //printf("未找到ip\n");
        return 0;
    }
}

//删除
MY_ROU *rou_pDeleteLink(MY_ROU *head)
{
    char num[16]="";
    MY_ROU *pe=head;
    MY_ROU *pf=head;

    printf("请输入你要删除的ip:");
    scanf("%s",num);

    if(NULL==head)
    {
        printf("无可删除数据\n");
    }
    else
    {
        while(strcmp(pe->ip,num))
        {
            pf=pe;
            pe=pe->next;
            if(NULL==pf->next)
            {
                printf("未找到要删除数据\n");
                return head;
            }
        }

        if(pe==head)
        {
            head=pe->next;
            free(pe);
        }
        else
        {
            pf->next=pe->next;
            free(pe);
        }
    }
    return head;
}
//*************************过滤链表******************************

//*************************arp缓存表*****************************
//arp缓存表尾插
MY_ARP *arp_pTailInsert(MY_ARP *head,char *mac,char *ip)
{
    //申请一个待插入的空间
    MY_ARP *pi=(MY_ARP*)malloc(sizeof(MY_ARP));
    pi->next=NULL;
    //向空间中插入数据
    strcpy(pi->ip,ip);
    strcpy(pi->mac,mac);
    //判断是否有数据
    if(head==NULL)
    {
        head=pi;
    }
    else
    {
        //寻找插入的节点
        MY_ARP *p1=head;
        while(p1->next!=NULL)
        {
            p1=p1->next;
        }
        //插入
        p1->next=pi;
    }
    printf("插入一个ip:%s    mac:%s 到arp缓存表\n",pi->ip,pi->mac);
    return head;
}

//arp中查找ip和mac
int arp_searcharpLink(MY_ARP *head,char *ip)
{
    int i=0;
    while(head!=NULL)
    {
        if(strcmp(ip,head->ip)==0)
        {
            i++;
            //printf("存在相同ip和mac\n");
            return 1;
        }
        head=head->next;
    }
    if(0==i)
    {
        //printf("未找到ip和mac\n");
        return 0;
    }
}

//遍历arp缓存表
void arp_print_link(MY_ARP *head)
{
    if(head==NULL)
    {
        printf("没有数据\n");
    }
    else
    {
        while(head!=NULL)
        {
            printf("ip:%s mac:%s\n",head->ip,head->mac);
            head=head->next;
        }
    }
    return;
}

//释放arp链表
MY_ARP* arp_freeLink(MY_ARP *head)
{
    MY_ARP *pd;
    pd=head;
    while(head!=NULL)
    {
        head=pd->next;
        free(pd);
        pd=head;
    }
    printf("arp链表释放完毕\n");
    return head;
}
//*************************arp缓存表*****************************

link.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define RECV_SIZE 2048
typedef struct My_buf
{
    unsigned char buf[RECV_SIZE];
    int my_buf_date_len;
}ip_buf;



typedef struct Arp_mac_ip
{
    char stc_mac[18];
    char stc_ip[16];
}arp_mac_ip;


extern void title();

//*************************arp缓存表*****************************
typedef struct myarp
{
    unsigned char mac[32] ;
    unsigned char ip[32] ;

    struct myarp* next;
}MY_ARP;


//arp缓存表尾插
extern MY_ARP *arp_pTailInsert(MY_ARP *head,char *mac,char *ip);
//arp中查找ip
extern int arp_searcharpLink(MY_ARP *head,char *ip);
//遍历arp缓存表
extern void arp_print_link(MY_ARP *head);
//释放arp链表
extern MY_ARP* arp_freeLink(MY_ARP *head);
//*************************arp缓存表*****************************




//*************************过滤链表******************************
typedef struct myrouter
{
    unsigned char ip[32] ;
    struct myrouter* next;
}MY_ROU;

//释放链表
extern MY_ROU* rou_freeLink(MY_ROU *head);
//尾插
extern MY_ROU *rou_pTailInsert(MY_ROU *head);
//遍历
extern void rou_print_link(MY_ROU *head);
//查找ip
extern int rou_searcharpLink(MY_ROU *head,char *ip);
//删除
extern MY_ROU *rou_pDeleteLink(MY_ROU *head);
//*************************过滤链表******************************

get_interface.c

#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <netinet/ether.h>	
#include "get_interface.h"

int interface_num=0;//接口数量
INTERFACE net_interface[MAXINTERFACES];//接口数据

/******************************************************************
函	数:	int get_interface_num()
功	能:	获取接口数量
参	数:	无
*******************************************************************/
int get_interface_num(){
	return interface_num;
}

/******************************************************************
函	数:	int getinterface()
功	能:	获取接口信息
参	数:	无
*******************************************************************/
void getinterface()
{
	struct ifreq buf[MAXINTERFACES];    /* ifreq结构数组 */
	struct ifconf ifc;                  /* ifconf结构 */
	
	int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	 /* 初始化ifconf结构 */
    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t) buf;
 
    /* 获得接口列表,所有接口的清单  */
    if (ioctl(sock_raw_fd, SIOCGIFCONF, (char *) &ifc) == -1){
        perror("SIOCGIFCONF ioctl");
        return ;
    }
    interface_num = ifc.ifc_len / sizeof(struct ifreq); /* 接口数量 */
    printf("interface_num=%d\n\n", interface_num);
 	char buff[20]="";
	int ip;
	int if_len = interface_num;
    while (if_len-- > 0)
	{ /* 遍历每个接口 */
        printf("%s\n", buf[if_len].ifr_name); /* 接口名称 */
        sprintf(net_interface[if_len].name, "%s", buf[if_len].ifr_name); /* 接口名称 */
		printf("-%d-%s--\n",if_len,net_interface[if_len].name);
        /* 获得接口标志、flags值 */
        if (!(ioctl(sock_raw_fd, SIOCGIFFLAGS, (char *) &buf[if_len])))
		{
            /* 接口状态 */
			/*IFF_UP :网络装置是否正常启用,不会因插拔网络线而有任何变化*/
            if (buf[if_len].ifr_flags & IFF_UP){
                printf("UP\n");
				net_interface[if_len].flag = 1;
            }
            else{
                printf("DOWN\n");
				net_interface[if_len].flag = 0;
            }
        }
		else
		{
            char str[256];
            sprintf(str, "SIOCGIFFLAGS ioctl %s", buf[if_len].ifr_name);
            perror(str);
        }
 
        /* IP地址 */
        if (!(ioctl(sock_raw_fd, SIOCGIFADDR, (char *) &buf[if_len])))
		{
			/*inet_ntoa将一个网络字节序的IP地址(也就是结构体in_addr类型变量)
				转化为点分十进制的IP地址(字符串)*/
			printf("IP:%s\n",(char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
			bzero(buff,sizeof(buff));
			sprintf(buff, "%s", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
			
			/*新型网路地址转化函数inet_pton:
			  将点分十进制的ip地址转化为用于网络传输的数值格式*/
			inet_pton(AF_INET, buff, &ip);
			memcpy(net_interface[if_len].ip, &ip, 4);
		}
		else
		{
            char str[256];
            sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name);
            perror(str);
        }
 
        /* 子网掩码 */
        if (!(ioctl(sock_raw_fd, SIOCGIFNETMASK, (char *) &buf[if_len])))
		{
            printf("netmask:%s\n",(char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
			bzero(buff,sizeof(buff));
			sprintf(buff, "%s", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
			inet_pton(AF_INET, buff, &ip);
			memcpy(net_interface[if_len].netmask, &ip, 4);
        }
		else
		{
            char str[256];
            sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name);
            perror(str);
        }
 
        /* 广播地址 */
        if (!(ioctl(sock_raw_fd, SIOCGIFBRDADDR, (char *) &buf[if_len])))
		{
            printf("br_ip:%s\n",(char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
			bzero(buff,sizeof(buff));
			sprintf(buff, "%s", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
			inet_pton(AF_INET, buff, &ip);
			memcpy(net_interface[if_len].br_ip, &ip, 4);
        }
		else
		{
            char str[256];
            sprintf(str, "SIOCGIF./ADDR ioctl %s", buf[if_len].ifr_name);
            perror(str);
        }

        /*MAC地址 */
		if (!(ioctl(sock_raw_fd, SIOCGIFHWADDR, (char *) &buf[if_len])))
		{
			printf("MAC:%02x:%02x:%02x:%02x:%02x:%02x\n\n",
					(unsigned char) buf[if_len].ifr_hwaddr.sa_data[0],
					(unsigned char) buf[if_len].ifr_hwaddr.sa_data[1],
					(unsigned char) buf[if_len].ifr_hwaddr.sa_data[2],
					(unsigned char) buf[if_len].ifr_hwaddr.sa_data[3],
					(unsigned char) buf[if_len].ifr_hwaddr.sa_data[4],
					(unsigned char) buf[if_len].ifr_hwaddr.sa_data[5]);
			memcpy(net_interface[if_len].mac, (unsigned char *)buf[if_len].ifr_hwaddr.sa_data, 6);
		}
		else
		{
            char str[256];
            sprintf(str, "SIOCGIFHWADDR ioctl %s", buf[if_len].ifr_name);
            perror(str);
        }
    }//–while end
    close(sock_raw_fd);   //关闭socket
}

get_interface.h

#ifndef GET_INTERFACE_H
#define GET_INTERFACE_H

#define MAXINTERFACES 16    /* 最大接口数 */

typedef struct interface{
	char name[20];		//接口名字
	unsigned char ip[4];		//IP地址
	unsigned char mac[6];		//MAC地址
	unsigned char netmask[4];	//子网掩码
	unsigned char br_ip[4];		//广播地址
	int  flag;			//状态
}INTERFACE;
extern INTERFACE net_interface[MAXINTERFACES];//接口数据

/******************************************************************
函	数:	int getinterface()
功	能:	获取接口信息
参	数:	无
*******************************************************************/
extern void getinterface();

/******************************************************************
函	数:	int get_interface_num()
功	能:	获取实际接口数量
参	数:	接口数量
*******************************************************************/
int get_interface_num();


#endif

ip_file.h

#ifndef IP_FILE_H
#define IP_FILE_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>


//*************************过滤链表******************************
typedef struct myrouter
{
    unsigned char ip[32] ;
    struct myrouter* next;
}MY_ROU;

//释放链表
extern MY_ROU* rou_freeLink(MY_ROU *head);
//尾插
extern MY_ROU *rou_pTailInsert(MY_ROU *head);
//遍历
extern void rou_print_link(MY_ROU *head);
//查找ip
extern int rou_searcharpLink(MY_ROU *head,char *ip);
//删除
extern MY_ROU *rou_pDeleteLink(MY_ROU *head);
//*************************过滤链表******************************

/******************************************************************
函	数:	void init_ip_link()
功	能:	读取配置文件数据到链表
参	数:	无
返回值: 无
*******************************************************************/
extern void init_ip_link();

/******************************************************************
函	数:	IP_LINK *find_ip(IP_LINK *head, unsigned char *ip)
功	能:	插入ip过滤链表
参	数:	IP_LINK *head ip过滤链表头  IP_LINK* p 待插入节点
返回值: IP_LINK *找到的节点
*******************************************************************/
extern MY_ROU *inner_ip_link(MY_ROU *head,MY_ROU* p);

/******************************************************************
函	数:	void save_ip_link()
功	能:	保存链表数据到配置文件
参	数:	无
返回值: 无
*******************************************************************/
extern void save_ip_link();

#endif

 ip_file.c

#include "ip_file.h"
#define ip_config_name "ip_config"

//与main.c共用一个结构体指针变量,保存过滤IP链表头节点
MY_ROU * roulink_head = NULL;

//--------------------操作文件中的过滤IP----------------------//
void init_ip_link()
{
    FILE *ip_config = NULL;
    ip_config = fopen(ip_config_name,"rb+");
	if(ip_config == NULL){
		perror("!!!configure file,in main.c");
		_exit(1);
	}
	puts("filter IP:");
    int i = 0;
    while(1)
    {
        
        char buff[500]="";
        bzero(buff, sizeof(buff));
        int ip;
        if(fgets(buff, sizeof(buff), ip_config) == NULL)
        {
            printf("ip_config 文件为空\n");
            break;
        }
        if(strlen(buff) < 7)//1.1.1.1
        {
            break;
        }
        buff[strlen(buff)-1]=0;//注意文件中存在\r
        //printf("IP[%d] = %s\n",i++,buff);
        inet_pton(AF_INET, buff, &ip);

        MY_ROU *pb = (MY_ROU *)malloc(sizeof(MY_ROU));	
        char ip_buf[16] = "";
        inet_ntop(AF_INET, &ip, ip_buf, 16);
        //printf("ip_buf[%d] = %s\n", ++i, ip_buf);
        //strcpy(pb->ip, ip_buf);
        memcpy(pb->ip, ip_buf, 16);
        printf("pb->ip[%d] = %s\n", i, pb->ip);

        //传入变化的头节点 + 带有IP信息的结构体指针变量
        roulink_head = inner_ip_link(roulink_head, pb);
        i++;
    }

    //rou_print_link(ip_head);
	fclose(ip_config);
}

MY_ROU *inner_ip_link(MY_ROU *head, MY_ROU* p)
{

    // head = (MY_ROU*)malloc(sizeof(MY_ROU));     //创建头结点 
    // head->next = NULL;
    MY_ROU * pb = head;
	int a = rou_searcharpLink(head, p->ip);//查找是否有该记录
    if(a == 0)
    {
        if(pb==NULL)
        {//未查找到,插入链表,直接插入表头方便
            p->next = NULL;
            head = p;
        }
        else
        {           
            #if 1  //头插法--寻找插入的节点              
                MY_ROU * p2_new = (MY_ROU*)malloc(sizeof(MY_ROU)); 
                strcpy(p2_new->ip, p->ip);
                // printf("继续头插!!!!p2_new->ip = %s!!!!!!\n",p2_new->ip);
                p2_new->next = pb->next;
                pb->next = p2_new;
            #endif                                  
            #if 0 //尾插法--正确
                MY_ROU *p1=pb;
                while(p1->next!=NULL)
                {
                    p1=p1->next;
                }
                //插入
                p1->next=p;  
            #endif             
        }
    }
	return head;
}

void save_ip_link()
{
    FILE *ip_config = fopen(ip_config_name,"wb+");
	if(ip_config == NULL){
		perror("!!!configure file,in main.c");
		_exit(1);
	}

    char buff[20]="";
	MY_ROU *pb=roulink_head;
    while(pb != NULL)
    {
        printf("!保存2命令输入IP\n");
        memcpy(buff, pb->ip, 16);//一次拷贝16个字节
        buff[strlen(buff)+1]='\n';//注意文件中存在\r

        //一个IP新切换一行保存到文件
        fprintf(ip_config, "%s\n", buff);
		pb = pb->next;
    }
    fclose(ip_config);
}
//--------------------操作文件中的过滤IP----------------------//




//*************************过滤链表******************************//
//尾插
MY_ROU *rou_pTailInsert(MY_ROU *head)
{

    //申请一个待插入的空间
    MY_ROU *pi=(MY_ROU*)malloc(sizeof(MY_ROU));
    pi->next=NULL;
    printf("输入过滤ip:");
    //向空间中插入数据
    scanf("%s",pi->ip);
    //判断是否有数据
    if(head==NULL)
    {
        head=pi;
    }
    else
    {
        //寻找插入的节点
        MY_ROU *p1=head;
        while(p1->next!=NULL)
        {
            p1=p1->next;
        }
        //插入
        p1->next=pi;
    }
    

    printf("设置完成\n");
    return head;
}

//遍历
void rou_print_link(MY_ROU *head)
{
    if(head==NULL)
    {
        printf("没有数据\n");
    }
    else
    {
        while(head!=NULL)
        {
            printf("ip:%s\n",head->ip);
            head=head->next;
        }
    }
    return;
}

//释放链表
MY_ROU* rou_freeLink(MY_ROU *head)
{
    MY_ROU *pd;
    pd=head;
    while(head!=NULL)
    {
        head=pd->next;
        free(pd);
        pd=head;
    }
    printf("过滤链表释放完毕\n");
    return head;
}

//查找ip
int rou_searcharpLink(MY_ROU *head,char *ip)
{
    MY_ROU * pb = head;
    int i=0;
    while(pb!=NULL)
    {
        if(strcmp(ip, pb->ip)==0)
        {
            i++;
            //printf("存在相同ip\n");
            return 1;
        }
        pb = pb->next;
    }
    if(0==i)
    {
        //printf("未找到ip\n");
        return 0;
    }
}

//删除
MY_ROU *rou_pDeleteLink(MY_ROU *head)
{
    char num[16]="";
    MY_ROU *pe=head;
    MY_ROU *pf=head;

    printf("请输入你要删除的ip:");
    scanf("%s",num);

    if(NULL==head)
    {
        printf("无可删除数据\n");
    }
    else
    {
        while(strcmp(pe->ip,num))
        {
            pf=pe;
            pe=pe->next;
            if(NULL==pf->next)
            {
                printf("未找到要删除数据\n");
                return head;
            }
        }

        if(pe==head)
        {
            head=pe->next;
            free(pe);
        }
        else
        {
            pf->next=pe->next;
            free(pe);
        }
    }
    return head;
}
//*************************过滤链表******************************

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐