dics.c revision 161030
1/*-
2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/tools/tools/net80211/wesside/dics/dics.c 161030 2006-08-07 00:05:04Z sam $
27 */
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/select.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <netinet/in_systm.h>
34#include <netinet/ip.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <string.h>
39#define __FAVOR_BSD
40#include <netinet/udp.h>
41
42#if 0
43#include <pcap.h>
44#endif
45
46#define MAGIC_LEN (20+8+5)
47
48#define PRGA_LEN (1500-14-20-8)
49
50#define BSD
51//#define LINUX
52
53#ifdef LINUX
54struct ippseudo {
55        struct  in_addr ippseudo_src;   /* source internet address */
56        struct  in_addr ippseudo_dst;   /* destination internet address */
57        u_char          ippseudo_pad;   /* pad, must be zero */
58        u_char          ippseudo_p;     /* protocol */
59        u_short         ippseudo_len;   /* protocol length */
60};
61#endif
62
63#define DPORT 6969
64#define TTLSENT 128
65
66int pps = 10;
67int poll_rate =5;
68
69/********** RIPPED
70************/
71unsigned short in_cksum (unsigned short *ptr, int nbytes) {
72  register long sum;
73  u_short oddbyte;
74  register u_short answer;
75
76  sum = 0;
77  while (nbytes > 1)
78    {
79      sum += *ptr++;
80      nbytes -= 2;
81    }
82
83  if (nbytes == 1)
84    {
85      oddbyte = 0;
86      *((u_char *) & oddbyte) = *(u_char *) ptr;
87      sum += oddbyte;
88    }
89
90  sum = (sum >> 16) + (sum & 0xffff);
91  sum += (sum >> 16);
92  answer = ~sum;
93  return (answer);
94}
95/**************
96************/
97
98void hexdump(unsigned char *ptr, int len) {
99        while(len > 0) {
100                printf("%.2X ", *ptr);
101                ptr++; len--;
102        }
103        printf("\n");
104}
105
106int check_signal(int s, char* ip, unsigned char* ttl, unsigned short* port) {
107	unsigned char buf[1024];
108	int rd;
109	struct msghdr msg;
110	struct iovec iv;
111	struct sockaddr_in s_in;
112	struct {
113		struct cmsghdr hdr;
114		unsigned char ttl;
115	} ctl;
116
117	iv.iov_base = buf;
118	iv.iov_len = sizeof(buf);
119
120	memset(&msg, 0, sizeof(msg));
121	memset(&ctl, 0, sizeof(ctl));
122	msg.msg_name = &s_in;
123	msg.msg_namelen = sizeof(s_in);
124	msg.msg_iov = &iv;
125	msg.msg_iovlen = 1;
126	msg.msg_control = &ctl;
127	msg.msg_controllen = sizeof(ctl);
128
129	rd = recvmsg(s, &msg, 0);
130	if (rd == -1) {
131		perror("recvmsg()");
132		exit(1);
133	}
134
135	if (rd != 5)
136		return 0;
137
138	if ( ctl.hdr.cmsg_level != IPPROTO_IP ||
139#ifdef LINUX
140	    ctl.hdr.cmsg_type != IP_TTL
141#else
142	    ctl.hdr.cmsg_type != IP_RECVTTL
143#endif
144	    ) {
145
146	    printf("Didn't get ttl! len=%d level=%d type=%d\n",
147	    	   ctl.hdr.cmsg_len, ctl.hdr.cmsg_level, ctl.hdr.cmsg_type);
148	    exit(1);
149	}
150
151	if (memcmp(buf, "sorbo", 5) != 0)
152		return 0;
153
154	strcpy(ip, inet_ntoa(s_in.sin_addr));
155	*ttl = ctl.ttl;
156	*port = ntohs(s_in.sin_port);
157	return 1;
158}
159
160#if 0
161int check_signal(const unsigned char* buf, int rd,
162		 char* ip, char* ttl, unsigned short *port) {
163	int got_it;
164	struct ip* iph;
165	struct udphdr* uh;
166
167	if (rd != MAGIC_LEN)
168		return 0;
169
170	iph = (struct ip*) buf;
171	uh = (struct udphdr*) ((char*)iph + 20);
172
173	if ( htons(uh->uh_dport) != DPORT)
174		return 0;
175
176	got_it = memcmp(&buf[rd-5], "sorbo", 5) == 0;
177
178	strcpy(ip, inet_ntoa(iph->ip_src));
179	*ttl = iph->ip_ttl;
180
181	*port = ntohs(uh->uh_sport);
182	return got_it;
183}
184#endif
185
186unsigned int udp_checksum(unsigned char *stuff0, int len, struct in_addr *sip,
187                          struct in_addr *dip) {
188        unsigned char *stuff;
189        struct ippseudo *ph;
190
191        stuff = (unsigned char*) malloc(len + sizeof(struct ippseudo));
192        if(!stuff) {
193                perror("malloc()");
194                exit(1);
195        }
196
197        ph = (struct ippseudo*) stuff;
198
199        memcpy(&ph->ippseudo_src, sip, 4);
200        memcpy(&ph->ippseudo_dst, dip, 4);
201        ph->ippseudo_pad =  0;
202        ph->ippseudo_p = IPPROTO_UDP;
203        ph->ippseudo_len = htons(len);
204
205        memcpy(stuff + sizeof(struct ippseudo), stuff0, len);
206
207        return in_cksum((unsigned short*)stuff, len+sizeof(struct ippseudo));
208}
209
210void send_stuff(int s, char* sip, char* ip, unsigned short port, int dlen) {
211	static unsigned char buf[PRGA_LEN+128] = "\x69";
212	static int plen = 0;
213	static struct sockaddr_in dst;
214	int rd;
215	struct in_addr tmp_dst;
216	int stuff, delay;
217	int i;
218
219	stuff = poll_rate*pps;
220	delay = (int) ((double)1.0/pps*1000.0*1000.0);
221
222	inet_aton(ip, &tmp_dst);
223	if (tmp_dst.s_addr != dst.sin_addr.s_addr ||
224	    dlen != (plen - 20 - 8)) {
225
226	    buf[0] = '\x69';
227	}
228
229	// create packet
230	if (buf[0] == '\x69') {
231		struct ip* iph;
232		struct udphdr* uh;
233		char* ptr;
234
235//		printf("Initializing packet...\n");
236		memset(buf, 0, sizeof(buf));
237		iph = (struct ip*) buf;
238		iph->ip_hl = 5;
239		iph->ip_v = 4;
240		iph->ip_tos = 0;
241		iph->ip_len = htons(20+8+dlen);
242		iph->ip_id = htons(666);
243		iph->ip_off = 0;
244		iph->ip_ttl = TTLSENT;
245		iph->ip_p = IPPROTO_UDP;
246		iph->ip_sum = 0;
247
248		inet_aton(sip, &iph->ip_src);
249		inet_aton(ip, &iph->ip_dst);
250
251		memset(&dst, 0, sizeof(dst));
252		dst.sin_family = PF_INET;
253		dst.sin_port = htons(port);
254		memcpy(&dst.sin_addr, &iph->ip_dst, sizeof(dst.sin_addr));
255
256		iph->ip_sum = in_cksum((unsigned short*)iph, 20);
257
258		uh = (struct udphdr*) ((char*)iph + 20);
259		uh->uh_sport = htons(DPORT);
260		uh->uh_dport = htons(port);
261		uh->uh_ulen = htons(8+dlen);
262		uh->uh_sum = 0;
263
264		ptr = (char*) uh + 8;
265
266		memset(ptr, 0, dlen);
267
268		uh->uh_sum = udp_checksum((unsigned char*)uh, 8+dlen,
269					  &iph->ip_src, &iph->ip_dst);
270
271#ifdef BSD
272		iph->ip_len = ntohs(iph->ip_len);
273#endif
274		plen = 20+8+dlen;
275	}
276#if 0
277	printf("Packet %d %s %d\n", plen, inet_ntoa(dst.sin_addr),
278	ntohs(dst.sin_port));
279	hexdump (buf, plen);
280#endif
281
282//	printf("sending stuff to %s\n", ip);
283	for (i = 0; i < stuff; i++) {
284		rd = sendto(s, buf, plen, 0, (struct sockaddr*)&dst, sizeof(dst));
285		if (rd == -1) {
286			perror("sendto()");
287			exit(1);
288		}
289		if (rd != plen) {
290			printf("wrote %d out of %d\n", rd, plen);
291			exit(1);
292		}
293
294		// sending ttl..
295		if (dlen != PRGA_LEN)
296			break;
297		usleep(delay);
298	}
299}
300
301int main(int argc, char *argv[]) {
302	int s, us;
303	int rd = 1;
304
305#if 0
306	const u_char* buf;
307	char errbuf[PCAP_ERRBUF_SIZE];
308	struct pcap_pkthdr phdr;
309	pcap_t* p;
310	int dtl;
311#endif
312
313	int got_it = 0;
314	char ip[16] = "\x00";
315	unsigned char ttl = 0;
316	unsigned short port;
317	struct sockaddr_in s_in;
318	struct timeval tv;
319	fd_set rfds;
320	unsigned char* sip = 0;
321
322	if (argc < 2) {
323		printf("Usage: %s <sip> [pps]\n", argv[0]);
324		exit(1);
325	}
326
327	if (argc > 2) {
328		pps = atoi(argv[2]);
329	}
330
331	printf("PPS=%d\n", pps);
332
333	sip = argv[1];
334
335	memset(&s_in, 0, sizeof(&s_in));
336	us = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
337	if (s == -1) {
338		perror("socket()");
339		exit(1);
340	}
341	s_in.sin_family = PF_INET;
342	s_in.sin_addr.s_addr = INADDR_ANY;
343	s_in.sin_port = htons(DPORT);
344	if (bind (us, (struct sockaddr*)&s_in, sizeof(s_in)) == -1) {
345		perror("bind()");
346		exit(1);
347	}
348
349	rd = 1;
350	if (setsockopt(us, IPPROTO_IP, IP_RECVTTL, &rd, sizeof(rd)) == -1) {
351		perror("setsockopt()");
352		exit(1);
353	}
354
355	s = socket (PF_INET, SOCK_RAW, IPPROTO_UDP);
356	if (s == -1) {
357		perror("socket()");
358		exit(1);
359	}
360
361	rd = 1;
362	if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &rd, sizeof(rd)) == -1) {
363		perror("setsockopt()");
364		exit(1);
365	}
366
367
368#if 0
369        p = pcap_open_live(argv[1], 512, 0, 25, errbuf);
370	if (!p) {
371		printf("pcap_open_live(): %s\n", errbuf);
372		exit(1);
373	}
374
375	dtl = pcap_datalink(p);
376
377	switch (dtl) {
378		case DLT_NULL:
379			dtl = 4;
380			break;
381
382		case DLT_EN10MB:
383			dtl = 14;
384			break;
385
386		default:
387			printf("Unknown datalink %d\n", dtl);
388			exit(1);
389	}
390
391	printf("Datalink size=%d\n", dtl);
392#endif
393	while (1) {
394#if 0
395		buf = pcap_next(p, &phdr);
396		if (buf) {
397			if (check_signal(buf+dtl, phdr.caplen-dtl,
398					 ip, &ttl, &port)) {
399				got_it = 2;
400				printf("Got signal from %s:%d TTL=%d\n",
401				       ip, port, ttl);
402			}
403		}
404#endif
405		FD_ZERO(&rfds);
406		FD_SET(us, &rfds);
407		tv.tv_sec = 0;
408		tv.tv_usec = 10*1000;
409		rd = select(us+1, &rfds, NULL, NULL, &tv);
410		if (rd == -1) {
411			perror("select()");
412			exit(1);
413		}
414		if (rd == 1 && FD_ISSET(us, &rfds)) {
415			char ipnew[16];
416			unsigned char ttlnew;
417			if (check_signal(us, ipnew, &ttlnew, &port)) {
418				int send_ttl = 0;
419				if (ttlnew != ttl || strcmp(ipnew, ip) != 0 ||
420				    got_it == 0) {
421				    	send_ttl = 1;
422				}
423				ttl = ttlnew;
424				strcpy(ip, ipnew);
425
426				printf("Got signal from %s:%d TTL=%d\n",
427				       ip, port, ttl);
428				got_it = 2;
429
430				if (send_ttl) {
431					printf("Sending ttl (%d)...\n", ttl);
432					send_stuff(s, sip, ip, port, 69 + (TTLSENT-ttl));
433				}
434			}
435		}
436
437		if (got_it) {
438			printf("Sending stuff to %s...\n", ip);
439			send_stuff(s, sip, ip, port, PRGA_LEN);
440			got_it--;
441
442			if (got_it == 0) {
443				printf("Stopping send\n");
444			}
445		}
446	}
447
448#if 0
449	pcap_close(p);
450#endif
451
452	close(s);
453	close(us);
454	exit(0);
455}
456