|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <stdlib.h> ! 3: #include <unistd.h> ! 4: #include <string.h> ! 5: #include <stdarg.h> ! 6: #include <errno.h> ! 7: #include <fcntl.h> ! 8: #include <libgen.h> ! 9: #include <signal.h> ! 10: #include <net/if.h> ! 11: #include <net/ethernet.h> ! 12: #include <sys/select.h> ! 13: #include <sys/socket.h> ! 14: #include <sys/stat.h> ! 15: #include <sys/un.h> ! 16: #include <syslog.h> ! 17: #include <getopt.h> ! 18: #include <pcap.h> ! 19: ! 20: #define SNAPLEN 1600 ! 21: ! 22: /* ! 23: * FIXME: is there a way to detect the version of the libpcap library? ! 24: * Version 0.9 has pcap_inject; version 0.8 doesn't, but both report ! 25: * their version number as 2.4. ! 26: */ ! 27: #define HAVE_PCAP_INJECT 0 ! 28: ! 29: struct hijack { ! 30: pcap_t *pcap; ! 31: int fd; ! 32: int datalink; ! 33: int filtered; ! 34: unsigned long rx_count; ! 35: unsigned long tx_count; ! 36: }; ! 37: ! 38: struct hijack_listener { ! 39: struct sockaddr_un sun; ! 40: int fd; ! 41: }; ! 42: ! 43: struct hijack_options { ! 44: char interface[IF_NAMESIZE]; ! 45: int daemonise; ! 46: }; ! 47: ! 48: static int daemonised = 0; ! 49: ! 50: static int signalled = 0; ! 51: ! 52: static void flag_signalled ( int signal __attribute__ (( unused )) ) { ! 53: signalled = 1; ! 54: } ! 55: ! 56: #if ! HAVE_PCAP_INJECT ! 57: /** ! 58: * Substitute for pcap_inject(), if this version of libpcap doesn't ! 59: * have it. Will almost certainly only work under Linux. ! 60: * ! 61: */ ! 62: int pcap_inject ( pcap_t *pcap, const void *data, size_t len ) { ! 63: int fd; ! 64: char *errbuf = pcap_geterr ( pcap ); ! 65: ! 66: fd = pcap_get_selectable_fd ( pcap ); ! 67: if ( fd < 0 ) { ! 68: snprintf ( errbuf, PCAP_ERRBUF_SIZE, ! 69: "could not get file descriptor" ); ! 70: return -1; ! 71: } ! 72: if ( write ( fd, data, len ) != len ) { ! 73: snprintf ( errbuf, PCAP_ERRBUF_SIZE, ! 74: "could not write data: %s", strerror ( errno ) ); ! 75: return -1; ! 76: } ! 77: return len; ! 78: } ! 79: #endif /* ! HAVE_PCAP_INJECT */ ! 80: ! 81: /** ! 82: * Log error message ! 83: * ! 84: */ ! 85: static __attribute__ (( format ( printf, 2, 3 ) )) void ! 86: logmsg ( int level, const char *format, ... ) { ! 87: va_list ap; ! 88: ! 89: va_start ( ap, format ); ! 90: if ( daemonised ) { ! 91: vsyslog ( ( LOG_DAEMON | level ), format, ap ); ! 92: } else { ! 93: vfprintf ( stderr, format, ap ); ! 94: } ! 95: va_end ( ap ); ! 96: } ! 97: ! 98: /** ! 99: * Open pcap device ! 100: * ! 101: */ ! 102: static int hijack_open ( const char *interface, struct hijack *hijack ) { ! 103: char errbuf[PCAP_ERRBUF_SIZE]; ! 104: ! 105: /* Open interface via pcap */ ! 106: errbuf[0] = '\0'; ! 107: hijack->pcap = pcap_open_live ( interface, SNAPLEN, 1, 0, errbuf ); ! 108: if ( ! hijack->pcap ) { ! 109: logmsg ( LOG_ERR, "Failed to open %s: %s\n", ! 110: interface, errbuf ); ! 111: goto err; ! 112: } ! 113: if ( errbuf[0] ) ! 114: logmsg ( LOG_WARNING, "Warning: %s\n", errbuf ); ! 115: ! 116: /* Set capture interface to non-blocking mode */ ! 117: if ( pcap_setnonblock ( hijack->pcap, 1, errbuf ) < 0 ) { ! 118: logmsg ( LOG_ERR, "Could not make %s non-blocking: %s\n", ! 119: interface, errbuf ); ! 120: goto err; ! 121: } ! 122: ! 123: /* Get file descriptor for select() */ ! 124: hijack->fd = pcap_get_selectable_fd ( hijack->pcap ); ! 125: if ( hijack->fd < 0 ) { ! 126: logmsg ( LOG_ERR, "Cannot get selectable file descriptor " ! 127: "for %s\n", interface ); ! 128: goto err; ! 129: } ! 130: ! 131: /* Get link layer type */ ! 132: hijack->datalink = pcap_datalink ( hijack->pcap ); ! 133: ! 134: return 0; ! 135: ! 136: err: ! 137: if ( hijack->pcap ) ! 138: pcap_close ( hijack->pcap ); ! 139: return -1; ! 140: } ! 141: ! 142: /** ! 143: * Close pcap device ! 144: * ! 145: */ ! 146: static void hijack_close ( struct hijack *hijack ) { ! 147: pcap_close ( hijack->pcap ); ! 148: } ! 149: ! 150: /** ! 151: * Install filter for hijacked connection ! 152: * ! 153: */ ! 154: static int hijack_install_filter ( struct hijack *hijack, ! 155: char *filter ) { ! 156: struct bpf_program program; ! 157: ! 158: /* Compile filter */ ! 159: if ( pcap_compile ( hijack->pcap, &program, filter, 1, 0 ) < 0 ) { ! 160: logmsg ( LOG_ERR, "could not compile filter \"%s\": %s\n", ! 161: filter, pcap_geterr ( hijack->pcap ) ); ! 162: goto err_nofree; ! 163: } ! 164: ! 165: /* Install filter */ ! 166: if ( pcap_setfilter ( hijack->pcap, &program ) < 0 ) { ! 167: logmsg ( LOG_ERR, "could not install filter \"%s\": %s\n", ! 168: filter, pcap_geterr ( hijack->pcap ) ); ! 169: goto err; ! 170: } ! 171: ! 172: logmsg ( LOG_INFO, "using filter \"%s\"\n", filter ); ! 173: ! 174: pcap_freecode ( &program ); ! 175: return 0; ! 176: ! 177: err: ! 178: pcap_freecode ( &program ); ! 179: err_nofree: ! 180: return -1; ! 181: } ! 182: ! 183: /** ! 184: * Set up filter for hijacked ethernet connection ! 185: * ! 186: */ ! 187: static int hijack_filter_ethernet ( struct hijack *hijack, const char *buf, ! 188: size_t len ) { ! 189: char filter[55]; /* see format string */ ! 190: struct ether_header *ether_header = ( struct ether_header * ) buf; ! 191: unsigned char *hwaddr = ether_header->ether_shost; ! 192: ! 193: if ( len < sizeof ( *ether_header ) ) ! 194: return -1; ! 195: ! 196: snprintf ( filter, sizeof ( filter ), "broadcast or multicast or " ! 197: "ether host %02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0], ! 198: hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5] ); ! 199: ! 200: return hijack_install_filter ( hijack, filter ); ! 201: } ! 202: ! 203: /** ! 204: * Set up filter for hijacked connection ! 205: * ! 206: */ ! 207: static int hijack_filter ( struct hijack *hijack, const char *buf, ! 208: size_t len ) { ! 209: switch ( hijack->datalink ) { ! 210: case DLT_EN10MB: ! 211: return hijack_filter_ethernet ( hijack, buf, len ); ! 212: default: ! 213: logmsg ( LOG_ERR, "unsupported protocol %s: cannot filter\n", ! 214: ( pcap_datalink_val_to_name ( hijack->datalink ) ? ! 215: pcap_datalink_val_to_name ( hijack->datalink ) : ! 216: "UNKNOWN" ) ); ! 217: /* Return success so we don't get called again */ ! 218: return 0; ! 219: } ! 220: } ! 221: ! 222: /** ! 223: * Forward data from hijacker ! 224: * ! 225: */ ! 226: static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) { ! 227: char buf[SNAPLEN]; ! 228: ssize_t len; ! 229: ! 230: /* Read packet from hijacker */ ! 231: len = read ( fd, buf, sizeof ( buf ) ); ! 232: if ( len < 0 ) { ! 233: logmsg ( LOG_ERR, "read from hijacker failed: %s\n", ! 234: strerror ( errno ) ); ! 235: return -1; ! 236: } ! 237: if ( len == 0 ) ! 238: return 0; ! 239: ! 240: /* Set up filter if not already in place */ ! 241: if ( ! hijack->filtered ) { ! 242: if ( hijack_filter ( hijack, buf, len ) == 0 ) ! 243: hijack->filtered = 1; ! 244: } ! 245: ! 246: /* Transmit packet to network */ ! 247: if ( pcap_inject ( hijack->pcap, buf, len ) != len ) { ! 248: logmsg ( LOG_ERR, "write to hijacked port failed: %s\n", ! 249: pcap_geterr ( hijack->pcap ) ); ! 250: return -1; ! 251: } ! 252: ! 253: hijack->tx_count++; ! 254: return len; ! 255: }; ! 256: ! 257: /** ! 258: * Forward data to hijacker ! 259: * ! 260: */ ! 261: static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) { ! 262: struct pcap_pkthdr *pkt_header; ! 263: const unsigned char *pkt_data; ! 264: ssize_t len; ! 265: ! 266: /* Receive packet from network */ ! 267: if ( pcap_next_ex ( hijack->pcap, &pkt_header, &pkt_data ) < 0 ) { ! 268: logmsg ( LOG_ERR, "read from hijacked port failed: %s\n", ! 269: pcap_geterr ( hijack->pcap ) ); ! 270: return -1; ! 271: } ! 272: if ( pkt_header->caplen != pkt_header->len ) { ! 273: logmsg ( LOG_ERR, "read partial packet (%d of %d bytes)\n", ! 274: pkt_header->caplen, pkt_header->len ); ! 275: return -1; ! 276: } ! 277: if ( pkt_header->caplen == 0 ) ! 278: return 0; ! 279: len = pkt_header->caplen; ! 280: ! 281: /* Write packet to hijacker */ ! 282: if ( write ( fd, pkt_data, len ) != len ) { ! 283: logmsg ( LOG_ERR, "write to hijacker failed: %s\n", ! 284: strerror ( errno ) ); ! 285: return -1; ! 286: } ! 287: ! 288: hijack->rx_count++; ! 289: return len; ! 290: }; ! 291: ! 292: ! 293: /** ! 294: * Run hijacker ! 295: * ! 296: */ ! 297: static int run_hijacker ( const char *interface, int fd ) { ! 298: struct hijack hijack; ! 299: fd_set fdset; ! 300: int max_fd; ! 301: ssize_t len; ! 302: ! 303: logmsg ( LOG_INFO, "new connection for %s\n", interface ); ! 304: ! 305: /* Open connection to network */ ! 306: memset ( &hijack, 0, sizeof ( hijack ) ); ! 307: if ( hijack_open ( interface, &hijack ) < 0 ) ! 308: goto err; ! 309: ! 310: /* Do the forwarding */ ! 311: max_fd = ( ( fd > hijack.fd ) ? fd : hijack.fd ); ! 312: while ( 1 ) { ! 313: /* Wait for available data */ ! 314: FD_ZERO ( &fdset ); ! 315: FD_SET ( fd, &fdset ); ! 316: FD_SET ( hijack.fd, &fdset ); ! 317: if ( select ( ( max_fd + 1 ), &fdset, NULL, NULL, 0 ) < 0 ) { ! 318: logmsg ( LOG_ERR, "select failed: %s\n", ! 319: strerror ( errno ) ); ! 320: goto err; ! 321: } ! 322: if ( FD_ISSET ( fd, &fdset ) ) { ! 323: len = forward_from_hijacker ( &hijack, fd ); ! 324: if ( len < 0 ) ! 325: goto err; ! 326: if ( len == 0 ) ! 327: break; ! 328: } ! 329: if ( FD_ISSET ( hijack.fd, &fdset ) ) { ! 330: len = forward_to_hijacker ( fd, &hijack ); ! 331: if ( len < 0 ) ! 332: goto err; ! 333: if ( len == 0 ) ! 334: break; ! 335: } ! 336: } ! 337: ! 338: hijack_close ( &hijack ); ! 339: logmsg ( LOG_INFO, "closed connection for %s\n", interface ); ! 340: logmsg ( LOG_INFO, "received %ld packets, sent %ld packets\n", ! 341: hijack.rx_count, hijack.tx_count ); ! 342: ! 343: return 0; ! 344: ! 345: err: ! 346: if ( hijack.pcap ) ! 347: hijack_close ( &hijack ); ! 348: return -1; ! 349: } ! 350: ! 351: /** ! 352: * Open listener socket ! 353: * ! 354: */ ! 355: static int open_listener ( const char *interface, ! 356: struct hijack_listener *listener ) { ! 357: ! 358: /* Create socket */ ! 359: listener->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 ); ! 360: if ( listener->fd < 0 ) { ! 361: logmsg ( LOG_ERR, "Could not create socket: %s\n", ! 362: strerror ( errno ) ); ! 363: goto err; ! 364: } ! 365: ! 366: /* Bind to local filename */ ! 367: listener->sun.sun_family = AF_UNIX, ! 368: snprintf ( listener->sun.sun_path, sizeof ( listener->sun.sun_path ), ! 369: "/var/run/hijack-%s", interface ); ! 370: if ( bind ( listener->fd, ( struct sockaddr * ) &listener->sun, ! 371: sizeof ( listener->sun ) ) < 0 ) { ! 372: logmsg ( LOG_ERR, "Could not bind socket to %s: %s\n", ! 373: listener->sun.sun_path, strerror ( errno ) ); ! 374: goto err; ! 375: } ! 376: ! 377: /* Set as a listening socket */ ! 378: if ( listen ( listener->fd, 0 ) < 0 ) { ! 379: logmsg ( LOG_ERR, "Could not listen to %s: %s\n", ! 380: listener->sun.sun_path, strerror ( errno ) ); ! 381: goto err; ! 382: } ! 383: ! 384: return 0; ! 385: ! 386: err: ! 387: if ( listener->fd >= 0 ) ! 388: close ( listener->fd ); ! 389: return -1; ! 390: } ! 391: ! 392: /** ! 393: * Listen on listener socket ! 394: * ! 395: */ ! 396: static int listen_for_hijackers ( struct hijack_listener *listener, ! 397: const char *interface ) { ! 398: int fd; ! 399: pid_t child; ! 400: int rc; ! 401: ! 402: logmsg ( LOG_INFO, "Listening on %s\n", listener->sun.sun_path ); ! 403: ! 404: while ( ! signalled ) { ! 405: /* Accept new connection, interruptibly */ ! 406: siginterrupt ( SIGINT, 1 ); ! 407: siginterrupt ( SIGHUP, 1 ); ! 408: fd = accept ( listener->fd, NULL, 0 ); ! 409: siginterrupt ( SIGINT, 0 ); ! 410: siginterrupt ( SIGHUP, 0 ); ! 411: if ( fd < 0 ) { ! 412: if ( errno == EINTR ) { ! 413: continue; ! 414: } else { ! 415: logmsg ( LOG_ERR, "accept failed: %s\n", ! 416: strerror ( errno ) ); ! 417: goto err; ! 418: } ! 419: } ! 420: ! 421: /* Fork child process */ ! 422: child = fork(); ! 423: if ( child < 0 ) { ! 424: logmsg ( LOG_ERR, "fork failed: %s\n", ! 425: strerror ( errno ) ); ! 426: goto err; ! 427: } ! 428: if ( child == 0 ) { ! 429: /* I am the child; run the hijacker */ ! 430: rc = run_hijacker ( interface, fd ); ! 431: close ( fd ); ! 432: exit ( rc ); ! 433: } ! 434: ! 435: close ( fd ); ! 436: } ! 437: ! 438: logmsg ( LOG_INFO, "Stopped listening on %s\n", ! 439: listener->sun.sun_path ); ! 440: return 0; ! 441: ! 442: err: ! 443: if ( fd >= 0 ) ! 444: close ( fd ); ! 445: return -1; ! 446: } ! 447: ! 448: /** ! 449: * Close listener socket ! 450: * ! 451: */ ! 452: static void close_listener ( struct hijack_listener *listener ) { ! 453: close ( listener->fd ); ! 454: unlink ( listener->sun.sun_path ); ! 455: } ! 456: ! 457: /** ! 458: * Print usage ! 459: * ! 460: */ ! 461: static void usage ( char **argv ) { ! 462: logmsg ( LOG_ERR, ! 463: "Usage: %s [options]\n" ! 464: "\n" ! 465: "Options:\n" ! 466: " -h|--help Print this help message\n" ! 467: " -i|--interface intf Use specified network interface\n" ! 468: " -n|--nodaemon Run in foreground\n", ! 469: argv[0] ); ! 470: } ! 471: ! 472: /** ! 473: * Parse command-line options ! 474: * ! 475: */ ! 476: static int parse_options ( int argc, char **argv, ! 477: struct hijack_options *options ) { ! 478: static struct option long_options[] = { ! 479: { "interface", 1, NULL, 'i' }, ! 480: { "nodaemon", 0, NULL, 'n' }, ! 481: { "help", 0, NULL, 'h' }, ! 482: { }, ! 483: }; ! 484: int c; ! 485: ! 486: /* Set default options */ ! 487: memset ( options, 0, sizeof ( *options ) ); ! 488: strncpy ( options->interface, "eth0", sizeof ( options->interface ) ); ! 489: options->daemonise = 1; ! 490: ! 491: /* Parse command-line options */ ! 492: while ( 1 ) { ! 493: int option_index = 0; ! 494: ! 495: c = getopt_long ( argc, argv, "i:hn", long_options, ! 496: &option_index ); ! 497: if ( c < 0 ) ! 498: break; ! 499: ! 500: switch ( c ) { ! 501: case 'i': ! 502: strncpy ( options->interface, optarg, ! 503: sizeof ( options->interface ) ); ! 504: break; ! 505: case 'n': ! 506: options->daemonise = 0; ! 507: break; ! 508: case 'h': ! 509: usage( argv ); ! 510: return -1; ! 511: case '?': ! 512: /* Unrecognised option */ ! 513: return -1; ! 514: default: ! 515: logmsg ( LOG_ERR, "Unrecognised option '-%c'\n", c ); ! 516: return -1; ! 517: } ! 518: } ! 519: ! 520: /* Check there's nothing left over on the command line */ ! 521: if ( optind != argc ) { ! 522: usage ( argv ); ! 523: return -1; ! 524: } ! 525: ! 526: return 0; ! 527: } ! 528: ! 529: /** ! 530: * Daemonise ! 531: * ! 532: */ ! 533: static int daemonise ( const char *interface ) { ! 534: char pidfile[16 + IF_NAMESIZE + 4]; /* "/var/run/hijack-<intf>.pid" */ ! 535: char pid[16]; ! 536: int pidlen; ! 537: int fd = -1; ! 538: ! 539: /* Daemonise */ ! 540: if ( daemon ( 0, 0 ) < 0 ) { ! 541: logmsg ( LOG_ERR, "Could not daemonise: %s\n", ! 542: strerror ( errno ) ); ! 543: goto err; ! 544: } ! 545: daemonised = 1; /* Direct messages to syslog now */ ! 546: ! 547: /* Open pid file */ ! 548: snprintf ( pidfile, sizeof ( pidfile ), "/var/run/hijack-%s.pid", ! 549: interface ); ! 550: fd = open ( pidfile, ( O_WRONLY | O_CREAT | O_TRUNC ), ! 551: ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ); ! 552: if ( fd < 0 ) { ! 553: logmsg ( LOG_ERR, "Could not open %s for writing: %s\n", ! 554: pidfile, strerror ( errno ) ); ! 555: goto err; ! 556: } ! 557: ! 558: /* Write pid to file */ ! 559: pidlen = snprintf ( pid, sizeof ( pid ), "%d\n", getpid() ); ! 560: if ( write ( fd, pid, pidlen ) != pidlen ) { ! 561: logmsg ( LOG_ERR, "Could not write %s: %s\n", ! 562: pidfile, strerror ( errno ) ); ! 563: goto err; ! 564: } ! 565: ! 566: close ( fd ); ! 567: return 0; ! 568: ! 569: err: ! 570: if ( fd >= 0 ) ! 571: close ( fd ); ! 572: return -1; ! 573: } ! 574: ! 575: int main ( int argc, char **argv ) { ! 576: struct hijack_options options; ! 577: struct hijack_listener listener; ! 578: struct sigaction sa; ! 579: ! 580: /* Parse command-line options */ ! 581: if ( parse_options ( argc, argv, &options ) < 0 ) ! 582: exit ( 1 ); ! 583: ! 584: /* Set up syslog connection */ ! 585: openlog ( basename ( argv[0] ), LOG_PID, LOG_DAEMON ); ! 586: ! 587: /* Set up listening socket */ ! 588: if ( open_listener ( options.interface, &listener ) < 0 ) ! 589: exit ( 1 ); ! 590: ! 591: /* Daemonise on demand */ ! 592: if ( options.daemonise ) { ! 593: if ( daemonise ( options.interface ) < 0 ) ! 594: exit ( 1 ); ! 595: } ! 596: ! 597: /* Avoid creating zombies */ ! 598: memset ( &sa, 0, sizeof ( sa ) ); ! 599: sa.sa_handler = SIG_IGN; ! 600: sa.sa_flags = SA_RESTART | SA_NOCLDWAIT; ! 601: if ( sigaction ( SIGCHLD, &sa, NULL ) < 0 ) { ! 602: logmsg ( LOG_ERR, "Could not set SIGCHLD handler: %s", ! 603: strerror ( errno ) ); ! 604: exit ( 1 ); ! 605: } ! 606: ! 607: /* Set 'signalled' flag on SIGINT or SIGHUP */ ! 608: sa.sa_handler = flag_signalled; ! 609: sa.sa_flags = SA_RESTART | SA_RESETHAND; ! 610: if ( sigaction ( SIGINT, &sa, NULL ) < 0 ) { ! 611: logmsg ( LOG_ERR, "Could not set SIGINT handler: %s", ! 612: strerror ( errno ) ); ! 613: exit ( 1 ); ! 614: } ! 615: if ( sigaction ( SIGHUP, &sa, NULL ) < 0 ) { ! 616: logmsg ( LOG_ERR, "Could not set SIGHUP handler: %s", ! 617: strerror ( errno ) ); ! 618: exit ( 1 ); ! 619: } ! 620: ! 621: /* Listen for hijackers */ ! 622: if ( listen_for_hijackers ( &listener, options.interface ) < 0 ) ! 623: exit ( 1 ); ! 624: ! 625: close_listener ( &listener ); ! 626: ! 627: return 0; ! 628: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.