Question

Je suis en train de forger un paquet de demande d'adhésion IGMPv2 et l'envoyer sur une socket RAW.

Les états RFC 3376:

  

messages IGMP sont encapsulées dans des datagrammes IPv4, avec un numéro de protocole IP 2. Chaque message IGMP décrit dans ce document est envoyé avec un Time-to-Live IP 1, IP Primauté de Internetwork contrôle (par exemple, le type de service 0xC0), et comporte une option d'alerte du routeur IP header [RFC-2113] dans son IP

Alors le drapeau IP_ROUTER_ALERT doit être réglé.

Je suis en train de forger le strict nécessaire du paquet (par exemple uniquement l'en-tête et la charge utile IGMP), donc je suis en utilisant le setsockopt pour modifier les options IP.

certaines variables utiles:

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

Voici comment j'ouvrir la prise 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;

Alors je le TTL et l'option d'alerte du routeur:

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

Le setsockopt de IP_ROUTER_ALERT retourne 0. Après forgeant le paquet, je l'envoie avec sendto ainsi:

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

Le paquet est envoyé, mais l'option IP_ROUTER_ALERT (vérifié avec Wireshark) est manquante. Est-ce que je fais quelque chose de mal? est-il d'autres méthodes pour définir l'option IP_ROUTER_ALERT?

Merci à l'avance.

Était-ce utile?

La solution

Enfin, je l'ai découvert que le IP_ROUTER_ALERT doit être réglé par le noyau Linux. les demandes d'adhésion IGMP sont envoyés après une IP_ADD_MEMBERSHIP est fait et le noyau prend en charge la définition du drapeau de IP_ROUTER_ALERT.

Autres conseils

Je ne sais pas pourquoi votre code ne fonctionne pas (il semble bien pour moi), mais je peux proposer une solution de contournement: Déposez une couche supplémentaire sur vos sockets raw et construire des trames Ethernet. Vous pouvez également jeter un oeil à Libnet , qui gère la construction des paquets comme celui-ci pour vous.

Le documentation indique :

  

passer tous à être des paquets transmis avec   l'option Routeur IP Alerte configurée avec cette   prise. Valable uniquement sur les sockets raw.   Ceci est utile, par exemple, pour l'utilisateur   RSVP daemons de l'espace. Les paquets taraudés   ne sont pas transmis par le noyau, il est   la responsabilité des utilisateurs de les envoyer   encore dehors. Socket fixation est ignoré,   de tels paquets ne sont filtrés par   protocole. Prévoit un indicateur de nombre entier.

Cela semble comme si l'option compte que lorsque recevoir paquets sur la prise, et non pas lors de leur envoi. Si vous envoyez des paquets bruts, ne pouvez pas vous venez définir l'option requise dans l'en-tête IP vous?

Comme référence, je recommande l'un des nombreux programmes IGMP au courant là-bas. Un exemple est 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);
}

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

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top