Reputation:
I'm trying to bind my socket to eth0 using SO_BINDTODEVICE
. I am passing eth0 to the variable opt
. My socket name is socketfd
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));
In order to do some debugging, I'm redirecting the value of opt and strlen(opt) to a log file and they get the values correctly.
cat /home/cayman/log.txt
The bind is done on interface eth0
opt length is 4
I also do a verification by capturing packets on eth0 but I don't see the traffic going through eth0. All what is see is other network related traffic as follows:
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
I also had a look on this thread and I made sure that I'm running my code as a super-user. I looked also at the man page of SO_BINDTODEVICE but I am not sure what could be missing. Any suggestions please ?
Upvotes: 0
Views: 1452
Reputation: 596582
Your first fprintf()
statement is wrong. You are not outputting the opt
value to stderr
correctly, and you are not copying opt
into ifr.ifr_name
at all before calling SIOCGIFINDEX
.
Try something more like this instead:
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;
}
See Get the index number of a Linux network interface in C using SIOCGIFINDEX
That being said, you don't need to use SIOCGIFINDEX
before calling SO_BINDTODEVICE
if you are going to bind to an interface name. Just call SO_BINDTODEVICE
by itself:
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;
}
Using SIOCGIFINDEX
does not make sense in this context. What would make sense is if you used SIOCGIFADDR
to retrieve the interface's IP address (see Get the IP address of a network interface in C using SIOCGIFADDR) and then passed that IP to bind()
instead of passing the interface name to SO_BINDTODEVICE
.
Upvotes: 0
Reputation: 48335
You're not checking the return codes for most of the calls you're making. One or more of them may be failing in a way that reveals additional information. You should (always) check the return values for errors.
Edit: I added error handling to your code:
#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));
}
And found the ioctl()
is failing. Then I noticed you're not initializing ifr.ifr_name
. If you copy opt
into ifr.ifr_name
, does your problem go away?
Upvotes: 1