I'd like to know how I can bind a socket to a specific interface in C.
My @IP is XYZ3, the gateway is XYZ1 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 XYZ9 (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);
}
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.