11 #include <net/ethernet.h>
12 #include <sys/select.h>
13 #include <sys/socket.h>
27 unsigned long rx_count;
28 unsigned long tx_count;
31 struct hijack_listener {
32 struct sockaddr_un sun;
36 struct hijack_options {
37 char interface[IF_NAMESIZE];
41 static int daemonised = 0;
43 static int signalled = 0;
45 static void flag_signalled ( int signal __attribute__ (( unused )) ) {
53 static __attribute__ (( format ( printf, 2, 3 ) )) void
54 logmsg ( int level, const char *format, ... ) {
57 va_start ( ap, format );
59 vsyslog ( ( LOG_DAEMON | level ), format, ap );
61 vfprintf ( stderr, format, ap );
70 static int hijack_open ( const char *interface, struct hijack *hijack ) {
71 char errbuf[PCAP_ERRBUF_SIZE];
73 /* Open interface via pcap */
75 hijack->pcap = pcap_open_live ( interface, SNAPLEN, 1, 0, errbuf );
76 if ( ! hijack->pcap ) {
77 logmsg ( LOG_ERR, "Failed to open %s: %s\n",
82 logmsg ( LOG_WARNING, "Warning: %s\n", errbuf );
84 /* Set capture interface to non-blocking mode */
85 if ( pcap_setnonblock ( hijack->pcap, 1, errbuf ) < 0 ) {
86 logmsg ( LOG_ERR, "Could not make %s non-blocking: %s\n",
91 /* Get file descriptor for select() */
92 hijack->fd = pcap_get_selectable_fd ( hijack->pcap );
93 if ( hijack->fd < 0 ) {
94 logmsg ( LOG_ERR, "Cannot get selectable file descriptor "
95 "for %s\n", interface );
99 /* Get link layer type */
100 hijack->datalink = pcap_datalink ( hijack->pcap );
106 pcap_close ( hijack->pcap );
114 static void hijack_close ( struct hijack *hijack ) {
115 pcap_close ( hijack->pcap );
119 * Install filter for hijacked connection
122 static int hijack_install_filter ( struct hijack *hijack,
124 struct bpf_program program;
127 if ( pcap_compile ( hijack->pcap, &program, filter, 1, 0 ) < 0 ) {
128 logmsg ( LOG_ERR, "could not compile filter \"%s\": %s\n",
129 filter, pcap_geterr ( hijack->pcap ) );
134 if ( pcap_setfilter ( hijack->pcap, &program ) < 0 ) {
135 logmsg ( LOG_ERR, "could not install filter \"%s\": %s\n",
136 filter, pcap_geterr ( hijack->pcap ) );
140 logmsg ( LOG_INFO, "using filter \"%s\"\n", filter );
142 pcap_freecode ( &program );
146 pcap_freecode ( &program );
152 * Set up filter for hijacked ethernet connection
155 static int hijack_filter_ethernet ( struct hijack *hijack, const char *buf,
157 char filter[55]; /* see format string */
158 struct ether_header *ether_header = ( struct ether_header * ) buf;
159 unsigned char *hwaddr = ether_header->ether_shost;
161 if ( len < sizeof ( *ether_header ) )
164 snprintf ( filter, sizeof ( filter ), "broadcast or multicast or "
165 "ether host %02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0],
166 hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5] );
168 return hijack_install_filter ( hijack, filter );
172 * Set up filter for hijacked connection
175 static int hijack_filter ( struct hijack *hijack, const char *buf,
177 switch ( hijack->datalink ) {
179 return hijack_filter_ethernet ( hijack, buf, len );
181 logmsg ( LOG_ERR, "unsupported protocol %s: cannot filter\n",
182 ( pcap_datalink_val_to_name ( hijack->datalink ) ?
183 pcap_datalink_val_to_name ( hijack->datalink ) :
185 /* Return success so we don't get called again */
191 * Forward data from hijacker
194 static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) {
198 /* Read packet from hijacker */
199 len = read ( fd, buf, sizeof ( buf ) );
201 logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
202 strerror ( errno ) );
208 /* Set up filter if not already in place */
209 if ( ! hijack->filtered ) {
210 if ( hijack_filter ( hijack, buf, len ) == 0 )
211 hijack->filtered = 1;
214 /* Transmit packet to network */
215 if ( pcap_inject ( hijack->pcap, buf, len ) != len ) {
216 logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
217 pcap_geterr ( hijack->pcap ) );
226 * Forward data to hijacker
229 static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) {
230 struct pcap_pkthdr *pkt_header;
231 const unsigned char *pkt_data;
234 /* Receive packet from network */
235 if ( pcap_next_ex ( hijack->pcap, &pkt_header, &pkt_data ) < 0 ) {
236 logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
237 pcap_geterr ( hijack->pcap ) );
240 if ( pkt_header->caplen != pkt_header->len ) {
241 logmsg ( LOG_ERR, "read partial packet (%d of %d bytes)\n",
242 pkt_header->caplen, pkt_header->len );
245 if ( pkt_header->caplen == 0 )
247 len = pkt_header->caplen;
249 /* Write packet to hijacker */
250 if ( write ( fd, pkt_data, len ) != len ) {
251 logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
252 strerror ( errno ) );
265 static int run_hijacker ( const char *interface, int fd ) {
266 struct hijack hijack;
271 logmsg ( LOG_INFO, "new connection for %s\n", interface );
273 /* Open connection to network */
274 memset ( &hijack, 0, sizeof ( hijack ) );
275 if ( hijack_open ( interface, &hijack ) < 0 )
278 /* Do the forwarding */
279 max_fd = ( ( fd > hijack.fd ) ? fd : hijack.fd );
281 /* Wait for available data */
283 FD_SET ( fd, &fdset );
284 FD_SET ( hijack.fd, &fdset );
285 if ( select ( ( max_fd + 1 ), &fdset, NULL, NULL, 0 ) < 0 ) {
286 logmsg ( LOG_ERR, "select failed: %s\n",
287 strerror ( errno ) );
290 if ( FD_ISSET ( fd, &fdset ) ) {
291 len = forward_from_hijacker ( &hijack, fd );
297 if ( FD_ISSET ( hijack.fd, &fdset ) ) {
298 len = forward_to_hijacker ( fd, &hijack );
306 hijack_close ( &hijack );
307 logmsg ( LOG_INFO, "closed connection for %s\n", interface );
308 logmsg ( LOG_INFO, "received %ld packets, sent %ld packets\n",
309 hijack.rx_count, hijack.tx_count );
315 hijack_close ( &hijack );
320 * Open listener socket
323 static int open_listener ( const char *interface,
324 struct hijack_listener *listener ) {
327 listener->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
328 if ( listener->fd < 0 ) {
329 logmsg ( LOG_ERR, "Could not create socket: %s\n",
330 strerror ( errno ) );
334 /* Bind to local filename */
335 listener->sun.sun_family = AF_UNIX,
336 snprintf ( listener->sun.sun_path, sizeof ( listener->sun.sun_path ),
337 "/var/run/hijack-%s", interface );
338 if ( bind ( listener->fd, ( struct sockaddr * ) &listener->sun,
339 sizeof ( listener->sun ) ) < 0 ) {
340 logmsg ( LOG_ERR, "Could not bind socket to %s: %s\n",
341 listener->sun.sun_path, strerror ( errno ) );
345 /* Set as a listening socket */
346 if ( listen ( listener->fd, 0 ) < 0 ) {
347 logmsg ( LOG_ERR, "Could not listen to %s: %s\n",
348 listener->sun.sun_path, strerror ( errno ) );
355 if ( listener->fd >= 0 )
356 close ( listener->fd );
361 * Listen on listener socket
364 static int listen_for_hijackers ( struct hijack_listener *listener,
365 const char *interface ) {
370 logmsg ( LOG_INFO, "Listening on %s\n", listener->sun.sun_path );
372 while ( ! signalled ) {
373 /* Accept new connection, interruptibly */
374 siginterrupt ( SIGINT, 1 );
375 siginterrupt ( SIGHUP, 1 );
376 fd = accept ( listener->fd, NULL, 0 );
377 siginterrupt ( SIGINT, 0 );
378 siginterrupt ( SIGHUP, 0 );
380 if ( errno == EINTR ) {
383 logmsg ( LOG_ERR, "accept failed: %s\n",
384 strerror ( errno ) );
389 /* Fork child process */
392 logmsg ( LOG_ERR, "fork failed: %s\n",
393 strerror ( errno ) );
397 /* I am the child; run the hijacker */
398 rc = run_hijacker ( interface, fd );
406 logmsg ( LOG_INFO, "Stopped listening on %s\n",
407 listener->sun.sun_path );
417 * Close listener socket
420 static void close_listener ( struct hijack_listener *listener ) {
421 close ( listener->fd );
422 unlink ( listener->sun.sun_path );
429 static void usage ( char **argv ) {
431 "Usage: %s [options]\n"
434 " -h|--help Print this help message\n"
435 " -i|--interface intf Use specified network interface\n"
436 " -n|--nodaemon Run in foreground\n",
441 * Parse command-line options
444 static int parse_options ( int argc, char **argv,
445 struct hijack_options *options ) {
446 static struct option long_options[] = {
447 { "interface", 1, NULL, 'i' },
448 { "nodaemon", 0, NULL, 'n' },
449 { "help", 0, NULL, 'h' },
454 /* Set default options */
455 memset ( options, 0, sizeof ( *options ) );
456 strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
457 options->daemonise = 1;
459 /* Parse command-line options */
461 int option_index = 0;
463 c = getopt_long ( argc, argv, "i:hn", long_options,
470 strncpy ( options->interface, optarg,
471 sizeof ( options->interface ) );
474 options->daemonise = 0;
480 /* Unrecognised option */
483 logmsg ( LOG_ERR, "Unrecognised option '-%c'\n", c );
488 /* Check there's nothing left over on the command line */
489 if ( optind != argc ) {
501 static int daemonise ( const char *interface ) {
502 char pidfile[16 + IF_NAMESIZE + 4]; /* "/var/run/hijack-<intf>.pid" */
508 if ( daemon ( 0, 0 ) < 0 ) {
509 logmsg ( LOG_ERR, "Could not daemonise: %s\n",
510 strerror ( errno ) );
513 daemonised = 1; /* Direct messages to syslog now */
516 snprintf ( pidfile, sizeof ( pidfile ), "/var/run/hijack-%s.pid",
518 fd = open ( pidfile, ( O_WRONLY | O_CREAT | O_TRUNC ),
519 ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) );
521 logmsg ( LOG_ERR, "Could not open %s for writing: %s\n",
522 pidfile, strerror ( errno ) );
526 /* Write pid to file */
527 pidlen = snprintf ( pid, sizeof ( pid ), "%d\n", getpid() );
528 if ( write ( fd, pid, pidlen ) != pidlen ) {
529 logmsg ( LOG_ERR, "Could not write %s: %s\n",
530 pidfile, strerror ( errno ) );
543 int main ( int argc, char **argv ) {
544 struct hijack_options options;
545 struct hijack_listener listener;
548 /* Parse command-line options */
549 if ( parse_options ( argc, argv, &options ) < 0 )
552 /* Set up syslog connection */
553 openlog ( basename ( argv[0] ), LOG_PID, LOG_DAEMON );
555 /* Set up listening socket */
556 if ( open_listener ( options.interface, &listener ) < 0 )
559 /* Daemonise on demand */
560 if ( options.daemonise ) {
561 if ( daemonise ( options.interface ) < 0 )
565 /* Avoid creating zombies */
566 memset ( &sa, 0, sizeof ( sa ) );
567 sa.sa_handler = SIG_IGN;
568 sa.sa_flags = SA_RESTART | SA_NOCLDWAIT;
569 if ( sigaction ( SIGCHLD, &sa, NULL ) < 0 ) {
570 logmsg ( LOG_ERR, "Could not set SIGCHLD handler: %s",
571 strerror ( errno ) );
575 /* Set 'signalled' flag on SIGINT or SIGHUP */
576 sa.sa_handler = flag_signalled;
577 sa.sa_flags = SA_RESTART | SA_RESETHAND;
578 if ( sigaction ( SIGINT, &sa, NULL ) < 0 ) {
579 logmsg ( LOG_ERR, "Could not set SIGINT handler: %s",
580 strerror ( errno ) );
583 if ( sigaction ( SIGHUP, &sa, NULL ) < 0 ) {
584 logmsg ( LOG_ERR, "Could not set SIGHUP handler: %s",
585 strerror ( errno ) );
589 /* Listen for hijackers */
590 if ( listen_for_hijackers ( &listener, options.interface ) < 0 )
593 close_listener ( &listener );