简体   繁体   中英

Bind a socket to a specific interface with UDP? - C

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM