2016-12-08 18 views
0

Я пытаюсь связать мой сокет с eth0 с помощью SO_BINDTODEVICE. Я передаю eth0 переменной opt. Мое имя сокета socketfdНет привязки трафика к интерфейсу с использованием SO_BINDTODEVICE

sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(sockfd < 0) { 
     perror("socket(): error "); 
     return 0; 
    } 
    struct ifreq ifr; 

    memset(&ifr, 0, sizeof(struct ifreq)); 
    fprintf(stderr,ifr.ifr_name, sizeof(ifr.ifr_name), opt); 
    ioctl(sockfd, SIOCGIFINDEX, &ifr); 
    setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, strlen(opt)); 
    fprintf(stderr, "The bind is done on interface %s \n", opt); 
    fprintf(stderr, "opt length is %zu \n", strlen(opt)); 

Для того, чтобы сделать некоторые отладки, я перенаправлять значение опц и STRLEN (OPT) в лог-файл, и они получают значения правильно.

кошка /home/cayman/log.txt
привязка осуществляется по интерфейсу eth0
неавтоматического длина 4

Я также проверку путем захвата пакетов на eth0, но я не Не вижу трафика, проходящего через eth0. Все, что видит другая сеть трафик, связанный следующим образом:

tshark -i eth0 
    1 0.000000 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00 Cost = 0 Port = 0x8009 
    2 0.326720 192.168.78.1 -> 224.0.0.13 PIMv2 70 Hello 
    3 1.030538 Cisco_51:fd:09 -> Cisco_51:fd:09 LOOP 62 Reply 
    4 2.004544 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00 Cost = 0 Port = 0x8009 
    5 3.254223 192.168.78.1 -> 224.0.0.10 EIGRP 76 Hello 
    6 4.010168 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00 Cost = 0 Port = 0x8009 
    7 6.014839 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00 Cost = 0 Port = 0x8009 
    8 7.896252 192.168.78.1 -> 224.0.0.10 EIGRP 76 Hello 
    9 8.023003 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00 Cost = 0 Port = 0x8009 

Я также имел взгляд на this thread, и я убедился, что я бег моего кода как супер-пользователь. Я посмотрел также на man page SO_BINDTODEVICE, но я не уверен, чего не хватает. Любые предложения, пожалуйста?

+0

Мне любопытно: почему вы привязываете свою розетку к eth0? –

+0

Я реализую функцию перенаправления UDP. Согласно вводу пользователя в переднем конце (eth0/eth1), back-end соответствующим образом привязывает сокет и сделает перенаправление трафика –

ответ

0

Вы не проверяете коды возврата для большинства вызовов, которые вы делаете. Один или несколько из них могут провалиться таким образом, чтобы выявить дополнительную информацию. Вы должны (всегда) проверять возвращаемые значения для ошибок.

Edit: я добавил обработку в код ошибки:

#include <sys/socket.h> 
#include <stdio.h> 
#include <sys/ioctl.h> 
#include <net/if.h> 
#include <string.h> 

int main() { 
    const char* opt = "wlp4s0"; 
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(sockfd < 0) { 
    perror("socket(): error "); 
    return 1; 
    } 
    struct ifreq ifr; 

    memset(&ifr, 0, sizeof(struct ifreq)); 
    fprintf(stderr,ifr.ifr_name, sizeof(ifr.ifr_name), opt); 
    if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) { 
    perror("ioctl(): error "); 
    return 2; 
    } 
    if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, strlen(opt)) > 0) { 
    perror("setsockopt(): error "); 
    return 3; 
    } 
    fprintf(stderr, "The bind is done on interface %s \n", opt); 
    fprintf(stderr, "opt length is %zu \n", strlen(opt)); 
} 

И нашел ioctl() не удается. Тогда я заметил, что вы не инициализируете ifr.ifr_name. Если вы скопируете opt в ifr.ifr_name, ваша проблема исчезнет?

+0

Спасибо за помощь. Да, если.ifr_name не инициализировалось. Это решило проблему! –

0

Ваше первое заявление fprintf() неверно. Вы не выводите значение opt в stderr правильно, и вы не копируете opt в ifr.ifr_name не ранее, чем звоните SIOCGIFINDEX.

Попробуйте что-то больше, как это вместо:

if (strlen(opt) >= sizeof(ifr.ifr_name)) { 
    fprintf(stderr, "%s", "interface name is too long \n"); 
    return 0; 
} 

... 

struct ifreq ifr; 
memset(&ifr, 0, sizeof(struct ifreq)); 
strncpy(ifr.ifr_name, opt, sizeof(ifr.ifr_name)); 

if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) { 
    perror("ioctl(): error "); 
    close(sockfd); 
    return 0; 
} 

См Get the index number of a Linux network interface in C using SIOCGIFINDEX

Это, как говорится, вам не нужно использовать SIOCGIFINDEX перед вызовом SO_BINDTODEVICE, если вы собираетесь связать с именем интерфейса. Просто позвоните SO_BINDTODEVICE сам по себе:

sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
if (sockfd < 0) { 
    perror("socket(): error "); 
    return 0; 
} 

if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, strlen(opt)) < 0) { 
    perror("setsockopt(): error "); 
    close(sockfd); 
    return 0; 
} 

Использование SIOCGIFINDEX не имеет смысла в этом контексте. Было бы полезно, если вы использовали SIOCGIFADDR для получения IP-адреса интерфейса (см. Get the IP address of a network interface in C using SIOCGIFADDR), а затем передали этот IP-адрес bind() вместо передачи имени интерфейса SO_BINDTODEVICE.