自己實現一個自動檢測網卡狀態,並設置 ip 地址

一、usb 網卡應該如何實現?

前文講了如何利用開源軟件 ifplugd 實現監測網口狀態變化,

ifplugd 的確可以實現監測網卡的狀態,並執行相應腳本,

但是有個前提,就是網口已經註冊到系統中,即用 ifconfig -a 能查看到

如何是 usb 網卡這種設備,在插入 usb 口之後網口設備纔會註冊

使用過程中可能隨時會拔掉 usb 網卡,

那麼這種情況下,要想設置 usb 網卡,那麼就就需要修改 ifplugd 程序。

爲了方便大家理解,本文給大家講解如何自己實現一個簡化的程序 ethcheck

可以實現自動監測網卡是否存在

rk3568 所有網口:

rk3568_r:/system # ifconfig -a                                                
lo        Link encap:Local Loopback                                           
          inet addr:127.0.0.1  Mask:255.0.0.0                                 
          inet6 addr: ::1/128 Scope: Host                                     
          UP LOOPBACK RUNNING  MTU:65536  Metric:1                            
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0                                               
                                                                              
dummy0    Link encap:Ethernet  HWaddr fa:85:6c:74:1b:7d                       
          inet6 addr: fe80::f885:6cff:fe74:1b7d/64 Scope: Link                
          UP BROADCAST RUNNING NOARP  MTU:1500  Metric:1                      
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:560                                             
                                                                              
sit0      Link encap:IPv6-in-IPv4                                             
          NOARP  MTU:1480  Metric:1                                           
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0                                               
                                                                              
ip6tnl0   Link encap:UNSPEC                                                   
          NOARP  MTU:1452  Metric:1                                           
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0                                               
                                                                              
eth1      Link encap:Ethernet  HWaddr 5a:53:63:cf:dd:0b  Driver rk_gmac-dwmac 
          UP BROADCAST MULTICAST  MTU:1500  Metric:1                          
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0                                               
          Interrupt:51                                                        
                                                                              
ip_vti0   Link encap:UNSPEC                                                   
          NOARP  MTU:1480  Metric:1                                           
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0                                               
                                                                              
eth0      Link encap:Ethernet  HWaddr 5e:53:63:cf:dd:0b  Driver rk_gmac-dwmac 
          UP BROADCAST MULTICAST  MTU:1500  Metric:1                          
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0                                               
          Interrupt:38                                                        
                                                                              
ip6_vti0  Link encap:UNSPEC                                                   
          NOARP  MTU:1364  Metric:1                                           
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0                  
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0                
          collisions:0 txqueuelen:1000                                        
          RX bytes:0 TX bytes:0

二、程序設計

0. 程序框圖

1. 設置程序爲守護進程

因爲該程序最終要在後臺執行,並且常駐內存,所以必須將該進程設置爲守護進程

關於守護進程的內容,請參考下面文章:

搞懂進程組、會話、控制終端關係,才能明白守護進程幹嘛的?

參考代碼如下:

void init_daemon(void)
{
 int pid;
 int i;
 
 if(pid=fork())
  exit(0);//是父進程,結束父進程?
 
 else if(pid< 0)
  exit(1);//fork失敗,退出?
 
//是第一子進程,後臺繼續執行?
 setsid();//第一子進程成爲新的會話組長和進程組長?
//並與控制終端分離?
 chdir("/tmp");//改變工作目錄到/tmp?
 umask(0);//重設文件創建掩模?
 
 for(i=0;i< NOFILE;++i)//關閉打開的文件描述符?
  close(i);

 return;
}

2. 確認制定網口是否存在?

要確認指定網口是否存在,主要通過/proc/net/dev 目錄下是否有該網口信息:

peng@ubuntu:~$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:   26163     292    0    0    0     0          0         0    26163     292    0    0    0     0       0          0
  eth0: 285444708  243273    0    0    0     0          0         0 91828270   88660    0    0    0     0       0          0

如何用 C 語言實現檢測指定網口,可以參考下面文章:

簡簡單單教你如何用 C 語言列舉當前所有網口!

參考代碼:

static char * interface_name_cut (char *buf, char **name)
{
  char *stat;
  /* Skip white space.  Line will include header spaces. */
  while (*buf == ' ')
    buf++;
  *name = buf;
  /* Cut interface name. */
  stat = strrchr (buf, ':');
  *stat++ = '\0';
  return stat;
}
/*
return value:1 exist 0:no
*/ 
int check_interface_fromproc(char *interface)
{
  FILE *fp;
  char buf[PROCBUFSIZ];
  struct interface *ifp;
  char *name;
 
  /* Open /proc/net/dev. */
  fp = fopen (_PATH_PROC_NET_DEV, "r");
  if (fp == NULL)
    {   
        printf("open proc file error\n");
      return -1; 
    }   
 
  /* Drop header lines. */
  fgets (buf, PROCBUFSIZ, fp);
  fgets (buf, PROCBUFSIZ, fp);
 
  /* Only allocate interface structure.  Other jobs will be done in
     if_ioctl.c. */
  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
    {   
      interface_name_cut (buf, &name);
      if(strcmp(interface,name)==0)
          return 1;
    }   
  fclose(fp);
  return 0;
}

3. 指定網口不存在

如果檢測網口不存在,則需要休眠,然後繼續監測/proc/net/dev文件。

4. 如果指定網口存在

則獲取該網口的 IP 地址,然後比較是否是指定的 IP 地址

網卡 IP 地址的獲取,主要通過系統調用ioctl()SIOCGIFADDR命令實現

關於如何用 c 語言操作網卡,擦靠下面文章

《Linux 下 C 語言操作網卡的幾個代碼實例!特別實用》

參考代碼如下:

int getLocalIp(const char *eth, char *ip) {
    struct ifreq ifr;
    struct sockaddr_in sin;
    int fd;
    bzero(&ifr, sizeof(ifr));
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        return -1;
    }
    strcpy(ifr.ifr_name, eth);
    if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
        close(fd);
        return -1;
    }
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr));
    close(fd);
    return 0;
}

讀取的 ip 地址存放在參數ip指向的內存中。

5. ip 地址相同

如果網卡地址與指定的 ip 地址相同,那麼不需要修改地址,休眠一段時間(根據實際操作的頻率設置時間), 然後再監測網口是否存在

6. IP 地址不相同

如果 ip 地址不相同,則需要修改 ip 地址,

執行我們提前設置好的腳本 if.sh 即可

#!/bin/bash

IPADDR=192.168.40.8
ETHPORT=eth1
echo "ethcheck set" $ETHPORT $IPADDR
echo $#
echo $0
echo $1
echo $2
if [ $# -eq 2 ];then
 if [ $1 = $ETHPORT ];then 
 echo $ETHPORT
 if [ $2 = "up" ];then
 ifconfig $ETHPORT $IPADDR
 sleep 1
 ip rule add from all lookup main pref 9000 
 sleep 1
 echo 1 > /proc/sys/net/ipv4/ip_forward 
 iptables -F
 echo "set" $ETHPORT "done"
 elif [ $2 = "down" ];then
 echo "down"
 elif [ $2 = "disable" ];then
 echo "disable"
 elif [ $2 = "error" ];then
 echo "error"
 fi
 fi
fi

7. 設置爲開機啓動

要實現開機就自動運行 ifplugd,可以參考下面文章:

《安卓如何設置開機自動啓動某個程序?ramdisk + init.rc 給你搞定》

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/LaVPfsa2amLqp4PJdANjBw