質問
IGMPV2メンバーシップリクエストパケットを偽造し、生のソケットに送信しようとしています。
RFC 3376の状態:
IGMPメッセージは、IPv4データグラムにカプセル化され、IPプロトコル番号は2です。このドキュメントで説明されているすべてのIGMPメッセージは、IPからliveまでのIPまでのIPがインターネットワーク制御のIPの優先順位(、サービス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;
生のソケットを開く方法は次のとおりです。
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およびRouterアラートオプションを設定します。
// 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を返します。
// 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オプションを設定する他の方法はありますか?
前もって感謝します。
解決
最後に、私はそれを見つけました IP_ROUTER_ALERT
Linuxカーネルで設定する必要があります。 IGMPメンバーシップリクエストは、後に送信されます IP_ADD_MEMBERSHIP
行われ、カーネルはの設定を担当します IP_ROUTER_ALERT
国旗。
他のヒント
なぜあなたのコードが機能していないのかはわかりませんが(私にはうまく見えます)、回避策を提案できます。生のソケットにもう1つレイヤーダウンしてイーサネットフレームを構築します。あなたも見たいかもしれません libnet, 、あなたのためにこのような建物のパケットを処理します。
ドキュメンテーション 州:
このソケットに設定されたIPルーターアラートオプションを使用して、すべての転送されたパケットを渡します。生のソケットに対してのみ有効です。これは、たとえば、ユーザースペースRSVP Daemonsにとって便利です。タップされたパケットはカーネルによって転送されるのではなく、再びそれらを送信するのはユーザーの責任です。ソケットバインディングは無視されます。このようなパケットは、プロトコルによってのみフィルタリングされます。整数フラグを期待しています。
これは、オプションがいつ重要であるかのように聞こえます 受信 ソケットのパケットは、送信するときではありません。生のパケットを送信している場合は、ただできません 必要なオプションを設定します 自分でIPヘッダーで?
参照として、私はそこに多くのIGMP認識プログラムの1つをお勧めします。一例は次のとおりです 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);
}