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