show version
[tridge/junkcode.git] / igmp_query.c
1 /* simple igmp query tool
2
3    Andrew Tridgell 2004
4 */
5
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
18 #include <sys/time.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>
25
26 #define DEBUG 0
27
28 #define MAX_PACKET_LENGTH 1600 
29 #define HISTORY_LENGTH 20
30
31 typedef unsigned char byte_t;
32
33 static void s_8(byte_t *pkt, int ofs, unsigned v)
34 {
35         pkt[ofs] = v;
36 }
37
38 static void s_16(byte_t *pkt, int ofs, unsigned v)
39 {
40         ((unsigned short *)(pkt + ofs))[0] = htons(v);
41 }
42
43 static void s_32(byte_t *pkt, int ofs, unsigned v)
44 {
45         ((unsigned *)(pkt + ofs))[0] = htonl(v);
46 }
47
48
49 static unsigned ip_sum(byte_t *data, int len)
50 {
51         int i;
52         unsigned sum = 0;
53         for (i=0;i<len;i+=2) {
54                 sum += ((unsigned short *)(data + i))[0];
55                 sum &= 0xFFFF;
56         }
57         return htons(~sum);
58 }
59
60
61 static int iface_index(const char *ifname)
62 {
63         int fd;
64         struct ifreq ifr;
65
66         if (isdigit(ifname[0])) {
67                 return atoi(ifname);
68         }
69
70         fd = socket(PF_PACKET, SOCK_DGRAM, ETH_P_IP);
71         if (fd == -1) {
72                 perror("socket");
73                 return -1;
74         }
75
76         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
77
78         if (ioctl(fd, SIOCGIFINDEX, &ifr) != 0) {
79                 perror("SIOCGIFINDEX");
80                 return -1;
81         }
82
83         close(fd);
84
85         return ifr.ifr_ifindex;
86 }
87
88
89 int main(int argc, char *argv[])
90 {
91         int fd;
92         byte_t pkt[32];
93         int ttl;
94         in_addr_t src_ip, dst_ip, group_ip;
95         struct sockaddr_ll ll;
96         int ifindex;
97
98         if (argc < 3) {
99                 printf("Usage igmp_query <ttl> <iface> <src>\n");
100                 exit(1);
101         }
102
103
104         fd = socket(PF_PACKET, SOCK_DGRAM, ETH_P_IP);
105         if (fd == -1) {
106                 perror("eth_open");
107                 exit(1);
108         }
109
110         ttl = atoi(argv[1]);
111
112         ifindex = iface_index(argv[2]);
113         if (ifindex == -1) {
114                 printf("Bad interface name '%s'\n", argv[2]);
115                 exit(1);
116         }
117
118         src_ip   = inet_addr(argv[3]);
119         dst_ip   = inet_addr("224.0.0.1");
120
121         group_ip = dst_ip;
122
123         memset(pkt, 0, sizeof(pkt));
124         
125         s_8 (pkt,  0, 0x46);
126         s_16(pkt,  2, sizeof(pkt));
127         s_8 (pkt,  8, ttl); 
128         s_8 (pkt,  9, 2);
129         s_32(pkt, 12, htonl(src_ip));
130         s_32(pkt, 16, htonl(dst_ip));
131         s_32(pkt, 20, 0x94040000); /* router alert */
132         
133         s_8 (pkt, 24, 0x11); /* membership report */
134         s_8 (pkt, 25, 0x64); /* v2 */
135         s_32(pkt, 28, 0);
136         
137         s_16(pkt, 26, ip_sum(pkt+24, 8)); /* igmp csum */
138         
139         s_16(pkt, 10, ip_sum(pkt, 32)-0x100); /* ip csum */
140         
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;
146         ll.sll_halen = 6;
147         ll.sll_addr[0] = 1;
148         ll.sll_addr[1] = 0;
149         s_32(ll.sll_addr, 2, (0x5e<<24) | (ntohl(group_ip) & 0x7FFFFF));
150         
151         sendto(fd, pkt, sizeof(pkt), 0, (struct sockaddr *)&ll, sizeof(ll));
152         
153         return 0;
154 }