Domanda

sto cercando di forgiare un pacchetto di richiesta IGMPv2 iscrizione e inviarlo su un raw socket.

Gli RFC 3376 afferma:

  messaggi

??IGMP sono incapsulati in datagrammi IPv4, con un numero di protocollo IP di 2. Ogni messaggio IGMP descritto nel presente documento viene inviato con un time-to-live di 1 IP, precedenza IP di Internetwork di controllo (ad esempio, Type of Service 0xc0), e porta un'opzione Router Alert IP [RFC-2113] nella sua intestazione IP

Quindi, la bandiera IP_ROUTER_ALERT deve essere impostato.

Sto cercando di forgiare la necessaria stretta del pacchetto (ad esempio, solo l'intestazione IGMP e payload), quindi sto usando il setsockopt per modificare le opzioni IP.

alcune variabili utili:

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

Ecco come apro il socket 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;

Poi ho impostato il TTL e l'opzione 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");
}

Il setsockopt di IP_ROUTER_ALERT restituisce 0. Dopo la forgiatura del pacchetto, mando con sendto in questo modo:

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

Il pacchetto viene inviato, ma l'opzione IP_ROUTER_ALERT (verificato con wireshark) è mancante. Sto facendo qualcosa di sbagliato? C'è qualche altro metodi per impostare l'opzione IP_ROUTER_ALERT?

Grazie in anticipo.

È stato utile?

Soluzione

Finalmente ho scoperto che il IP_ROUTER_ALERT deve essere impostato dal kernel Linux. richieste di appartenenza IGMP vengono inviate dopo un IP_ADD_MEMBERSHIP è fatto e il kernel prende in carico impostando il flag IP_ROUTER_ALERT.

Altri suggerimenti

Non so il motivo per cui il codice non funziona (si guarda bene a me), ma posso suggerire una soluzione: Goccia un altro strato giù sulle vostre presa Ethernet e costruire telai prime. Si potrebbe anche voler dare un'occhiata a Libnet , che si occupa di costruzione di pacchetti come questo per voi.

Il documentazione stati:

  

Passo tutto a-essere inoltrata pacchetti con   l'opzione di avviso router IP impostato a questo   zoccolo. Valido solo per i socket raw.   Ciò è utile, ad esempio, per l'utente   demoni spazio RSVP. I pacchetti filettati   non vengono inoltrati dal kernel, è   la responsabilità agli utenti di inviare loro   di nuovo fuori. Presa di legame viene ignorato,   tali pacchetti sono filtrati solo   protocollo. Si attende una bandiera intero.

Questa suoni come se l'opzione conta solo quando ricevere i pacchetti sul socket, non quando l'invio di loro. Se si sta inviando pacchetti grezzi, non puoi semplicemente impostare l'opzione richiesta nell'intestazione IP te stesso?

Come riferimento mi sento di raccomandare uno dei tanti programmi consapevoli IGMP là fuori. Un esempio è 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);

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top