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: src/tools/tools/net80211/wesside/dics/dics.c,v 1.1 2006/08/07 00:05:03 sam Exp $
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
54 struct 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 
66 int pps = 10;
67 int poll_rate =5;
68 
69 /********** RIPPED
70 ************/
in_cksum(unsigned short * ptr,int nbytes)71 unsigned 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 
hexdump(unsigned char * ptr,int len)98 void hexdump(unsigned char *ptr, int len) {
99         while(len > 0) {
100                 printf("%.2X ", *ptr);
101                 ptr++; len--;
102         }
103         printf("\n");
104 }
105 
check_signal(int s,char * ip,unsigned char * ttl,unsigned short * port)106 int 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
161 int 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 
udp_checksum(unsigned char * stuff0,int len,struct in_addr * sip,struct in_addr * dip)186 unsigned 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 
send_stuff(int s,char * sip,char * ip,unsigned short port,int dlen)210 void 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 
main(int argc,char * argv[])301 int 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 = NULL;
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