0

I'd like to know how I can bind a socket to a specific interface in C.

My @IP is X.Y.Z.3, the gateway is X.Y.Z.1 on eth1 But if I send my packet, it'll be send on the loopback interface.

The strange thing is, if I make my packet with X.Y.Z.9 (for example) as the IP SOURCE (instead of mine), it works.

Any clue?

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> #include <sys/ioctl.h> #include <net/if.h> #include <string.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/time.h> #define PCK_MAX_LEN 1024 #define IP_NAMESERV "172.20.10.1" #define IP_ATTACKER "172.20.10.3" #define PORT_QUERY 5555 pthread_cond_t ans_listen = PTHREAD_COND_INITIALIZER; pthread_cond_t ans_receiv = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *fctThreadSendQuery (void *arg); // Send 1 query to random.example.com void *fctThreadListenResponse (void *arg); // Listen for response to that query int main (void) { pthread_t threadSendQuery; pthread_t threadListenResponse; pthread_create (&threadSendQuery, NULL, fctThreadSendQuery, NULL); pthread_create (&threadListenResponse, NULL, fctThreadListenResponse, NULL); pthread_join (threadListenResponse, NULL); pthread_join (threadSendQuery, NULL); return 0; } void *fctThreadSendQuery(void *arg) { unsigned int nQuery = 1; struct sockaddr_in *sin_attacker, *sin_resolver; sin_attacker = calloc(1, sizeof(struct sockaddr_in)); sin_resolver = calloc(1, sizeof(struct sockaddr_in)); sin_attacker->sin_family = AF_INET; sin_attacker->sin_addr.s_addr = inet_addr(IP_ATTACKER); sin_attacker->sin_port = htons(PORT_QUERY); int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); bind(fd, sin_attacker, sizeof(struct sockaddr_in)); sin_resolver->sin_family = AF_INET; sin_resolver->sin_addr.s_addr = inet_addr(IP_RESOLVER); sin_resolver->sin_port = htons(53); while (1) { // Now, we can build and send the query char *packet = calloc(PCK_MAX_LEN, sizeof(char)); int pck_len = 0; int id = 0; char *target = calloc(16, sizeof(char)); strcpy(target, randomTarget(nQuery-1)); build_packet(IP_SRC, IP_DST, PORT_QUERY, 53, packet, &pck_len, target, NAME_LEN, id, QUERY); // Before sending the packet, we want to be sure that fctThreadListenResponse is listening pthread_mutex_lock (&mutex); puts("SEND: wait for RECV to LISTEN"); pthread_cond_wait (&ans_listen, &mutex); puts("SEND: wait for RECV to LISTEN - OK"); pthread_mutex_unlock(&mutex); sendto (fd, packet, pck_len, 0, sin_attacker, sizeof(struct sockaddr_in)); puts("SEND: PCK SENT"); pthread_mutex_lock (&mutex); puts("SEND: wait for RECV to RECV"); pthread_cond_wait (&ans_receiv, &mutex); puts("SEND: wait for RECV to RECV - OK"); pthread_mutex_unlock(&mutex); nQuery++; free(target); free(packet); } free(sin_resolver); free(sin_attacker); pthread_exit(NULL); } void *fctThreadListenResponse (void *arg) { usleep(100); struct sockaddr_in *sin_attacker, *sin_resolver; sin_attacker = calloc(1, sizeof(struct sockaddr_in)); sin_resolver = calloc(1, sizeof(struct sockaddr_in)); sin_attacker->sin_family = AF_INET; sin_attacker->sin_addr.s_addr = inet_addr(IP_ATTACKER); sin_attacker->sin_port = htons(PORT_QUERY); int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); bind(fd, sin_attacker, sizeof(struct sockaddr_in)); while (1) { char *packet = calloc(PCK_MAX_LEN, sizeof(char)); unsigned int pck_len; pthread_mutex_lock (&mutex); pthread_cond_signal (&ans_listen); puts("RECV: LISTENING"); pthread_mutex_unlock(&mutex); pck_len = recvfrom(fd, packet, PCK_MAX_LEN, 0, NULL, sin_resolver); puts("RECV: PCK RECEIVED"); if (pck_len > 0) { pthread_mutex_lock (&mutex); pthread_cond_signal (&ans_receiv); pthread_mutex_unlock (&mutex); } free(packet); } pthread_exit(NULL); } 
3
  • You do this with the bind() function , of course. You must be sending to yourself it it goes via the loopback interface, and what's wrong with that? Commented Dec 15, 2014 at 17:54
  • I'm not sending it to myself. I'm sending it to the gateway. I tried some stuff I found (SO_BINDTODEVICE, ...) but nothing seemed to work. Commented Dec 15, 2014 at 18:28
  • why raw sockets? If you want to use UDP (as you state), SOCK_DGRAM and IPPROTO_UDP may be more suitable Commented Dec 15, 2014 at 19:19

1 Answer 1

2

I don't know what build_packet does, but the documentation for sendto lists only a few possible prototypes, of which only one has the parameter list you are using:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 

In your call you use:

sendto (fd, packet, pck_len, 0, sin_attacker, sizeof(struct sockaddr_in)); 

Where you have configured sin_attacker (the dest_addr parameter) using IP_ATTACKER, which seems to be your own address. Thus sendto sees a destination address that is hosted on the local system and sends the packet using the loopback adapter.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.