Networking

如何從點擊界面讀取數據?

  • February 9, 2019

我遇到了網橋和 tun/tap 設備的問題。

實際上,主要問題是我試圖在編譯之前創建一個網橋和一個 Tap 介面。在編譯時我的程式碼需要使用介面。在我的項目程式碼中,the Contiki( https://github.com/contiki-os/contiki ) 程式碼被編譯並用於創建點擊介面和通信。

如果我用命令執行我的原始碼sudo,一切都很好,但正如我所說,我之前需要創建點擊界面,我應該在沒有sudo命令的情況下執行程式碼。

因此,如果我的程式碼使用sudo命令執行,ifconfig tap0則響應如下所示;

tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
       inet6 fc00::231  prefixlen 7  scopeid 0x0<global>
       inet6 fe80::cc9f:ddff:fe50:7d9a  prefixlen 64  scopeid 0x20<link>
       ether ce:9f:dd:50:7d:9a  txqueuelen 1000  (Ethernet)
       RX packets 50  bytes 12195 (12.1 KB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 52  bytes 7869 (7.8 KB)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

在這種狀態下,我的項目執行良好。

但我正在嘗試使用以下命令創建點擊界面;

sudo ip tuntap add mode tap tap0 user myusername
sudo ifconfig tap0 up
sudo ip link set tap0 up
sudo ip -6 address add fc00::231/7 dev tap0
sudo ip address add dev tap0 scope link fe80::cc9f:ddff:fe50:7d9a

然後是ifconfig tap0響應;

tap0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
       inet6 fe80::cc9f:ddff:fe50:7d9a  prefixlen 128  scopeid 0x20<link>
       inet6 fc00::231  prefixlen 7  scopeid 0x0<global>
       ether 06:ea:8d:0e:66:74  txqueuelen 1000  (Ethernet)
       RX packets 0  bytes 0 (0.0 B)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 0  bytes 0 (0.0 B)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

因此,在我的 Contiki 程式碼中進行此修改後,嘗試讀取 tap0 介面

ret = read(fd, uip_buf, UIP_BUFSIZE);

但是 ret 值是-1。(它在使用 sudo 執行時返回一個 int 值)我想如果我能夠更改 tap0 介面的狀態,RUNNING也許我可以獲得 ret 值,但我不知道該怎麼做。

有誰知道我該怎麼做?

注意:tapdev6.c 修改

void
tapdev_init(void)
{
 printf("INIT TAP DEV!!!!!!!!!!!!!!!!! \n");
 net_fd = open(DEVTAP, O_RDWR);
 if(net_fd == -1) {
   perror("tapdev: tapdev_init: open");
   return;
 }

#ifdef __linux
 {
   memset(&ifr, 0, sizeof(ifr));
   ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
   printf("INIT0 net_fd %d \n", net_fd);
   if (ioctl(/*net_fd*/4, TUNSETIFF, (void *) &ifr) < 0) {
       printf("INIT FAIL \n");
     perror("Unable to init tunnel interface\n");
     //exit(1);
   }
   printf("INIT1 net_fd %d \n", net_fd);
   ioctl(/*net_fd*/4, SIOCGIFHWADDR, &ifr);
   printf("INIT2 net_fd %d \n", net_fd);
 }
 /* Linux (ubuntu) */
char buf[256];
    snprintf(buf, sizeof(buf), "ip link set tap0 up");
    system(buf);
    PRINTF("%s\n", buf);
    snprintf(buf, sizeof(buf), "ip -6 address add fc00::231/7 dev tap0");
    system(buf);
    PRINTF("%s\n", buf);
    snprintf(buf, sizeof(buf), "ip -6 route add fc00::0/7 dev tap0");
    system(buf);
    PRINTF("%s\n", buf);

 /* freebsd */

   //try to set hw address
    // 12:bc:34:76:c9:2f
   ifr.ifr_hwaddr.sa_data[0] = 0x12;
   ifr.ifr_hwaddr.sa_data[1] = 0xbc;
   ifr.ifr_hwaddr.sa_data[2] = 0x34;
   ifr.ifr_hwaddr.sa_data[3] = 0x76;
   ifr.ifr_hwaddr.sa_data[4] = 0xc9;
   ifr.ifr_hwaddr.sa_data[5] = 0x2f;
 printf("Lan device %s\n", ifr.ifr_name);
 printf("LAN HW addr %02X:%02X:%02X:%02X:%02X:%02X\n",
         (unsigned char)ifr.ifr_hwaddr.sa_data[0],
         (unsigned char)ifr.ifr_hwaddr.sa_data[1],
         (unsigned char)ifr.ifr_hwaddr.sa_data[2],
         (unsigned char)ifr.ifr_hwaddr.sa_data[3],
         (unsigned char)ifr.ifr_hwaddr.sa_data[4],
         (unsigned char)ifr.ifr_hwaddr.sa_data[5]);
#endif /* Linux */

 lasttime = 0;

}

-ESUDO

說真的,你應該設置點擊界面的所有者。嘗試以下:

ip tuntap add tap0 mode tap user USER

USER將讀取和寫入通過打開的句柄的使用者在哪裡/dev/net/tun。我懷疑不僅 read 失敗了,而且ioctl(TUNSETIFF), 但你沒有費心檢查返回值。

這是一個簡單的opentap(ifname)函式,它應該打開一個指向 tap 介面的 fd 句柄,前提是執行它的使用者具有正確的權限:

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int opentap(char *ifn)
{
   int fd;
   struct ifreq ifr = { 0 };
   if (snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s", ifn)
           >= sizeof ifr.ifr_name) {
       errno = ENAMETOOLONG; return -1;
   }
   if ((fd = open("/dev/net/tun", O_RDWR)) == -1) return -1;
   ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
   if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
       int e = errno; close(fd); errno = e; return -1;
   }
   return fd;
}

引用自:https://unix.stackexchange.com/questions/499548