1161030Ssam/*-
2161030Ssam * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3161030Ssam * All rights reserved.
4161030Ssam *
5161030Ssam * Redistribution and use in source and binary forms, with or without
6161030Ssam * modification, are permitted provided that the following conditions
7161030Ssam * are met:
8161030Ssam * 1. Redistributions of source code must retain the above copyright
9161030Ssam *    notice, this list of conditions and the following disclaimer.
10161030Ssam * 2. Redistributions in binary form must reproduce the above copyright
11161030Ssam *    notice, this list of conditions and the following disclaimer in the
12161030Ssam *    documentation and/or other materials provided with the distribution.
13161030Ssam *
14161030Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15161030Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16161030Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17161030Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18161030Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19161030Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20161030Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21161030Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22161030Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23161030Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24161030Ssam * SUCH DAMAGE.
25161030Ssam *
26161030Ssam * $FreeBSD$
27161030Ssam */
28161030Ssam#include <sys/types.h>
29161030Ssam#include <sys/socket.h>
30161030Ssam#include <sys/select.h>
31161030Ssam#include <netinet/in.h>
32161030Ssam#include <arpa/inet.h>
33161030Ssam#include <netinet/in_systm.h>
34161030Ssam#include <netinet/ip.h>
35161030Ssam#include <stdio.h>
36161030Ssam#include <stdlib.h>
37161030Ssam#include <unistd.h>
38161030Ssam#include <string.h>
39161030Ssam#define __FAVOR_BSD
40161030Ssam#include <netinet/udp.h>
41161030Ssam
42161030Ssam#if 0
43161030Ssam#include <pcap.h>
44161030Ssam#endif
45161030Ssam
46161030Ssam#define MAGIC_LEN (20+8+5)
47161030Ssam
48161030Ssam#define PRGA_LEN (1500-14-20-8)
49161030Ssam
50161030Ssam#define BSD
51161030Ssam//#define LINUX
52161030Ssam
53161030Ssam#ifdef LINUX
54161030Ssamstruct ippseudo {
55161030Ssam        struct  in_addr ippseudo_src;   /* source internet address */
56161030Ssam        struct  in_addr ippseudo_dst;   /* destination internet address */
57161030Ssam        u_char          ippseudo_pad;   /* pad, must be zero */
58161030Ssam        u_char          ippseudo_p;     /* protocol */
59161030Ssam        u_short         ippseudo_len;   /* protocol length */
60161030Ssam};
61161030Ssam#endif
62161030Ssam
63161030Ssam#define DPORT 6969
64161030Ssam#define TTLSENT 128
65161030Ssam
66161030Ssamint pps = 10;
67161030Ssamint poll_rate =5;
68161030Ssam
69161030Ssam/********** RIPPED
70161030Ssam************/
71161030Ssamunsigned short in_cksum (unsigned short *ptr, int nbytes) {
72161030Ssam  register long sum;
73161030Ssam  u_short oddbyte;
74161030Ssam  register u_short answer;
75161030Ssam
76161030Ssam  sum = 0;
77161030Ssam  while (nbytes > 1)
78161030Ssam    {
79161030Ssam      sum += *ptr++;
80161030Ssam      nbytes -= 2;
81161030Ssam    }
82161030Ssam
83161030Ssam  if (nbytes == 1)
84161030Ssam    {
85161030Ssam      oddbyte = 0;
86161030Ssam      *((u_char *) & oddbyte) = *(u_char *) ptr;
87161030Ssam      sum += oddbyte;
88161030Ssam    }
89161030Ssam
90161030Ssam  sum = (sum >> 16) + (sum & 0xffff);
91161030Ssam  sum += (sum >> 16);
92161030Ssam  answer = ~sum;
93161030Ssam  return (answer);
94161030Ssam}
95161030Ssam/**************
96161030Ssam************/
97161030Ssam
98161030Ssamvoid hexdump(unsigned char *ptr, int len) {
99161030Ssam        while(len > 0) {
100161030Ssam                printf("%.2X ", *ptr);
101161030Ssam                ptr++; len--;
102161030Ssam        }
103161030Ssam        printf("\n");
104161030Ssam}
105161030Ssam
106161030Ssamint check_signal(int s, char* ip, unsigned char* ttl, unsigned short* port) {
107161030Ssam	unsigned char buf[1024];
108161030Ssam	int rd;
109161030Ssam	struct msghdr msg;
110161030Ssam	struct iovec iv;
111161030Ssam	struct sockaddr_in s_in;
112161030Ssam	struct {
113161030Ssam		struct cmsghdr hdr;
114161030Ssam		unsigned char ttl;
115161030Ssam	} ctl;
116161030Ssam
117161030Ssam	iv.iov_base = buf;
118161030Ssam	iv.iov_len = sizeof(buf);
119161030Ssam
120161030Ssam	memset(&msg, 0, sizeof(msg));
121161030Ssam	memset(&ctl, 0, sizeof(ctl));
122161030Ssam	msg.msg_name = &s_in;
123161030Ssam	msg.msg_namelen = sizeof(s_in);
124161030Ssam	msg.msg_iov = &iv;
125161030Ssam	msg.msg_iovlen = 1;
126161030Ssam	msg.msg_control = &ctl;
127161030Ssam	msg.msg_controllen = sizeof(ctl);
128161030Ssam
129161030Ssam	rd = recvmsg(s, &msg, 0);
130161030Ssam	if (rd == -1) {
131161030Ssam		perror("recvmsg()");
132161030Ssam		exit(1);
133161030Ssam	}
134161030Ssam
135161030Ssam	if (rd != 5)
136161030Ssam		return 0;
137161030Ssam
138161030Ssam	if ( ctl.hdr.cmsg_level != IPPROTO_IP ||
139161030Ssam#ifdef LINUX
140161030Ssam	    ctl.hdr.cmsg_type != IP_TTL
141161030Ssam#else
142161030Ssam	    ctl.hdr.cmsg_type != IP_RECVTTL
143161030Ssam#endif
144161030Ssam	    ) {
145161030Ssam
146161030Ssam	    printf("Didn't get ttl! len=%d level=%d type=%d\n",
147161030Ssam	    	   ctl.hdr.cmsg_len, ctl.hdr.cmsg_level, ctl.hdr.cmsg_type);
148161030Ssam	    exit(1);
149161030Ssam	}
150161030Ssam
151161030Ssam	if (memcmp(buf, "sorbo", 5) != 0)
152161030Ssam		return 0;
153161030Ssam
154161030Ssam	strcpy(ip, inet_ntoa(s_in.sin_addr));
155161030Ssam	*ttl = ctl.ttl;
156161030Ssam	*port = ntohs(s_in.sin_port);
157161030Ssam	return 1;
158161030Ssam}
159161030Ssam
160161030Ssam#if 0
161161030Ssamint check_signal(const unsigned char* buf, int rd,
162161030Ssam		 char* ip, char* ttl, unsigned short *port) {
163161030Ssam	int got_it;
164161030Ssam	struct ip* iph;
165161030Ssam	struct udphdr* uh;
166161030Ssam
167161030Ssam	if (rd != MAGIC_LEN)
168161030Ssam		return 0;
169161030Ssam
170161030Ssam	iph = (struct ip*) buf;
171161030Ssam	uh = (struct udphdr*) ((char*)iph + 20);
172161030Ssam
173161030Ssam	if ( htons(uh->uh_dport) != DPORT)
174161030Ssam		return 0;
175161030Ssam
176161030Ssam	got_it = memcmp(&buf[rd-5], "sorbo", 5) == 0;
177161030Ssam
178161030Ssam	strcpy(ip, inet_ntoa(iph->ip_src));
179161030Ssam	*ttl = iph->ip_ttl;
180161030Ssam
181161030Ssam	*port = ntohs(uh->uh_sport);
182161030Ssam	return got_it;
183161030Ssam}
184161030Ssam#endif
185161030Ssam
186161030Ssamunsigned int udp_checksum(unsigned char *stuff0, int len, struct in_addr *sip,
187161030Ssam                          struct in_addr *dip) {
188161030Ssam        unsigned char *stuff;
189161030Ssam        struct ippseudo *ph;
190161030Ssam
191161030Ssam        stuff = (unsigned char*) malloc(len + sizeof(struct ippseudo));
192161030Ssam        if(!stuff) {
193161030Ssam                perror("malloc()");
194161030Ssam                exit(1);
195161030Ssam        }
196161030Ssam
197161030Ssam        ph = (struct ippseudo*) stuff;
198161030Ssam
199161030Ssam        memcpy(&ph->ippseudo_src, sip, 4);
200161030Ssam        memcpy(&ph->ippseudo_dst, dip, 4);
201161030Ssam        ph->ippseudo_pad =  0;
202161030Ssam        ph->ippseudo_p = IPPROTO_UDP;
203161030Ssam        ph->ippseudo_len = htons(len);
204161030Ssam
205161030Ssam        memcpy(stuff + sizeof(struct ippseudo), stuff0, len);
206161030Ssam
207161030Ssam        return in_cksum((unsigned short*)stuff, len+sizeof(struct ippseudo));
208161030Ssam}
209161030Ssam
210161030Ssamvoid send_stuff(int s, char* sip, char* ip, unsigned short port, int dlen) {
211161030Ssam	static unsigned char buf[PRGA_LEN+128] = "\x69";
212161030Ssam	static int plen = 0;
213161030Ssam	static struct sockaddr_in dst;
214161030Ssam	int rd;
215161030Ssam	struct in_addr tmp_dst;
216161030Ssam	int stuff, delay;
217161030Ssam	int i;
218161030Ssam
219161030Ssam	stuff = poll_rate*pps;
220161030Ssam	delay = (int) ((double)1.0/pps*1000.0*1000.0);
221161030Ssam
222161030Ssam	inet_aton(ip, &tmp_dst);
223161030Ssam	if (tmp_dst.s_addr != dst.sin_addr.s_addr ||
224161030Ssam	    dlen != (plen - 20 - 8)) {
225161030Ssam
226161030Ssam	    buf[0] = '\x69';
227161030Ssam	}
228161030Ssam
229161030Ssam	// create packet
230161030Ssam	if (buf[0] == '\x69') {
231161030Ssam		struct ip* iph;
232161030Ssam		struct udphdr* uh;
233161030Ssam		char* ptr;
234161030Ssam
235161030Ssam//		printf("Initializing packet...\n");
236161030Ssam		memset(buf, 0, sizeof(buf));
237161030Ssam		iph = (struct ip*) buf;
238161030Ssam		iph->ip_hl = 5;
239161030Ssam		iph->ip_v = 4;
240161030Ssam		iph->ip_tos = 0;
241161030Ssam		iph->ip_len = htons(20+8+dlen);
242161030Ssam		iph->ip_id = htons(666);
243161030Ssam		iph->ip_off = 0;
244161030Ssam		iph->ip_ttl = TTLSENT;
245161030Ssam		iph->ip_p = IPPROTO_UDP;
246161030Ssam		iph->ip_sum = 0;
247161030Ssam
248161030Ssam		inet_aton(sip, &iph->ip_src);
249161030Ssam		inet_aton(ip, &iph->ip_dst);
250161030Ssam
251161030Ssam		memset(&dst, 0, sizeof(dst));
252161030Ssam		dst.sin_family = PF_INET;
253161030Ssam		dst.sin_port = htons(port);
254161030Ssam		memcpy(&dst.sin_addr, &iph->ip_dst, sizeof(dst.sin_addr));
255161030Ssam
256161030Ssam		iph->ip_sum = in_cksum((unsigned short*)iph, 20);
257161030Ssam
258161030Ssam		uh = (struct udphdr*) ((char*)iph + 20);
259161030Ssam		uh->uh_sport = htons(DPORT);
260161030Ssam		uh->uh_dport = htons(port);
261161030Ssam		uh->uh_ulen = htons(8+dlen);
262161030Ssam		uh->uh_sum = 0;
263161030Ssam
264161030Ssam		ptr = (char*) uh + 8;
265161030Ssam
266161030Ssam		memset(ptr, 0, dlen);
267161030Ssam
268161030Ssam		uh->uh_sum = udp_checksum((unsigned char*)uh, 8+dlen,
269161030Ssam					  &iph->ip_src, &iph->ip_dst);
270161030Ssam
271161030Ssam#ifdef BSD
272161030Ssam		iph->ip_len = ntohs(iph->ip_len);
273161030Ssam#endif
274161030Ssam		plen = 20+8+dlen;
275161030Ssam	}
276161030Ssam#if 0
277161030Ssam	printf("Packet %d %s %d\n", plen, inet_ntoa(dst.sin_addr),
278161030Ssam	ntohs(dst.sin_port));
279161030Ssam	hexdump (buf, plen);
280161030Ssam#endif
281161030Ssam
282161030Ssam//	printf("sending stuff to %s\n", ip);
283161030Ssam	for (i = 0; i < stuff; i++) {
284161030Ssam		rd = sendto(s, buf, plen, 0, (struct sockaddr*)&dst, sizeof(dst));
285161030Ssam		if (rd == -1) {
286161030Ssam			perror("sendto()");
287161030Ssam			exit(1);
288161030Ssam		}
289161030Ssam		if (rd != plen) {
290161030Ssam			printf("wrote %d out of %d\n", rd, plen);
291161030Ssam			exit(1);
292161030Ssam		}
293161030Ssam
294161030Ssam		// sending ttl..
295161030Ssam		if (dlen != PRGA_LEN)
296161030Ssam			break;
297161030Ssam		usleep(delay);
298161030Ssam	}
299161030Ssam}
300161030Ssam
301161030Ssamint main(int argc, char *argv[]) {
302161030Ssam	int s, us;
303161030Ssam	int rd = 1;
304161030Ssam
305161030Ssam#if 0
306161030Ssam	const u_char* buf;
307161030Ssam	char errbuf[PCAP_ERRBUF_SIZE];
308161030Ssam	struct pcap_pkthdr phdr;
309161030Ssam	pcap_t* p;
310161030Ssam	int dtl;
311161030Ssam#endif
312161030Ssam
313161030Ssam	int got_it = 0;
314161030Ssam	char ip[16] = "\x00";
315161030Ssam	unsigned char ttl = 0;
316161030Ssam	unsigned short port;
317161030Ssam	struct sockaddr_in s_in;
318161030Ssam	struct timeval tv;
319161030Ssam	fd_set rfds;
320161030Ssam	unsigned char* sip = 0;
321161030Ssam
322161030Ssam	if (argc < 2) {
323161030Ssam		printf("Usage: %s <sip> [pps]\n", argv[0]);
324161030Ssam		exit(1);
325161030Ssam	}
326161030Ssam
327161030Ssam	if (argc > 2) {
328161030Ssam		pps = atoi(argv[2]);
329161030Ssam	}
330161030Ssam
331161030Ssam	printf("PPS=%d\n", pps);
332161030Ssam
333161030Ssam	sip = argv[1];
334161030Ssam
335237546Skevlo	memset(&s_in, 0, sizeof(s_in));
336161030Ssam	us = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
337161030Ssam	if (s == -1) {
338161030Ssam		perror("socket()");
339161030Ssam		exit(1);
340161030Ssam	}
341161030Ssam	s_in.sin_family = PF_INET;
342161030Ssam	s_in.sin_addr.s_addr = INADDR_ANY;
343161030Ssam	s_in.sin_port = htons(DPORT);
344161030Ssam	if (bind (us, (struct sockaddr*)&s_in, sizeof(s_in)) == -1) {
345161030Ssam		perror("bind()");
346161030Ssam		exit(1);
347161030Ssam	}
348161030Ssam
349161030Ssam	rd = 1;
350161030Ssam	if (setsockopt(us, IPPROTO_IP, IP_RECVTTL, &rd, sizeof(rd)) == -1) {
351161030Ssam		perror("setsockopt()");
352161030Ssam		exit(1);
353161030Ssam	}
354161030Ssam
355161030Ssam	s = socket (PF_INET, SOCK_RAW, IPPROTO_UDP);
356161030Ssam	if (s == -1) {
357161030Ssam		perror("socket()");
358161030Ssam		exit(1);
359161030Ssam	}
360161030Ssam
361161030Ssam	rd = 1;
362161030Ssam	if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &rd, sizeof(rd)) == -1) {
363161030Ssam		perror("setsockopt()");
364161030Ssam		exit(1);
365161030Ssam	}
366161030Ssam
367161030Ssam
368161030Ssam#if 0
369161030Ssam        p = pcap_open_live(argv[1], 512, 0, 25, errbuf);
370161030Ssam	if (!p) {
371161030Ssam		printf("pcap_open_live(): %s\n", errbuf);
372161030Ssam		exit(1);
373161030Ssam	}
374161030Ssam
375161030Ssam	dtl = pcap_datalink(p);
376161030Ssam
377161030Ssam	switch (dtl) {
378161030Ssam		case DLT_NULL:
379161030Ssam			dtl = 4;
380161030Ssam			break;
381161030Ssam
382161030Ssam		case DLT_EN10MB:
383161030Ssam			dtl = 14;
384161030Ssam			break;
385161030Ssam
386161030Ssam		default:
387161030Ssam			printf("Unknown datalink %d\n", dtl);
388161030Ssam			exit(1);
389161030Ssam	}
390161030Ssam
391161030Ssam	printf("Datalink size=%d\n", dtl);
392161030Ssam#endif
393161030Ssam	while (1) {
394161030Ssam#if 0
395161030Ssam		buf = pcap_next(p, &phdr);
396161030Ssam		if (buf) {
397161030Ssam			if (check_signal(buf+dtl, phdr.caplen-dtl,
398161030Ssam					 ip, &ttl, &port)) {
399161030Ssam				got_it = 2;
400161030Ssam				printf("Got signal from %s:%d TTL=%d\n",
401161030Ssam				       ip, port, ttl);
402161030Ssam			}
403161030Ssam		}
404161030Ssam#endif
405161030Ssam		FD_ZERO(&rfds);
406161030Ssam		FD_SET(us, &rfds);
407161030Ssam		tv.tv_sec = 0;
408161030Ssam		tv.tv_usec = 10*1000;
409161030Ssam		rd = select(us+1, &rfds, NULL, NULL, &tv);
410161030Ssam		if (rd == -1) {
411161030Ssam			perror("select()");
412161030Ssam			exit(1);
413161030Ssam		}
414161030Ssam		if (rd == 1 && FD_ISSET(us, &rfds)) {
415161030Ssam			char ipnew[16];
416161030Ssam			unsigned char ttlnew;
417161030Ssam			if (check_signal(us, ipnew, &ttlnew, &port)) {
418161030Ssam				int send_ttl = 0;
419161030Ssam				if (ttlnew != ttl || strcmp(ipnew, ip) != 0 ||
420161030Ssam				    got_it == 0) {
421161030Ssam				    	send_ttl = 1;
422161030Ssam				}
423161030Ssam				ttl = ttlnew;
424161030Ssam				strcpy(ip, ipnew);
425161030Ssam
426161030Ssam				printf("Got signal from %s:%d TTL=%d\n",
427161030Ssam				       ip, port, ttl);
428161030Ssam				got_it = 2;
429161030Ssam
430161030Ssam				if (send_ttl) {
431161030Ssam					printf("Sending ttl (%d)...\n", ttl);
432161030Ssam					send_stuff(s, sip, ip, port, 69 + (TTLSENT-ttl));
433161030Ssam				}
434161030Ssam			}
435161030Ssam		}
436161030Ssam
437161030Ssam		if (got_it) {
438161030Ssam			printf("Sending stuff to %s...\n", ip);
439161030Ssam			send_stuff(s, sip, ip, port, PRGA_LEN);
440161030Ssam			got_it--;
441161030Ssam
442161030Ssam			if (got_it == 0) {
443161030Ssam				printf("Stopping send\n");
444161030Ssam			}
445161030Ssam		}
446161030Ssam	}
447161030Ssam
448161030Ssam#if 0
449161030Ssam	pcap_close(p);
450161030Ssam#endif
451161030Ssam
452161030Ssam	close(s);
453161030Ssam	close(us);
454161030Ssam	exit(0);
455161030Ssam}
456