Я пытаюсь создать несколько устройств TUN для туннелирования трафика нескольких устройств c через общий физический интерфейс.
У меня есть такая схема: Сокет 1 отправляет трафик c через tun1 с IP-адресом назначения 1.1.1.2, а Socket 2 делает то же самое на другом интерфейсе. У меня есть программа, работающая между обоими устройствами TUN и физическим интерфейсом (eth0), которая инкапсулирует IP-пакеты от устройств TUN в пакеты UDP, а затем отправляет их на сервер. Сервер распаковывает полученные пакеты и отвечает обоим клиентам эхо-пакетами (также инкапсулированными). Когда эти пакеты поступают в eth0, другая программа считывает пакеты и пересылает их на свое устройство TUN. После этого обе программы, работающие за сокетами, блокируются функцией recv (), ожидающей ответа сервера на устройствах tunX. Однако, похоже, что ядро отбрасывает эти пакеты на устройствах TUN, даже когда они правильно сформированы.
Я попытался изменить маску сети обоих интерфейсов на 255.255.255.0, и тогда только один из сокетов получает правильно ответ.
Все это программное обеспечение было написано в C.
Эта функция для создания нового устройства TUN:
#define MTU_SIZE 1500
#define SUBNET_MASK 0xFFFFFFFF
int open_tun_iface(char * name, uint8_t * ip)
{
int sock;
struct ifreq ifr_tun;
struct sockaddr_in * sa;
int tunfd = tun_init(name, &ifr_tun, IFF_TUN | IFF_NO_PI);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Open socket");
tun_close(tunfd);
return -1;
}
/* Set tun IP */
if (set_ip(&ifr_tun, sock, ip) < 0) {
tun_close(tunfd);
return -1;
}
sa = (struct sockaddr_in *)&ifr_tun.ifr_netmask;
memset(sa,0,sizeof(*sa));
sa->sin_family = AF_INET;
sa->sin_addr.s_addr = htonl(SUBNET_MASK);
/* Set the mask */
if (ioctl(sock, SIOCSIFNETMASK, &ifr_tun) < 0)
{
perror("SIOCSIFNETMASK");
tun_close(tunfd);
close(sock);
return -1;
}
/* Read flags */
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set Iface up and flags */
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set MTU size */
ifr_tun.ifr_mtu = MTU_SIZE;
if (ioctl(sock, SIOCSIFMTU, &ifr_tun) < 0) {
perror("SIOCSIFMTU");
tun_close(tunfd);
close(sock);
return -1;
}
close(sock);
return tunfd;
}
Функция, которая читает пакеты из eth0 и перенаправляет их на правильный интерфейс TUN:
void * downlink_distributor(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in spgw_addr;
int sockfd;
int sockaddr_len = sizeof(spgw_addr);
int len, packet_len, teid;
eNB * enb = (eNB *) args;
sockfd = get_spgw_socket(enb);
while(1)
{
/* Read packets from the server */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &spgw_addr, (socklen_t *)&sockaddr_len);
if(len < 0)
{
perror("recv downlink_distributor");
return NULL;
}
/* Get the TEID that identifies the TUN device */
teid = analyze_gtp_header(buffer, &packet_len);
if(teid > -1)
{
/* Write the packet in the TUN device associated with the packet TEID */
tun_write(get_tun_device(tun_descriptors[teid % MAX_TUN_DESCRIPTORS]), buffer + 8, packet_len);
}
}
return NULL;
}
Наконец, эта функция работает на обоих сокетах и генерирует трафик c:
void * _generate_udp_traffic(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in dest_addr, spgw_addr;
fd_set fds;
struct timeval timeout;
int retval;
timeout.tv_sec = 0;
timeout.tv_usec = 1;
int tunfd;
char msg[] = "Uplink traffic";
int sockfd;
int len;
int sockaddr_len = sizeof(dest_addr);
udp_generator gen;
/* Copy args */
memcpy(&gen, args, sizeof(udp_generator));
free(args);
/* Get TUN device */
tunfd = get_tun_device(gen.ue);
/* Get UE data socket (TUN socket) */
sockfd = get_data_plane_socket(gen.ue);
/* Configure destiny address */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(gen.port_dest);
memcpy((void*) &dest_addr.sin_addr.s_addr, gen.dest_ip, sizeof(struct in_addr));
/* Configure SPGW address */
memset(&spgw_addr, 0, sizeof(spgw_addr));
spgw_addr.sin_family = AF_INET;
spgw_addr.sin_port = htons(S1_U_PORT);
memcpy((void*) &spgw_addr.sin_addr.s_addr, get_spgw_ip(gen.ue), sizeof(struct in_addr));
while(1)
{
sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *) &dest_addr, sizeof(dest_addr));
while(1)
{
FD_ZERO(&fds);
FD_SET(tunfd, &fds);
retval = select(tunfd+1, &fds, 0, 0, &timeout);
if (retval == -1){
perror("select()");
}
else if (retval){
/* Reuse of the buffer with enough space for the GTP header */
len = tun_read(tunfd, buffer+8, BUFFER_DATA_LEN); /* We call read to clean the buffer from external traffic */
/* Detect IPv4 packets*/
if((buffer[8] & 0xF0) == 0x40)
{
generate_gtp_header(buffer, gen.ue, len);
break;
}
}
}
/* Protect the access to the eNB socket with a lock*/
pthread_mutex_lock(&lock);
/* Send tho the SPGW */
sendto(get_spgw_socket(gen.enb), buffer, len+8, 0, (const struct sockaddr *) &spgw_addr, sizeof(spgw_addr));
/* Unlock the mutex */
pthread_mutex_unlock(&lock);
/* Receive server answer listening on the TUN device */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &dest_addr, (socklen_t *)&sockaddr_len);
printf("UE %d has received: %s\n", get_ue_id(gen.ue), buffer);
/* Sleep 5 seconds */
sleep(5);
}
return NULL;
}
Если маска сети составляет 32, обе программы, генерирующие клиентский трафик c, блокируются функцией recvfrom () внутри функции _generate_udp_traffi c. Если я установлю обе маски сети на 24, только один из них получит ответ от сервера, а другой застрянет на recvfrom.
Как настроить оба устройства TUN для правильной работы обоих подключенных сокетов?
ОБНОВЛЕНИЕ : Я думаю, что моя проблема - это проблема таблицы маршрутизации ядра. Если я использую только один сокет, я получаю только трафик c с сетевой маской <= 30. С сетевой маской 32, я вижу, что ответ сервера вводится правильно на интерфейсе TUN, но каким-то образом сокет, заблокированный в recv () ничего не получает. </p>