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;
47 static __attribute__ (( format ( printf, 2, 3 ) )) void
48 logmsg ( int level, const char *format, ... ) {
51 va_start ( ap, format );
53 vsyslog ( ( LOG_DAEMON | level ), format, ap );
55 vfprintf ( stderr, format, ap );
64 static int hijack_open ( const char *interface, struct hijack *hijack ) {
65 char errbuf[PCAP_ERRBUF_SIZE];
67 /* Open interface via pcap */
69 hijack->pcap = pcap_open_live ( interface, SNAPLEN, 1, 0, errbuf );
70 if ( ! hijack->pcap ) {
71 logmsg ( LOG_ERR, "Failed to open %s: %s\n",
76 logmsg ( LOG_WARNING, "Warning: %s\n", errbuf );
78 /* Set capture interface to non-blocking mode */
79 if ( pcap_setnonblock ( hijack->pcap, 1, errbuf ) < 0 ) {
80 logmsg ( LOG_ERR, "Could not make %s non-blocking: %s\n",
85 /* Get file descriptor for select() */
86 hijack->fd = pcap_get_selectable_fd ( hijack->pcap );
87 if ( hijack->fd < 0 ) {
88 logmsg ( LOG_ERR, "Cannot get selectable file descriptor "
89 "for %s\n", interface );
93 /* Get link layer type */
94 hijack->datalink = pcap_datalink ( hijack->pcap );
100 pcap_close ( hijack->pcap );
108 static void hijack_close ( struct hijack *hijack ) {
109 pcap_close ( hijack->pcap );
113 * Install filter for hijacked connection
116 static int hijack_install_filter ( struct hijack *hijack,
118 struct bpf_program program;
121 if ( pcap_compile ( hijack->pcap, &program, filter, 1, 0 ) < 0 ) {
122 logmsg ( LOG_ERR, "could not compile filter \"%s\": %s\n",
123 filter, pcap_geterr ( hijack->pcap ) );
128 if ( pcap_setfilter ( hijack->pcap, &program ) < 0 ) {
129 logmsg ( LOG_ERR, "could not install filter \"%s\": %s\n",
130 filter, pcap_geterr ( hijack->pcap ) );
134 logmsg ( LOG_INFO, "using filter \"%s\"\n", filter );
136 pcap_freecode ( &program );
140 pcap_freecode ( &program );
146 * Set up filter for hijacked ethernet connection
149 static int hijack_filter_ethernet ( struct hijack *hijack, const char *buf,
151 char filter[55]; /* see format string */
152 struct ether_header *ether_header = ( struct ether_header * ) buf;
153 unsigned char *hwaddr = ether_header->ether_shost;
155 if ( len < sizeof ( *ether_header ) )
158 snprintf ( filter, sizeof ( filter ), "broadcast or multicast or "
159 "ether host %02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0],
160 hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5] );
162 return hijack_install_filter ( hijack, filter );
166 * Set up filter for hijacked connection
169 static int hijack_filter ( struct hijack *hijack, const char *buf,
171 switch ( hijack->datalink ) {
173 return hijack_filter_ethernet ( hijack, buf, len );
175 logmsg ( LOG_ERR, "unsupported protocol %s: cannot filter\n",
176 ( pcap_datalink_val_to_name ( hijack->datalink ) ?
177 pcap_datalink_val_to_name ( hijack->datalink ) :
179 /* Return success so we don't get called again */
185 * Forward data from hijacker
188 static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) {
192 /* Read packet from hijacker */
193 len = read ( fd, buf, sizeof ( buf ) );
195 logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
196 strerror ( errno ) );
202 /* Set up filter if not already in place */
203 if ( ! hijack->filtered ) {
204 if ( hijack_filter ( hijack, buf, len ) == 0 )
205 hijack->filtered = 1;
208 /* Transmit packet to network */
209 if ( pcap_inject ( hijack->pcap, buf, len ) != len ) {
210 logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
211 pcap_geterr ( hijack->pcap ) );
220 * Forward data to hijacker
223 static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) {
224 struct pcap_pkthdr *pkt_header;
225 const unsigned char *pkt_data;
228 /* Receive packet from network */
229 if ( pcap_next_ex ( hijack->pcap, &pkt_header, &pkt_data ) < 0 ) {
230 logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
231 pcap_geterr ( hijack->pcap ) );
234 if ( pkt_header->caplen != pkt_header->len ) {
235 logmsg ( LOG_ERR, "read partial packet (%d of %d bytes)\n",
236 pkt_header->caplen, pkt_header->len );
239 if ( pkt_header->caplen == 0 )
241 len = pkt_header->caplen;
243 /* Write packet to hijacker */
244 if ( write ( fd, pkt_data, len ) != len ) {
245 logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
246 strerror ( errno ) );
259 static int run_hijacker ( const char *interface, int fd ) {
260 struct hijack hijack;
265 logmsg ( LOG_INFO, "new connection for %s\n", interface );
267 /* Open connection to network */
268 memset ( &hijack, 0, sizeof ( hijack ) );
269 if ( hijack_open ( interface, &hijack ) < 0 )
272 /* Do the forwarding */
273 max_fd = ( ( fd > hijack.fd ) ? fd : hijack.fd );
275 /* Wait for available data */
277 FD_SET ( fd, &fdset );
278 FD_SET ( hijack.fd, &fdset );
279 if ( select ( ( max_fd + 1 ), &fdset, NULL, NULL, 0 ) < 0 ) {
280 logmsg ( LOG_ERR, "select failed: %s\n",
281 strerror ( errno ) );
284 if ( FD_ISSET ( fd, &fdset ) ) {
285 len = forward_from_hijacker ( &hijack, fd );
291 if ( FD_ISSET ( hijack.fd, &fdset ) ) {
292 len = forward_to_hijacker ( fd, &hijack );
300 hijack_close ( &hijack );
301 logmsg ( LOG_INFO, "closed connection for %s\n", interface );
302 logmsg ( LOG_INFO, "received %ld packets, sent %ld packets\n",
303 hijack.rx_count, hijack.tx_count );
309 hijack_close ( &hijack );
314 * Open listener socket
317 static int open_listener ( const char *interface,
318 struct hijack_listener *listener ) {
321 listener->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
322 if ( listener->fd < 0 ) {
323 logmsg ( LOG_ERR, "Could not create socket: %s\n",
324 strerror ( errno ) );
328 /* Bind to local filename */
329 listener->sun.sun_family = AF_UNIX,
330 snprintf ( listener->sun.sun_path, sizeof ( listener->sun.sun_path ),
331 "/var/run/hijack-%s", interface );
332 if ( bind ( listener->fd, ( struct sockaddr * ) &listener->sun,
333 sizeof ( listener->sun ) ) < 0 ) {
334 logmsg ( LOG_ERR, "Could not bind socket to %s: %s\n",
335 listener->sun.sun_path, strerror ( errno ) );
339 /* Set as a listening socket */
340 if ( listen ( listener->fd, 0 ) < 0 ) {
341 logmsg ( LOG_ERR, "Could not listen to %s: %s\n",
342 listener->sun.sun_path, strerror ( errno ) );
349 if ( listener->fd >= 0 )
350 close ( listener->fd );
355 * Listen on listener socket
358 static int listen_for_hijackers ( struct hijack_listener *listener,
359 const char *interface ) {
364 logmsg ( LOG_INFO, "Listening on %s\n", listener->sun.sun_path );
367 /* Accept new connection */
368 fd = accept ( listener->fd, NULL, 0 );
370 logmsg ( LOG_ERR, "accept failed: %s\n",
371 strerror ( errno ) );
375 /* Fork child process */
378 logmsg ( LOG_ERR, "fork failed: %s\n",
379 strerror ( errno ) );
383 /* I am the child; run the hijacker */
384 rc = run_hijacker ( interface, fd );
401 * Close listener socket
404 static void close_listener ( struct hijack_listener *listener ) {
405 close ( listener->fd );
406 unlink ( listener->sun.sun_path );
413 static void usage ( char **argv ) {
415 "Usage: %s [options]\n"
418 " -h|--help Print this help message\n"
419 " -i|--interface intf Use specified network interface\n"
420 " -n|--nodaemon Run in foreground\n",
425 * Parse command-line options
428 static int parse_options ( int argc, char **argv,
429 struct hijack_options *options ) {
430 static struct option long_options[] = {
431 { "interface", 1, NULL, 'i' },
432 { "nodaemon", 0, NULL, 'n' },
433 { "help", 0, NULL, 'h' },
438 /* Set default options */
439 memset ( options, 0, sizeof ( *options ) );
440 strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
441 options->daemonise = 1;
443 /* Parse command-line options */
445 int option_index = 0;
447 c = getopt_long ( argc, argv, "i:hn", long_options,
454 strncpy ( options->interface, optarg,
455 sizeof ( options->interface ) );
458 options->daemonise = 0;
464 /* Unrecognised option */
467 logmsg ( LOG_ERR, "Unrecognised option '-%c'\n", c );
472 /* Check there's nothing left over on the command line */
473 if ( optind != argc ) {
485 static int daemonise ( const char *interface ) {
486 char pidfile[16 + IF_NAMESIZE + 4]; /* "/var/run/hijack-<intf>.pid" */
492 if ( daemon ( 0, 0 ) < 0 ) {
493 logmsg ( LOG_ERR, "Could not daemonise: %s\n",
494 strerror ( errno ) );
497 daemonised = 1; /* Direct messages to syslog now */
500 snprintf ( pidfile, sizeof ( pidfile ), "/var/run/hijack-%s.pid",
502 fd = open ( pidfile, ( O_WRONLY | O_CREAT | O_TRUNC ),
503 ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) );
505 logmsg ( LOG_ERR, "Could not open %s for writing: %s\n",
506 pidfile, strerror ( errno ) );
510 /* Write pid to file */
511 pidlen = snprintf ( pid, sizeof ( pid ), "%d\n", getpid() );
512 if ( write ( fd, pid, pidlen ) != pidlen ) {
513 logmsg ( LOG_ERR, "Could not write %s: %s\n",
514 pidfile, strerror ( errno ) );
527 int main ( int argc, char **argv ) {
528 struct hijack_options options;
529 struct hijack_listener listener;
530 struct sigaction sigchld;
532 /* Parse command-line options */
533 if ( parse_options ( argc, argv, &options ) < 0 )
536 /* Set up syslog connection */
537 openlog ( basename ( argv[0] ), LOG_PID, LOG_DAEMON );
539 /* Set up listening socket */
540 if ( open_listener ( options.interface, &listener ) < 0 )
543 /* Daemonise on demand */
544 if ( options.daemonise ) {
545 if ( daemonise ( options.interface ) < 0 )
549 /* Avoid creating zombies */
550 memset ( &sigchld, 0, sizeof ( sigchld ) );
551 sigchld.sa_handler = SIG_IGN;
552 sigchld.sa_flags = SA_NOCLDWAIT;
553 if ( sigaction ( SIGCHLD, &sigchld, NULL ) < 0 ) {
554 logmsg ( LOG_ERR, "Could not set signal handler: %s",
555 strerror ( errno ) );
559 /* Listen for hijackers */
560 if ( listen_for_hijackers ( &listener, options.interface ) < 0 )
563 close_listener ( &listener );