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
 #include <libgen.h>
8
 #include <libgen.h>
9
 #include <signal.h>
9
 #include <signal.h>
10
 #include <net/if.h>
10
 #include <net/if.h>
11
+#include <net/ethernet.h>
11
 #include <sys/select.h>
12
 #include <sys/select.h>
12
 #include <sys/socket.h>
13
 #include <sys/socket.h>
13
 #include <sys/stat.h>
14
 #include <sys/stat.h>
21
 struct hijack {
22
 struct hijack {
22
 	pcap_t *pcap;
23
 	pcap_t *pcap;
23
 	int fd;
24
 	int fd;
25
+	int datalink;
26
+	int filtered;
27
+	unsigned long rx_count;
28
+	unsigned long tx_count;
24
 };
29
 };
25
 
30
 
26
 struct hijack_listener {
31
 struct hijack_listener {
39
  * Log error message
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
 	va_list ap;
49
 	va_list ap;
44
 
50
 
45
 	va_start ( ap, format );
51
 	va_start ( ap, format );
84
 		goto err;
90
 		goto err;
85
 	}
91
 	}
86
 
92
 
93
+	/* Get link layer type */
94
+	hijack->datalink = pcap_datalink ( hijack->pcap );
95
+
87
 	return 0;
96
 	return 0;
88
 
97
 
89
  err:
98
  err:
100
 	pcap_close ( hijack->pcap );
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
  * Forward data from hijacker
185
  * Forward data from hijacker
105
  *
186
  *
108
 	char buf[SNAPLEN];
189
 	char buf[SNAPLEN];
109
 	ssize_t len;
190
 	ssize_t len;
110
 
191
 
192
+	/* Read packet from hijacker */
111
 	len = read ( fd, buf, sizeof ( buf ) );
193
 	len = read ( fd, buf, sizeof ( buf ) );
112
 	if ( len < 0 ) {
194
 	if ( len < 0 ) {
113
 		logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
195
 		logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
114
 			 strerror ( errno ) );
196
 			 strerror ( errno ) );
115
 		return -1;
197
 		return -1;
116
 	}
198
 	}
117
-
118
 	if ( len == 0 )
199
 	if ( len == 0 )
119
 		return 0;
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
 		logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
210
 		logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
123
-			 strerror ( errno ) );
211
+			 pcap_geterr ( hijack->pcap ) );
124
 		return -1;
212
 		return -1;
125
 	}
213
 	}
126
 
214
 
127
-	logmsg ( LOG_INFO, "forwarded %zd bytes from hijacker\n", len );
128
-
215
+	hijack->tx_count++;
129
 	return len;
216
 	return len;
130
 };
217
 };
131
 
218
 
134
  *
221
  *
135
  */
222
  */
136
 static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) {
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
 	ssize_t len;
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
 		logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
230
 		logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
143
-			 strerror ( errno ) );
231
+			 pcap_geterr ( hijack->pcap ) );
144
 		return -1;
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
 		return 0;
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
 		logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
245
 		logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
152
 			 strerror ( errno ) );
246
 			 strerror ( errno ) );
153
 		return -1;
247
 		return -1;
154
 	}
248
 	}
155
 
249
 
156
-	logmsg ( LOG_INFO, "forwarded %zd bytes to hijacker\n", len );
157
-
250
+	hijack->rx_count++;
158
 	return len;
251
 	return len;
159
 };
252
 };
160
 
253
 
169
 	int max_fd;
262
 	int max_fd;
170
 	ssize_t len;
263
 	ssize_t len;
171
 
264
 
172
-	memset ( &hijack, 0, sizeof ( hijack ) );
173
-
174
 	logmsg ( LOG_INFO, "new connection for %s\n", interface );
265
 	logmsg ( LOG_INFO, "new connection for %s\n", interface );
175
 
266
 
267
+	/* Open connection to network */
268
+	memset ( &hijack, 0, sizeof ( hijack ) );
176
 	if ( hijack_open ( interface, &hijack ) < 0 )
269
 	if ( hijack_open ( interface, &hijack ) < 0 )
177
 		goto err;
270
 		goto err;
178
 	
271
 	
206
 
299
 
207
 	hijack_close ( &hijack );
300
 	hijack_close ( &hijack );
208
 	logmsg ( LOG_INFO, "closed connection for %s\n", interface );
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
 	return 0;
305
 	return 0;
211
 
306
 
297
 	return 0;
392
 	return 0;
298
 
393
 
299
  err:
394
  err:
395
+	if ( fd >= 0 )
396
+		close ( fd );
300
 	return -1;
397
 	return -1;
301
 }
398
 }
302
 
399
 

Loading…
Cancel
Save