Pregunta

Estoy tratando de forjar un paquete de solicitud de miembro IGMPv2 y enviarlo en un socket RAW.

Los RFC 3376 estados:

mensajes

IGMP se encapsulan en datagramas IPv4, con un número de protocolo IP de 2. mensaje cada IGMP se describe en este documento se envía con un Time-to-live IP de 1, Precedencia IP de control Internetwork (por ejemplo, tipo de servicio 0xC0), y lleva una opción IP Alerta Router [RFC-2113] en su IP de cabecera

Así que la bandera IP_ROUTER_ALERT debe ser conjunto.

Estoy tratando de forjar el estrictamente necesario del paquete (por ejemplo, sólo el encabezado y la carga útil IGMP), por lo que estoy usando el setsockopt para editar las opciones de IP.

algunas variables útiles:

#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;

Así es como abro el conector directo:

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;

Entonces establece el TTL y la opción 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");
}

El setsockopt de IP_ROUTER_ALERT devuelve 0. Después de forjar el paquete, i enviarlo con sendto de esta manera:

// 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);
}

El paquete es enviado, pero la opción IP_ROUTER_ALERT (comprobado con wireshark) no se encuentra. ¿Estoy haciendo algo mal? ¿hay algunos otros métodos para establecer la opción IP_ROUTER_ALERT?

Gracias de antemano.

¿Fue útil?

Solución

Finalmente he descubierto que el IP_ROUTER_ALERT tiene que ser establecido por el núcleo Linux. solicitudes de pertenencia IGMP se envían después de un IP_ADD_MEMBERSHIP se hace y el kernel se encarga de establecer el indicador IP_ROUTER_ALERT.

Otros consejos

No sé por qué el código no está funcionando (se ve bien para mí), pero puedo sugerir una solución alternativa: Gota una capa más abajo en sus marcos de socket Ethernet y acumulación primas. También es posible que desee echar un vistazo a Libnet , que se ocupa de la construcción de paquetes como esto para usted.

El documentación estados:

Pass todos a-ser enviado paquetes con la opción IP Router Alert configurado para esta enchufe. Sólo es válido para los conectores directos. Esto es útil, por ejemplo, para el usuario demonios espacio de RSVP. Los paquetes roscados No se reenvían por el núcleo, es responsabilidad de los usuarios para enviarlos Fuera denuevo. la unión se ignora zócalo, tales paquetes sólo son filtrados por protocolo. Espera una bandera de número entero.

Esto suena como si la opción sólo importa cuando recibir paquetes en el zócalo, no cuando enviarlos. Si va a enviar paquetes crudos, no puedes simplemente establecer la opción deseada en la cabecera IP a sí mismo?

Como referencia recomendaría uno de los muchos programas conscientes de IGMP por ahí. Un ejemplo es 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);
}

y 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);

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top