Frage

Ich versuche, ein IGMPv2 Membership-Request-Paket zu schmieden und es auf einem RAW-Socket senden.

Die RFC 3376 heißt es:

IGMP-Nachrichten werden in IPv4-Datagrammen gekapselt, mit einer IP-Protokollnummer von 2. Jeden IGMP-Nachricht in diesem Dokument beschrieben wird mit einer IP-Time-to-Live gesendet von 1, IP-Präzedenz von Internetwork Control (zB Type of Service 0xc0) und führt eine IP-Router Alert Option [RFC-2113] in seinem IP-Header

So ist der IP_ROUTER_ALERT-Flag gesetzt sein muss.

Ich versuche, die strenge notwendig des Pakets zu fälschen (z nur die IGMP-Header und Payload), also bin ich die setsockopt zu bearbeiten, um die IP-Optionen.

einige nützliche Variablen:

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

Hier ist, wie ich die RAW-Socket öffnen:

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;

Dann stelle ich die TTL und Router Alert Option:

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

Die setsockopt von IP_ROUTER_ALERT 0 zurück, nachdem das Paket Schmieden, ich sende es mit sendto auf diese Weise:

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

Das Paket wird gesendet, aber die IP_ROUTER_ALERT Option (mit wireshark geprüft) fehlt. Mache ich etwas falsch? gibt es einige andere Methoden, um die IP_ROUTER_ALERT Option setzen?

Vielen Dank im Voraus.

War es hilfreich?

Lösung

Schließlich habe ich herausgefunden, dass der IP_ROUTER_ALERT vom Linux-Kernel gesetzt werden muss. IGMP Mitgliedschaftsanfragen gesendet werden, nachdem ein IP_ADD_MEMBERSHIP getan wird und die Kernel übernimmt die IP_ROUTER_ALERT Flagge zu setzen.

Andere Tipps

Ich weiß nicht, warum Ihr Code nicht funktioniert (es sieht für mich in Ordnung), aber ich kann eine Abhilfe vorschlagen: Tropfen eine weitere Schicht nach unten auf dem Raw-Socket und Build-Ethernet-Frames. Sie können auch einen Blick nehmen unter Libnet , die Griffe bauen Pakete wie dies für Sie.

Die Dokumentation heißt es:

Pass alle zu weitergeleitet werden Pakete mit die IP-Router Alert Option im Set Steckdose. Nur gültig für Raw-Sockets. Dies ist nützlich, zum Beispiel für Benutzer Raum RSVP-Daemons. Die Gewinde Pakete werden nicht vom Kernel weitergeleitet, es ist die Verantwortung Benutzer sie senden nochmal raus. Socket-Bindung wird ignoriert, Solche Pakete werden nur gefiltert durch Protokoll. Erwartet eine ganze Zahl Flagge.

Das klingt, als ob die Option ist nur wichtig, wenn Empfang Pakete auf dem Sockel, nicht, wenn sie gesendet werden. Wenn Sie Rohpakete senden, können Sie nicht nur stellen Sie die gewünschte Option im IP-Header selbst?

Als Referenz würde ich eine der vielen IGMP bewusst Programme gibt empfehlen. Ein Beispiel dafür ist 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);
}

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

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top