Linux

如何在C中設置TUN介面的IP地址和Peer IP地址

  • September 12, 2022

我是一名在 CMU 研究月球車的學生,需要在月球車上的兩個設備之間使用 TUN 介面通信。我可以創建一個 TUN 介面,但無法在 C 中分配其 IP 地址。

以下是製作 TUN 設備後的目前狀態:

41: tun11: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
link/none

這是所需的狀態:

14: tun71: <POINTOPOINT,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 500
link/none 
inet 192.168.0.29 peer 192.168.0.23/32 scope global tun71
  valid_lft forever preferred_lft forever

我嘗試為 ifreq 設置 dstaddr 無濟於事。

int fd;
int dst_fd;
struct ifreq ifr;
struct sockaddr_in* addr;
struct sockaddr_in* dst_addr;

fd = socket(AF_INET, SOCK_DGRAM, 0);
dst_fd = socket(AF_INET, SOCK_DGRAM, 0);

ifr.ifr_addr.sa_family = AF_INET;

memcpy(ifr.ifr_name, "tun11", IFNAMSIZ - 1);
addr = (struct sockaddr_in*)&ifr.ifr_addr;
dst_addr = (struct sockaddr_in*)&ifr.ifr_dstaddr;

inet_pton(AF_INET, ip_address, &addr->sin_addr);
inet_pton(AF_INET, ip_address, &dst_addr->sin_addr);
int err;
if ( (err = ioctl(fd, SIOCSIFADDR, &ifr)) == -1 ) {
   perror("ioctl SIOCSIFFLAGS");close(fd);exit(1);
}

我不知道還能做什麼。我在給它一個命令後嘗試調試 IP,但我無法弄清楚。

如果您還沒有,請創建一個測試 tun

# ip tuntap add mode tun dev tun0
# ip address show dev tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
   link/none

這看起來與問題中的內容非常相似。現在看看我們需要什麼程式碼……

// uptun.c - set an IP address and UP a tun
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>             /* offsetof */
#include <net/if.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <asm/types.h>
#include <linux/if_ether.h>
#endif

// TWEAK
#define IFNAME "tun0"
#define HOST "192.168.0.29"

#define ifreq_offsetof(x) offsetof(struct ifreq, x)

int main(int argc, char **argv) {
   struct ifreq ifr;
   struct sockaddr_in sai;
   int sockfd; /* socket fd we use to manipulate stuff with */
   int selector;
   unsigned char mask;

   char *p;

   /* Create a channel to the NET kernel. */
   sockfd = socket(AF_INET, SOCK_DGRAM, 0);

   /* get interface name */
   strncpy(ifr.ifr_name, IFNAME, IFNAMSIZ);

   memset(&sai, 0, sizeof(struct sockaddr));
   sai.sin_family = AF_INET;
   sai.sin_port   = 0;

   sai.sin_addr.s_addr = inet_addr(HOST);

   p = (char *) &sai;
   memcpy((((char *) &ifr + ifreq_offsetof(ifr_addr))), p,
          sizeof(struct sockaddr));

   ioctl(sockfd, SIOCSIFADDR, &ifr);
   ioctl(sockfd, SIOCGIFFLAGS, &ifr);

   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
   // ifr.ifr_flags &= ~selector;  // unset something

   ioctl(sockfd, SIOCSIFFLAGS, &ifr);
   close(sockfd);
   return 0;
}

這給了我們:

# make uptun
cc     uptun.c   -o uptun
# ./uptun
# ip address show dev tun0
5: tun0: <NO-CARRIER,POINTOPOINT,MULTICAST,NOARP,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 500
   link/none
   inet 192.168.0.29/32 scope global tun0
      valid_lft forever preferred_lft forever

僅缺少對等地址。一些 altagoobingleduckgoing 顯示 tunSIOCSIFDSTADDR除了 SIOCSIFADDR. 讓我們把它塞進劇本之後 SIOCGIFFLAGS

       // KLUGE copypasta in the destination address
       sai.sin_addr.s_addr = inet_addr("192.168.0.23");
       p = (char *) &sai;
       memcpy((((char *) &ifr + ifreq_offsetof(ifr_addr))), p,
              sizeof(struct sockaddr));
       ioctl(sockfd, SIOCSIFDSTADDR, &ifr);

在編譯並重新執行之後,uptun我們有:

# ip address show dev tun0
5: tun0: <NO-CARRIER,POINTOPOINT,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 500
   link/none
   inet 192.168.0.29 peer 192.168.0.23/32 scope global tun0
      valid_lft forever preferred_lft forever

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