Параметры оповещения маршрутизатора для пакетов IGMPv2 - PullRequest
1 голос
/ 12 ноября 2010

Я пытаюсь подделать пакет запроса на членство 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?

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

Ответы [ 4 ]

2 голосов
/ 29 декабря 2010

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

1 голос
/ 12 ноября 2010

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

0 голосов
/ 21 сентября 2016

В качестве ссылки я бы порекомендовал одну из множества программ, поддерживающих 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);

}
0 голосов
/ 12 ноября 2010

В документации говорится:

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

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

...