1 /* simple igmp query tool
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
19 #include <netinet/in.h>
20 #include <netinet/ip.h>
21 #include <netinet/udp.h>
22 #include <arpa/inet.h>
23 #include <linux/if_ether.h>
24 #include <linux/if_arp.h>
28 #define MAX_PACKET_LENGTH 1600
29 #define HISTORY_LENGTH 20
31 typedef unsigned char byte_t;
33 static void s_8(byte_t *pkt, int ofs, unsigned v)
38 static void s_16(byte_t *pkt, int ofs, unsigned v)
40 ((unsigned short *)(pkt + ofs))[0] = htons(v);
43 static void s_32(byte_t *pkt, int ofs, unsigned v)
45 ((unsigned *)(pkt + ofs))[0] = htonl(v);
49 static unsigned ip_sum(byte_t *data, int len)
53 for (i=0;i<len;i+=2) {
54 sum += ((unsigned short *)(data + i))[0];
61 static int iface_index(const char *ifname)
66 if (isdigit(ifname[0])) {
70 fd = socket(PF_PACKET, SOCK_DGRAM, ETH_P_IP);
76 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
78 if (ioctl(fd, SIOCGIFINDEX, &ifr) != 0) {
79 perror("SIOCGIFINDEX");
85 return ifr.ifr_ifindex;
89 int main(int argc, char *argv[])
94 in_addr_t src_ip, dst_ip, group_ip;
95 struct sockaddr_ll ll;
99 printf("Usage igmp_query <ttl> <iface> <src>\n");
104 fd = socket(PF_PACKET, SOCK_DGRAM, ETH_P_IP);
112 ifindex = iface_index(argv[2]);
114 printf("Bad interface name '%s'\n", argv[2]);
118 src_ip = inet_addr(argv[3]);
119 dst_ip = inet_addr("224.0.0.1");
123 memset(pkt, 0, sizeof(pkt));
126 s_16(pkt, 2, sizeof(pkt));
129 s_32(pkt, 12, htonl(src_ip));
130 s_32(pkt, 16, htonl(dst_ip));
131 s_32(pkt, 20, 0x94040000); /* router alert */
133 s_8 (pkt, 24, 0x11); /* membership report */
134 s_8 (pkt, 25, 0x64); /* v2 */
137 s_16(pkt, 26, ip_sum(pkt+24, 8)); /* igmp csum */
139 s_16(pkt, 10, ip_sum(pkt, 32)-0x100); /* ip csum */
141 ll.sll_family = AF_PACKET;
142 ll.sll_protocol = htons(ETH_P_IP);
143 ll.sll_ifindex = ifindex;
144 ll.sll_hatype = htons(ARPHRD_ETHER);
145 ll.sll_pkttype = PACKET_MULTICAST;
149 s_32(ll.sll_addr, 2, (0x5e<<24) | (ntohl(group_ip) & 0x7FFFFF));
151 sendto(fd, pkt, sizeof(pkt), 0, (struct sockaddr *)&ll, sizeof(ll));