11 #include <net/ethernet.h>
12 #include <sys/select.h>
13 #include <sys/socket.h>
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.
27 #define HAVE_PCAP_INJECT 0
34 unsigned long rx_count
;
35 unsigned long tx_count
;
38 struct hijack_listener
{
39 struct sockaddr_un sun
;
43 struct hijack_options
{
44 char interface
[IF_NAMESIZE
];
48 static int daemonised
= 0;
50 static int signalled
= 0;
52 static void flag_signalled ( int signal
__attribute__ (( unused
)) ) {
56 #if ! HAVE_PCAP_INJECT
58 * Substitute for pcap_inject(), if this version of libpcap doesn't
59 * have it. Will almost certainly only work under Linux.
62 int pcap_inject ( pcap_t
*pcap
, const void *data
, size_t len
) {
64 char *errbuf
= pcap_geterr ( pcap
);
66 fd
= pcap_get_selectable_fd ( pcap
);
68 snprintf ( errbuf
, PCAP_ERRBUF_SIZE
,
69 "could not get file descriptor" );
72 if ( write ( fd
, data
, len
) != len
) {
73 snprintf ( errbuf
, PCAP_ERRBUF_SIZE
,
74 "could not write data: %s", strerror ( errno
) );
79 #endif /* ! HAVE_PCAP_INJECT */
85 static __attribute__ (( format ( printf
, 2, 3 ) )) void
86 logmsg ( int level
, const char *format
, ... ) {
89 va_start ( ap
, format
);
91 vsyslog ( ( LOG_DAEMON
| level
), format
, ap
);
93 vfprintf ( stderr
, format
, ap
);
102 static int hijack_open ( const char *interface
, struct hijack
*hijack
) {
103 char errbuf
[PCAP_ERRBUF_SIZE
];
105 /* Open interface via pcap */
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",
114 logmsg ( LOG_WARNING
, "Warning: %s\n", errbuf
);
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",
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
);
131 /* Get link layer type */
132 hijack
->datalink
= pcap_datalink ( hijack
->pcap
);
138 pcap_close ( hijack
->pcap
);
146 static void hijack_close ( struct hijack
*hijack
) {
147 pcap_close ( hijack
->pcap
);
151 * Install filter for hijacked connection
154 static int hijack_install_filter ( struct hijack
*hijack
,
156 struct bpf_program program
;
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
) );
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
) );
172 logmsg ( LOG_INFO
, "using filter \"%s\"\n", filter
);
174 pcap_freecode ( &program
);
178 pcap_freecode ( &program
);
184 * Set up filter for hijacked ethernet connection
187 static int hijack_filter_ethernet ( struct hijack
*hijack
, const char *buf
,
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
;
193 if ( len
< sizeof ( *ether_header
) )
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] );
200 return hijack_install_filter ( hijack
, filter
);
204 * Set up filter for hijacked connection
207 static int hijack_filter ( struct hijack
*hijack
, const char *buf
,
209 switch ( hijack
->datalink
) {
211 return hijack_filter_ethernet ( hijack
, buf
, len
);
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
) :
217 /* Return success so we don't get called again */
223 * Forward data from hijacker
226 static ssize_t
forward_from_hijacker ( struct hijack
*hijack
, int fd
) {
230 /* Read packet from hijacker */
231 len
= read ( fd
, buf
, sizeof ( buf
) );
233 logmsg ( LOG_ERR
, "read from hijacker failed: %s\n",
234 strerror ( errno
) );
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;
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
) );
258 * Forward data to hijacker
261 static ssize_t
forward_to_hijacker ( int fd
, struct hijack
*hijack
) {
262 struct pcap_pkthdr
*pkt_header
;
263 const unsigned char *pkt_data
;
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
) );
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
);
277 if ( pkt_header
->caplen
== 0 )
279 len
= pkt_header
->caplen
;
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
) );
297 static int run_hijacker ( const char *interface
, int fd
) {
298 struct hijack hijack
;
303 logmsg ( LOG_INFO
, "new connection for %s\n", interface
);
305 /* Open connection to network */
306 memset ( &hijack
, 0, sizeof ( hijack
) );
307 if ( hijack_open ( interface
, &hijack
) < 0 )
310 /* Do the forwarding */
311 max_fd
= ( ( fd
> hijack
.fd
) ? fd
: hijack
.fd
);
313 /* Wait for available data */
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
) );
322 if ( FD_ISSET ( fd
, &fdset
) ) {
323 len
= forward_from_hijacker ( &hijack
, fd
);
329 if ( FD_ISSET ( hijack
.fd
, &fdset
) ) {
330 len
= forward_to_hijacker ( fd
, &hijack
);
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
);
347 hijack_close ( &hijack
);
352 * Open listener socket
355 static int open_listener ( const char *interface
,
356 struct hijack_listener
*listener
) {
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
) );
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
) );
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
) );
387 if ( listener
->fd
>= 0 )
388 close ( listener
->fd
);
393 * Listen on listener socket
396 static int listen_for_hijackers ( struct hijack_listener
*listener
,
397 const char *interface
) {
402 logmsg ( LOG_INFO
, "Listening on %s\n", listener
->sun
.sun_path
);
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 );
412 if ( errno
== EINTR
) {
415 logmsg ( LOG_ERR
, "accept failed: %s\n",
416 strerror ( errno
) );
421 /* Fork child process */
424 logmsg ( LOG_ERR
, "fork failed: %s\n",
425 strerror ( errno
) );
429 /* I am the child; run the hijacker */
430 rc
= run_hijacker ( interface
, fd
);
438 logmsg ( LOG_INFO
, "Stopped listening on %s\n",
439 listener
->sun
.sun_path
);
449 * Close listener socket
452 static void close_listener ( struct hijack_listener
*listener
) {
453 close ( listener
->fd
);
454 unlink ( listener
->sun
.sun_path
);
461 static void usage ( char **argv
) {
463 "Usage: %s [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",
473 * Parse command-line options
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' },
486 /* Set default options */
487 memset ( options
, 0, sizeof ( *options
) );
488 strncpy ( options
->interface
, "eth0", sizeof ( options
->interface
) );
489 options
->daemonise
= 1;
491 /* Parse command-line options */
493 int option_index
= 0;
495 c
= getopt_long ( argc
, argv
, "i:hn", long_options
,
502 strncpy ( options
->interface
, optarg
,
503 sizeof ( options
->interface
) );
506 options
->daemonise
= 0;
512 /* Unrecognised option */
515 logmsg ( LOG_ERR
, "Unrecognised option '-%c'\n", c
);
520 /* Check there's nothing left over on the command line */
521 if ( optind
!= argc
) {
533 static int daemonise ( const char *interface
) {
534 char pidfile
[16 + IF_NAMESIZE
+ 4]; /* "/var/run/hijack-<intf>.pid" */
540 if ( daemon ( 0, 0 ) < 0 ) {
541 logmsg ( LOG_ERR
, "Could not daemonise: %s\n",
542 strerror ( errno
) );
545 daemonised
= 1; /* Direct messages to syslog now */
548 snprintf ( pidfile
, sizeof ( pidfile
), "/var/run/hijack-%s.pid",
550 fd
= open ( pidfile
, ( O_WRONLY
| O_CREAT
| O_TRUNC
),
551 ( S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
) );
553 logmsg ( LOG_ERR
, "Could not open %s for writing: %s\n",
554 pidfile
, strerror ( errno
) );
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
) );
575 int main ( int argc
, char **argv
) {
576 struct hijack_options options
;
577 struct hijack_listener listener
;
580 /* Parse command-line options */
581 if ( parse_options ( argc
, argv
, &options
) < 0 )
584 /* Set up syslog connection */
585 openlog ( basename ( argv
[0] ), LOG_PID
, LOG_DAEMON
);
587 /* Set up listening socket */
588 if ( open_listener ( options
.interface
, &listener
) < 0 )
591 /* Daemonise on demand */
592 if ( options
.daemonise
) {
593 if ( daemonise ( options
.interface
) < 0 )
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
) );
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
) );
615 if ( sigaction ( SIGHUP
, &sa
, NULL
) < 0 ) {
616 logmsg ( LOG_ERR
, "Could not set SIGHUP handler: %s",
617 strerror ( errno
) );
621 /* Listen for hijackers */
622 if ( listen_for_hijackers ( &listener
, options
.interface
) < 0 )
625 close_listener ( &listener
);