Я пытаюсь написать программу туннелирования на C, которая будет принимать UDP-пакеты из интерфейса TUNTAP и отправлять их в последовательный интерфейс.Интерфейс TUNTAP в C (Linux): Не удается захватить UDP-пакеты, отправленные на TUNTAP с помощью sendto()
Что я делаю, это выделить интерфейс из клона устройства/Dev/нетто/тун, включите его и дайте ему IP-адрес:
int tun_setup(char *dev, int flags) {
struct sockaddr_in my_addr;
struct ifreq ifr;
int fd, err;
string clonedev = "/dev/net/tun";
// Open clone device file descriptor
if((fd = open(clonedev.c_str() , O_RDWR)) < 0) {
perror("Opening /dev/net/tun");
return fd;
}
// Initialise interface parameters structure
memset(&ifr, 0, sizeof(ifr));
// Set up flags
ifr.ifr_flags = flags;
// Set up interface name
if (*dev) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
// Put interface in TUN mode
if((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
perror("ioctl(TUNSETIFF)");
close(fd);
return err;
}
strcpy(dev, ifr.ifr_name);
// Create a socket
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
// Get interface flags
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
perror("cannot get interface flags");
exit(1);
}
// Turn on interface
ifr.ifr_flags |= IFF_UP;
if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
fprintf(stderr, "ifup: failed ");
perror(ifr.ifr_name);
exit(1);
}
// Set interface address
bzero((char *) &my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(inet_network("192.168.2.1"));
memcpy(&ifr.ifr_addr, &my_addr, sizeof(struct sockaddr));
if (ioctl(s, SIOCSIFADDR, &ifr) < 0) {
fprintf(stderr, "Cannot set IP address. ");
perror(ifr.ifr_name);
exit(1);
}
// Return interface file descriptor
return fd;
}
Затем я создаю поток, который будет опрашивать() на файловый дескриптор созданного интерфейса и читать() + некоторые другие вещи, когда происходит событие.
void* tun_readThreadProc (void* param) {
struct pollfd fds[1];
int nread;
unsigned char buffer[BUFFERSIZE];
fds[0].fd = tun_fd;
fds[0].events = POLLIN;
printf("%s : Entered. tun_fd = %d \n",__FUNCTION__,tun_fd);
for(;;)
{
printf("%s : Entered loop\n",__FUNCTION__);
if((poll(fds, 1, -1)) == -1)
{
perror("poll");
exit(1);
}
printf("%s : Poll sensed something\n",__FUNCTION__);
if((nread = read(tun_fd, buffer, BUFFERSIZE)) < 0)
{
perror("read");
close(tun_fd);
exit(1);
}
printf("%s : Read something : %d bytes\n",__FUNCTION__,nread);
}
return 0;
}
В другой части программы я связываю сокет UDP с IP-адресом этого интерфейса TUNTAP.
void socketInit(void)
{
int on = 1;
struct sockaddr_in my_addr;
unsigned short DefaultPort = 47808;
// Create a socket
if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
// Bind to it
bzero((char *) &my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(inet_network("192.168.2.1"));
my_addr.sin_port = htons(DefaultPort);
if ((bind(s, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0)) {
perror("bind");
}
// Allow it to broadcast
if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) {
perror("setsockopt");
}
}
В другой функции я использую sendto() для отправки пакетов с этим сокетом. Я должен захватить эти пакеты потоком poll() + read(), а затем отправить их на последовательный порт, но poll() никогда не захватывает события на интерфейсе TUNTAP.
Я могу свистеть через этот интерфейс, используя пинг -I tun0 [некоторые назначения] (tun0 = имя интерфейса TUNTAP)
Но если я использую пинг -I 192.168.2.1 [некоторые назначения] (192.168.2.1 = адрес интерфейса TUNTAP) он проходит через интерфейс по умолчанию (eth0, физический сетевой адаптер).
Я смог проверить это с помощью Wireshark.
Это наиболее вероятно, проблема конфигурации маршрута ф ...
Я был бы очень рад, если кто-нибудь может мне помочь.
Оправа код создания здесь: http://pastebin.com/raw.php?i=JZLKkuxS –
Что вы имеете в виду UDP-пакетов «на этом интерфейсе»? Вы имеете в виду направления, направляемые через этот интерфейс? –
@DavidSchwartz Да точно –