Параметры оповещения маршрутизатора о пакетах IGMPv2

StackOverflow https://stackoverflow.com/questions/4164670

  •  09-10-2019
  •  | 
  •  

Вопрос

Я пытаюсь подделать пакет запроса на членство в IGMPv2 и отправить его через сокет RAW.

В RFC 3376 говорится:

Сообщения IGMP инкапсулируются в датаграммы IPv4 с номером протокола IP 2.Каждое сообщение IGMP, описанное в этом документе, отправляется со временем жизни IP, равным 1, приоритетом IP межсетевого управления (например, типом службы 0xc0) и содержит опцию оповещения IP-маршрутизатора [RFC-2113] в своем IP-заголовке.

Поэтому флаг IP_ROUTER_ALERT должен быть установлен.

Я пытаюсь подделать строгую необходимость пакета (например.только заголовок и полезная нагрузка IGMP), поэтому я использую Setsockopt для редактирования параметров IP.

некоторые полезные переменные:

#define C_IP_MULTICAST_TTL 1
#define C_IP_ROUTER_ALERT 1

int sockfd = 0;
int ecsockopt = 0;
int bytes_num = 0;

int ip_multicast_ttl = C_IP_MULTICAST_TTL;
int ip_router_alert = C_IP_ROUTER_ALERT;

Вот как я открываю сокет RAW:

sock_domain = AF_INET;
sock_type = SOCK_RAW;
sock_proto = IPPROTO_IGMP;

if ((ecsockopt = socket(sock_domain,sock_type,sock_proto)) < 0) {
  printf("Error %d: Can't open socket.\n", errno);
  return 1;
} else {
  printf("** Socket opened.\n");
}
sockfd = ecsockopt;

Затем я установил опцию TTL и Router Alert:

// Set the sent packets TTL
if((ecsockopt = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ip_multicast_ttl, sizeof(ip_multicast_ttl))) < 0) {
  printf("Error %d: Can't set TTL.\n", ecsockopt);
  return 1;
} else {
  printf("** TTL set.\n");
}

// Set the Router Alert
if((ecsockopt = setsockopt(sockfd, IPPROTO_IP, IP_ROUTER_ALERT, &ip_router_alert, sizeof(ip_router_alert))) < 0) {
  printf("Error %d: Can't set Router Alert.\n", ecsockopt);
  return 1;
} else {
  printf("** Router Alert set.\n");
}

Setsockopt IP_ROUTER_ALERT возвращает 0.После подделки пакета я отправляю его с помощью sendto следующим образом:

// Send the packet
if((bytes_num = sendto(sockfd, packet, packet_size, 0, (struct sockaddr*) &mgroup1_addr, sizeof(mgroup1_addr))) < 0) {
  printf("Error %d: Can't send Membership report message.\n", bytes_num);
  return 1;
} else {
  printf("** Membership report message sent. (bytes=%d)\n",bytes_num);
}

Пакет отправлен, но опция IP_ROUTER_ALERT (проверена с помощью Wireshark) отсутствует.Я делаю что-то неправильно?есть ли другие способы установить параметр IP_ROUTER_ALERT?

Заранее спасибо.

Это было полезно?

Решение

Наконец я узнал, что IP_ROUTER_ALERT должен быть установлен ядром Linux.Запросы на членство в IGMP отправляются после IP_ADD_MEMBERSHIP завершено, и ядро ​​берет на себя ответственность за настройку IP_ROUTER_ALERT флаг.

Другие советы

Я не знаю, почему ваш код не работает (он выглядит хорошо для меня), но я могу предложить обходной путь: опустите еще один слой вниз на вашу сырье и построить рамы Ethernet. Вы также можете взглянуть на Libnet., который обрабатывает строительные пакеты, как это для вас.

То документация состояния:

Передайте все перенаправленные пакеты с помощью параметра Alert Alert Alert IP-маршрутизатора. Действителен только для сырьевых сокетов. Это полезно, например, для пользовательского пространства RSVP Daemons. Постукрытые пакеты не пересылаются ядром, это ответственность пользователей, чтобы отправить их снова. Привязка сокета игнорируется, такие пакеты фильтруются только по протоколу. Ожидает целочисленного флага.

Это звучит, как если опция имеет значение только тогда, когда прием Пакеты на розетке, а не при отправке их. Если вы отправляете сырые пакеты, не можете ли вы просто Установите необходимый вариант в заголовке IP сам?

В качестве ссылки я бы порекомендовал один из множества программ IGMP программ там. Одним из примеров igmpproxy: https://github.com/vitoni/igmpproxy/blob/logging/src/igmp.c#l54.

/*
 * Open and initialize the igmp socket, and fill in the non-changing
 * IP header fields in the output packet buffer.
 */
void initIgmp(void) {
    struct ip *ip;

    recv_buf = malloc(RECV_BUF_SIZE);
    send_buf = malloc(RECV_BUF_SIZE);

    k_hdr_include(true);    /* include IP header when sending */
    k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering        */
    k_set_ttl(1);       /* restrict multicasts to one hop */
    k_set_loop(false);      /* disable multicast loopback     */

    ip         = (struct ip *)send_buf;
    memset(ip, 0, sizeof(struct ip));
    /*
     * Fields zeroed that aren't filled in later:
     * - IP ID (let the kernel fill it in)
     * - Offset (we don't send fragments)
     * - Checksum (let the kernel fill it in)
     */
    ip->ip_v   = IPVERSION;
    ip->ip_hl  = (sizeof(struct ip) + 4) >> 2; /* +4 for Router Alert option */
    ip->ip_tos = 0xc0;      /* Internet Control */
    ip->ip_ttl = MAXTTL;    /* applies to unicasts only */
    ip->ip_p   = IPPROTO_IGMP;

    allhosts_group   = htonl(INADDR_ALLHOSTS_GROUP);
    allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
    alligmp3_group   = htonl(INADDR_ALLIGMPV3_GROUP);
}

а также https://github.com/vitoni/igmpproxy/blob/logging/src/igmp.c#l271.

/*
 * Construct an IGMP message in the output packet buffer.  The caller may
 * have already placed data in that buffer, of length 'datalen'.
 */
static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
    struct ip *ip;
    struct igmp *igmp;
    extern int curttl;

    ip                      = (struct ip *)send_buf;
    ip->ip_src.s_addr       = src;
    ip->ip_dst.s_addr       = dst;
    ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen);

    if (IN_MULTICAST(ntohl(dst))) {
        ip->ip_ttl = curttl;
    } else {
        ip->ip_ttl = MAXTTL;
    }

    /* Add Router Alert option */
    ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[0] = IPOPT_RA;
    ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[1] = 0x04;
    ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00;
    ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00;

    igmp                    = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN);
    igmp->igmp_type         = type;
    igmp->igmp_code         = code;
    igmp->igmp_group.s_addr = group;
    igmp->igmp_cksum        = 0;
    igmp->igmp_cksum        = inetChksum((unsigned short *)igmp,
                                         IP_HEADER_RAOPT_LEN + datalen);

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top