1

IGMPv2メンバーシップリクエストパケットを偽造して、RAWソケットで送信しようとしています。

RFC3376は次のように述べています。

IGMPメッセージは、IPプロトコル番号2のIPv4データグラムにカプセル化されます。このドキュメントで説明されているすべてのIGMPメッセージは、IP Time-to-Live 1、IP Precedence of Internetwork Control(Type of Service 0xc0など)、 IPヘッダーにIPルーターアラートオプション[RFC-2113]が含まれています

したがって、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とルーターアラートオプションを設定します。

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

IP_ROUTER_ALERTのsetsockoptは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

4 に答える 4

2

IP_ROUTER_ALERT最後に、Linuxカーネルによって設定する必要があることがわかりました。IP_ADD_MEMBERSHIPが実行され、カーネルがIP_ROUTER_ALERTフラグの設定を担当した後、IGMPメンバーシップ要求が送信されます。

于 2010-12-29T13:50:53.010 に答える
1

コードが機能しない理由はわかりませんが(私には問題ないように見えます)、回避策を提案できます。rawソケットにもう1つレイヤーをドロップして、イーサネットフレームを構築します。また、このようなパケットの作成を処理するLibnetも確認することをお勧めします。

于 2010-11-12T14:01:46.163 に答える
0

ドキュメントには次のように記載されています。

IPルーターアラートオプションをこのソケットに設定して、転送されるすべてのパケットを渡します。rawソケットにのみ有効です。これは、たとえば、ユーザースペースのRSVPデーモンに役立ちます。タップされたパケットはカーネルによって転送されません。それらを再送信するのはユーザーの責任です。ソケットバインディングは無視され、そのようなパケットはプロトコルによってのみフィルタリングされます。整数フラグが必要です。

これは、パケットを送信するときではなく、ソケットでパケットを受信するときにのみオプションが重要であるかのように聞こえます。生のパケットを送信する場合は、IPヘッダーに必要なオプションを自分で設定するだけでは不十分ですか?

于 2010-11-12T12:49:49.643 に答える
0

参考までに、IGMP対応の多くのプログラムの1つをお勧めします。1つの例は次のとおりですigmpproxyhttps ://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);

}
于 2016-09-21T12:29:46.763 に答える