Browse Source

Use libpcap API to send/receive packets.

Include automatic filtering (based on source MAC address of first
transmitted packet).

Proven to successfully elicit a ping response from a remote host.
tags/v0.9.3
Michael Brown 19 years ago
parent
commit
e072baeb8c
1 changed files with 114 additions and 17 deletions
  1. 114
    17
      src/util/hijack.c

+ 114
- 17
src/util/hijack.c View File

@@ -8,6 +8,7 @@
8 8
 #include <libgen.h>
9 9
 #include <signal.h>
10 10
 #include <net/if.h>
11
+#include <net/ethernet.h>
11 12
 #include <sys/select.h>
12 13
 #include <sys/socket.h>
13 14
 #include <sys/stat.h>
@@ -21,6 +22,10 @@
21 22
 struct hijack {
22 23
 	pcap_t *pcap;
23 24
 	int fd;
25
+	int datalink;
26
+	int filtered;
27
+	unsigned long rx_count;
28
+	unsigned long tx_count;
24 29
 };
25 30
 
26 31
 struct hijack_listener {
@@ -39,7 +44,8 @@ static int daemonised = 0;
39 44
  * Log error message
40 45
  *
41 46
  */
42
-static void logmsg ( int level, const char *format, ... ) {
47
+static __attribute__ (( format ( printf, 2, 3 ) )) void
48
+logmsg ( int level, const char *format, ... ) {
43 49
 	va_list ap;
44 50
 
45 51
 	va_start ( ap, format );
@@ -84,6 +90,9 @@ static int hijack_open ( const char *interface, struct hijack *hijack ) {
84 90
 		goto err;
85 91
 	}
86 92
 
93
+	/* Get link layer type */
94
+	hijack->datalink = pcap_datalink ( hijack->pcap );
95
+
87 96
 	return 0;
88 97
 
89 98
  err:
@@ -100,6 +109,78 @@ static void hijack_close ( struct hijack *hijack ) {
100 109
 	pcap_close ( hijack->pcap );
101 110
 }
102 111
 
112
+/**
113
+ * Install filter for hijacked connection
114
+ *
115
+ */
116
+static int hijack_install_filter ( struct hijack *hijack,
117
+				   char *filter ) {
118
+	struct bpf_program program;
119
+
120
+	/* Compile filter */
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 ) );
124
+		goto err_nofree;
125
+	}
126
+
127
+	/* Install filter */
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 ) );
131
+		goto err;
132
+	}
133
+	
134
+	logmsg ( LOG_INFO, "using filter \"%s\"\n", filter );
135
+
136
+	pcap_freecode ( &program );
137
+	return 0;
138
+
139
+ err:	
140
+	pcap_freecode ( &program );
141
+ err_nofree:
142
+	return -1;
143
+}
144
+
145
+/**
146
+ * Set up filter for hijacked ethernet connection
147
+ *
148
+ */
149
+static int hijack_filter_ethernet ( struct hijack *hijack, const char *buf,
150
+				    size_t len ) {
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;
154
+
155
+	if ( len < sizeof ( *ether_header ) )
156
+		return -1;
157
+
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] );
161
+
162
+	return hijack_install_filter ( hijack, filter );
163
+}
164
+
165
+/**
166
+ * Set up filter for hijacked connection
167
+ *
168
+ */
169
+static int hijack_filter ( struct hijack *hijack, const char *buf,
170
+			   size_t len ) {
171
+	switch ( hijack->datalink ) {
172
+	case DLT_EN10MB:
173
+		return hijack_filter_ethernet ( hijack, buf, len );
174
+	default:
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 ) :
178
+			   "UNKNOWN" ) );
179
+		/* Return success so we don't get called again */
180
+		return 0;
181
+	}
182
+}
183
+
103 184
 /**
104 185
  * Forward data from hijacker
105 186
  *
@@ -108,24 +189,30 @@ static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) {
108 189
 	char buf[SNAPLEN];
109 190
 	ssize_t len;
110 191
 
192
+	/* Read packet from hijacker */
111 193
 	len = read ( fd, buf, sizeof ( buf ) );
112 194
 	if ( len < 0 ) {
113 195
 		logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
114 196
 			 strerror ( errno ) );
115 197
 		return -1;
116 198
 	}
117
-
118 199
 	if ( len == 0 )
119 200
 		return 0;
120 201
 
121
-	if ( write ( hijack->fd, buf, len ) != len ) {
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;
206
+	}
207
+
208
+	/* Transmit packet to network */
209
+	if ( pcap_inject ( hijack->pcap, buf, len ) != len ) {
122 210
 		logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
123
-			 strerror ( errno ) );
211
+			 pcap_geterr ( hijack->pcap ) );
124 212
 		return -1;
125 213
 	}
126 214
 
127
-	logmsg ( LOG_INFO, "forwarded %zd bytes from hijacker\n", len );
128
-
215
+	hijack->tx_count++;
129 216
 	return len;
130 217
 };
131 218
 
@@ -134,27 +221,33 @@ static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) {
134 221
  *
135 222
  */
136 223
 static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) {
137
-	char buf[SNAPLEN];
224
+	struct pcap_pkthdr *pkt_header;
225
+	const unsigned char *pkt_data;
138 226
 	ssize_t len;
139 227
 
140
-	len = read ( hijack->fd, buf, sizeof ( buf ) );
141
-	if ( len < 0 ) {
228
+	/* Receive packet from network */
229
+	if ( pcap_next_ex ( hijack->pcap, &pkt_header, &pkt_data ) < 0 ) {
142 230
 		logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
143
-			 strerror ( errno ) );
231
+			 pcap_geterr ( hijack->pcap ) );
144 232
 		return -1;
145 233
 	}
146
-
147
-	if ( len == 0 )
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 );
237
+		return -1;
238
+	}
239
+	if ( pkt_header->caplen == 0 )
148 240
 		return 0;
241
+	len = pkt_header->caplen;
149 242
 
150
-	if ( write ( fd, buf, len ) != len ) {
243
+	/* Write packet to hijacker */
244
+	if ( write ( fd, pkt_data, len ) != len ) {
151 245
 		logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
152 246
 			 strerror ( errno ) );
153 247
 		return -1;
154 248
 	}
155 249
 
156
-	logmsg ( LOG_INFO, "forwarded %zd bytes to hijacker\n", len );
157
-
250
+	hijack->rx_count++;
158 251
 	return len;
159 252
 };
160 253
 
@@ -169,10 +262,10 @@ static int run_hijacker ( const char *interface, int fd ) {
169 262
 	int max_fd;
170 263
 	ssize_t len;
171 264
 
172
-	memset ( &hijack, 0, sizeof ( hijack ) );
173
-
174 265
 	logmsg ( LOG_INFO, "new connection for %s\n", interface );
175 266
 
267
+	/* Open connection to network */
268
+	memset ( &hijack, 0, sizeof ( hijack ) );
176 269
 	if ( hijack_open ( interface, &hijack ) < 0 )
177 270
 		goto err;
178 271
 	
@@ -206,6 +299,8 @@ static int run_hijacker ( const char *interface, int fd ) {
206 299
 
207 300
 	hijack_close ( &hijack );
208 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 );
209 304
 
210 305
 	return 0;
211 306
 
@@ -297,6 +392,8 @@ static int listen_for_hijackers ( struct hijack_listener *listener,
297 392
 	return 0;
298 393
 
299 394
  err:
395
+	if ( fd >= 0 )
396
+		close ( fd );
300 397
 	return -1;
301 398
 }
302 399
 

Loading…
Cancel
Save