I am working in an application embedded in a device running Linux and BusyBox. The hardware has 2 communication interfaces: Wi-Fi and 3G.
In each connection, the application must try to connect using wi-fi first and, if it fails, the application tries again using 3G.
I am forcing the connection to use the selected interface binding it like this:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <net/if.h>
static void resolveDns(const char *hostname, struct addrinfo **destInfo)
{
int err;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((err = getaddrinfo(hostname, "80", &hints, destInfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(err));
exit(EXIT_FAILURE);
}
struct sockaddr_in *addr = (struct sockaddr_in *)((*destInfo)->ai_addr);
printf("Destination IP: %s\n", inet_ntoa(addr->sin_addr));
}
static void getComInterface(const char *iface, struct ifreq *ifr)
{
ifr->ifr_addr.sa_family = AF_INET;
strcpy(ifr->ifr_name, iface);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
int err = ioctl(sock, SIOCGIFADDR, ifr);
close(sock);
if (err) {
fprintf(stderr, "ioctl error: %d\n", err);
exit(EXIT_FAILURE);
}
printf("Interface IP: %s\n", inet_ntoa(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr));
}
int main()
{
int err;
struct ifreq ifr;
getComInterface("wlan0", &ifr);
struct addrinfo *destInfo;
resolveDns("www.google.com", &destInfo);
int s = socket(AF_INET, SOCK_STREAM, 0);
err = bind(s, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
if (err) {
fprintf(stderr, "bind error = %d, %d\n", err, errno);
exit(EXIT_FAILURE);
}
err = connect(s, destInfo->ai_addr, destInfo->ai_addrlen);
if (err) {
fprintf(stderr, "connect error = %d, %d \n", err, errno);
exit(EXIT_FAILURE);
}
printf("Ok!\n");
freeaddrinfo(destInfo);
close(s);
return EXIT_SUCCESS;
}
But this doesn't solve the problem in DNS lookup.
Is there a way to force getaddrinfo to use the selected interface? Or, even better, is there a way to force all connections to use the selected interface without disconnecting the other?
P.S.: If you know how to do this in more complex SO, like Ubuntu for instance, please share your solution.
Thanks