|
@@ -0,0 +1,338 @@
|
|
1
|
+#include <stdio.h>
|
|
2
|
+#include <stdlib.h>
|
|
3
|
+#include <unistd.h>
|
|
4
|
+#include <string.h>
|
|
5
|
+#include <errno.h>
|
|
6
|
+#include <time.h>
|
|
7
|
+#include <sys/socket.h>
|
|
8
|
+#include <sys/un.h>
|
|
9
|
+#include <net/if.h>
|
|
10
|
+#include <net/ethernet.h>
|
|
11
|
+#include <netinet/in.h>
|
|
12
|
+#include <getopt.h>
|
|
13
|
+
|
|
14
|
+typedef int irq_action_t;
|
|
15
|
+
|
|
16
|
+struct nic {
|
|
17
|
+ struct nic_operations *nic_op;
|
|
18
|
+ unsigned char *node_addr;
|
|
19
|
+ unsigned char *packet;
|
|
20
|
+ unsigned int packetlen;
|
|
21
|
+ void *priv_data; /* driver private data */
|
|
22
|
+};
|
|
23
|
+
|
|
24
|
+struct nic_operations {
|
|
25
|
+ int ( *connect ) ( struct nic * );
|
|
26
|
+ int ( *poll ) ( struct nic *, int retrieve );
|
|
27
|
+ void ( *transmit ) ( struct nic *, const char *,
|
|
28
|
+ unsigned int, unsigned int, const char * );
|
|
29
|
+ void ( *irq ) ( struct nic *, irq_action_t );
|
|
30
|
+};
|
|
31
|
+
|
|
32
|
+/*****************************************************************************
|
|
33
|
+ *
|
|
34
|
+ * Hijack device interface
|
|
35
|
+ *
|
|
36
|
+ * This requires a hijack daemon to be running
|
|
37
|
+ *
|
|
38
|
+ */
|
|
39
|
+
|
|
40
|
+struct hijack {
|
|
41
|
+ int fd;
|
|
42
|
+};
|
|
43
|
+
|
|
44
|
+struct hijack_device {
|
|
45
|
+ char *name;
|
|
46
|
+};
|
|
47
|
+
|
|
48
|
+static int hijack_poll ( struct nic *nic, int retrieve ) {
|
|
49
|
+ struct hijack *hijack = nic->priv_data;
|
|
50
|
+ fd_set fdset;
|
|
51
|
+ struct timeval tv;
|
|
52
|
+ int ready;
|
|
53
|
+ ssize_t len;
|
|
54
|
+
|
|
55
|
+ /* Poll for data */
|
|
56
|
+ FD_ZERO ( &fdset );
|
|
57
|
+ FD_SET ( hijack->fd, &fdset );
|
|
58
|
+ tv.tv_sec = 0;
|
|
59
|
+ tv.tv_usec = 500; /* 500us to avoid hogging CPU */
|
|
60
|
+ ready = select ( ( hijack->fd + 1 ), &fdset, NULL, NULL, &tv );
|
|
61
|
+ if ( ready < 0 ) {
|
|
62
|
+ fprintf ( stderr, "select() failed: %s\n",
|
|
63
|
+ strerror ( errno ) );
|
|
64
|
+ return 0;
|
|
65
|
+ }
|
|
66
|
+ if ( ready == 0 )
|
|
67
|
+ return 0;
|
|
68
|
+
|
|
69
|
+ /* Return if we're not retrieving data yet */
|
|
70
|
+ if ( ! retrieve )
|
|
71
|
+ return 1;
|
|
72
|
+
|
|
73
|
+ /* Fetch data */
|
|
74
|
+ len = read ( hijack->fd, nic->packet, ETH_FRAME_LEN );
|
|
75
|
+ if ( len < 0 ) {
|
|
76
|
+ fprintf ( stderr, "read() failed: %s\n",
|
|
77
|
+ strerror ( errno ) );
|
|
78
|
+ return 0;
|
|
79
|
+ }
|
|
80
|
+ nic->packetlen = len;
|
|
81
|
+
|
|
82
|
+ return 1;
|
|
83
|
+}
|
|
84
|
+
|
|
85
|
+static void hijack_transmit ( struct nic *nic, const char *dest,
|
|
86
|
+ unsigned int type, unsigned int size,
|
|
87
|
+ const char *packet ) {
|
|
88
|
+ struct hijack *hijack = nic->priv_data;
|
|
89
|
+ unsigned int nstype = htons ( type );
|
|
90
|
+ unsigned int total_size = ETH_HLEN + size;
|
|
91
|
+ char txbuf[ total_size ];
|
|
92
|
+
|
|
93
|
+ /* Build packet header */
|
|
94
|
+ memcpy ( txbuf, dest, ETH_ALEN );
|
|
95
|
+ memcpy ( txbuf + ETH_ALEN, nic->node_addr, ETH_ALEN );
|
|
96
|
+ memcpy ( txbuf + 2 * ETH_ALEN, &nstype, 2 );
|
|
97
|
+ memcpy ( txbuf + ETH_HLEN, packet, size );
|
|
98
|
+
|
|
99
|
+ /* Transmit data */
|
|
100
|
+ if ( write ( hijack->fd, txbuf, total_size ) != total_size ) {
|
|
101
|
+ fprintf ( stderr, "write() failed: %s\n",
|
|
102
|
+ strerror ( errno ) );
|
|
103
|
+ }
|
|
104
|
+}
|
|
105
|
+
|
|
106
|
+static int hijack_connect ( struct nic *nic ) {
|
|
107
|
+ return 1;
|
|
108
|
+}
|
|
109
|
+
|
|
110
|
+static void hijack_irq ( struct nic *nic, irq_action_t action ) {
|
|
111
|
+ /* Do nothing */
|
|
112
|
+}
|
|
113
|
+
|
|
114
|
+static struct nic_operations hijack_operations = {
|
|
115
|
+ .connect = hijack_connect,
|
|
116
|
+ .transmit = hijack_transmit,
|
|
117
|
+ .poll = hijack_poll,
|
|
118
|
+ .irq = hijack_irq,
|
|
119
|
+};
|
|
120
|
+
|
|
121
|
+static int hijack_probe ( struct nic *nic, struct hijack_device *hijack_dev ) {
|
|
122
|
+ static struct hijack hijack;
|
|
123
|
+ struct sockaddr_un sun;
|
|
124
|
+ int i;
|
|
125
|
+
|
|
126
|
+ memset ( &hijack, 0, sizeof ( hijack ) );
|
|
127
|
+
|
|
128
|
+ /* Create socket */
|
|
129
|
+ hijack.fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
|
|
130
|
+ if ( hijack.fd < 0 ) {
|
|
131
|
+ fprintf ( stderr, "socket() failed: %s\n",
|
|
132
|
+ strerror ( errno ) );
|
|
133
|
+ goto err;
|
|
134
|
+ }
|
|
135
|
+
|
|
136
|
+ /* Connect to hijack daemon */
|
|
137
|
+ sun.sun_family = AF_UNIX;
|
|
138
|
+ snprintf ( sun.sun_path, sizeof ( sun.sun_path ), "/var/run/hijack-%s",
|
|
139
|
+ hijack_dev->name );
|
|
140
|
+ if ( connect ( hijack.fd, ( struct sockaddr * ) &sun,
|
|
141
|
+ sizeof ( sun ) ) < 0 ) {
|
|
142
|
+ fprintf ( stderr, "could not connect to %s: %s\n",
|
|
143
|
+ sun.sun_path, strerror ( errno ) );
|
|
144
|
+ goto err;
|
|
145
|
+ }
|
|
146
|
+
|
|
147
|
+ /* Generate MAC address */
|
|
148
|
+ srand ( time ( NULL ) );
|
|
149
|
+ for ( i = 0 ; i < ETH_ALEN ; i++ ) {
|
|
150
|
+ nic->node_addr[i] = ( rand() & 0xff );
|
|
151
|
+ }
|
|
152
|
+ nic->node_addr[0] &= 0xfe; /* clear multicast bit */
|
|
153
|
+ nic->node_addr[0] |= 0x02; /* set "locally-assigned" bit */
|
|
154
|
+
|
|
155
|
+ nic->priv_data = &hijack;
|
|
156
|
+ nic->nic_op = &hijack_operations;
|
|
157
|
+ return 1;
|
|
158
|
+
|
|
159
|
+ err:
|
|
160
|
+ if ( hijack.fd >= 0 )
|
|
161
|
+ close ( hijack.fd );
|
|
162
|
+ return 0;
|
|
163
|
+}
|
|
164
|
+
|
|
165
|
+static void hijack_disable ( struct nic *nic,
|
|
166
|
+ struct hijack_device *hijack_dev ) {
|
|
167
|
+ struct hijack *hijack = nic->priv_data;
|
|
168
|
+
|
|
169
|
+ close ( hijack->fd );
|
|
170
|
+}
|
|
171
|
+
|
|
172
|
+/*****************************************************************************
|
|
173
|
+ *
|
|
174
|
+ * Parse command-line options
|
|
175
|
+ *
|
|
176
|
+ */
|
|
177
|
+
|
|
178
|
+struct tester_options {
|
|
179
|
+ char interface[IF_NAMESIZE];
|
|
180
|
+};
|
|
181
|
+
|
|
182
|
+static void usage ( char **argv ) {
|
|
183
|
+ fprintf ( stderr,
|
|
184
|
+ "Usage: %s [options]\n"
|
|
185
|
+ "\n"
|
|
186
|
+ "Options:\n"
|
|
187
|
+ " -h|--help Print this help message\n"
|
|
188
|
+ " -i|--interface intf Use specified network interface\n",
|
|
189
|
+ argv[0] );
|
|
190
|
+}
|
|
191
|
+
|
|
192
|
+static int parse_options ( int argc, char **argv,
|
|
193
|
+ struct tester_options *options ) {
|
|
194
|
+ static struct option long_options[] = {
|
|
195
|
+ { "interface", 1, NULL, 'i' },
|
|
196
|
+ { "help", 0, NULL, 'h' },
|
|
197
|
+ { },
|
|
198
|
+ };
|
|
199
|
+ int c;
|
|
200
|
+
|
|
201
|
+ /* Set default options */
|
|
202
|
+ memset ( options, 0, sizeof ( *options ) );
|
|
203
|
+ strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
|
|
204
|
+
|
|
205
|
+ /* Parse command-line options */
|
|
206
|
+ while ( 1 ) {
|
|
207
|
+ int option_index = 0;
|
|
208
|
+
|
|
209
|
+ c = getopt_long ( argc, argv, "i:h", long_options,
|
|
210
|
+ &option_index );
|
|
211
|
+ if ( c < 0 )
|
|
212
|
+ break;
|
|
213
|
+
|
|
214
|
+ switch ( c ) {
|
|
215
|
+ case 'i':
|
|
216
|
+ strncpy ( options->interface, optarg,
|
|
217
|
+ sizeof ( options->interface ) );
|
|
218
|
+ break;
|
|
219
|
+ case 'h':
|
|
220
|
+ usage( argv );
|
|
221
|
+ return -1;
|
|
222
|
+ case '?':
|
|
223
|
+ /* Unrecognised option */
|
|
224
|
+ return -1;
|
|
225
|
+ default:
|
|
226
|
+ fprintf ( stderr, "Unrecognised option '-%c'\n", c );
|
|
227
|
+ return -1;
|
|
228
|
+ }
|
|
229
|
+ }
|
|
230
|
+
|
|
231
|
+ /* Check there's nothing left over on the command line */
|
|
232
|
+ if ( optind != argc ) {
|
|
233
|
+ usage ( argv );
|
|
234
|
+ return -1;
|
|
235
|
+ }
|
|
236
|
+
|
|
237
|
+ return 0;
|
|
238
|
+}
|
|
239
|
+
|
|
240
|
+/*****************************************************************************
|
|
241
|
+ *
|
|
242
|
+ * uIP wrapper layer
|
|
243
|
+ *
|
|
244
|
+ */
|
|
245
|
+
|
|
246
|
+#include "../proto/uip/uip.h"
|
|
247
|
+#include "../proto/uip/uip_arp.h"
|
|
248
|
+
|
|
249
|
+static int done;
|
|
250
|
+
|
|
251
|
+void UIP_APPCALL ( void ) {
|
|
252
|
+ printf ( "appcall\n" );
|
|
253
|
+}
|
|
254
|
+
|
|
255
|
+void udp_appcall ( void ) {
|
|
256
|
+}
|
|
257
|
+
|
|
258
|
+static void uip_transmit ( struct nic *nic ) {
|
|
259
|
+ uip_arp_out();
|
|
260
|
+ nic->nic_op->transmit ( nic, ( char * ) uip_buf,
|
|
261
|
+ ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) ),
|
|
262
|
+ uip_len - ETH_HLEN,
|
|
263
|
+ ( char * ) uip_buf + ETH_HLEN );
|
|
264
|
+ uip_len = 0;
|
|
265
|
+}
|
|
266
|
+
|
|
267
|
+static void run_stack ( struct nic *nic ) {
|
|
268
|
+ struct uip_eth_addr hwaddr;
|
|
269
|
+ u16_t ipaddr[2];
|
|
270
|
+ uint16_t type;
|
|
271
|
+ int i;
|
|
272
|
+
|
|
273
|
+ uip_init();
|
|
274
|
+ uip_arp_init();
|
|
275
|
+ memcpy ( &hwaddr, nic->node_addr, sizeof ( hwaddr ) );
|
|
276
|
+ uip_setethaddr ( hwaddr );
|
|
277
|
+
|
|
278
|
+ uip_ipaddr(ipaddr, 192,168,0,1);
|
|
279
|
+ uip_connect(ipaddr, HTONS(80));
|
|
280
|
+
|
|
281
|
+ done = 0;
|
|
282
|
+ while ( ! done ) {
|
|
283
|
+ if ( nic->nic_op->poll ( nic, 1 ) ) {
|
|
284
|
+ /* We have data */
|
|
285
|
+ memcpy ( uip_buf, nic->packet, nic->packetlen );
|
|
286
|
+ uip_len = nic->packetlen;
|
|
287
|
+ type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) );
|
|
288
|
+ if ( type == ETHERTYPE_ARP ) {
|
|
289
|
+ uip_arp_arpin();
|
|
290
|
+ } else {
|
|
291
|
+ uip_arp_ipin();
|
|
292
|
+ uip_input();
|
|
293
|
+ }
|
|
294
|
+ if ( uip_len > 0 )
|
|
295
|
+ uip_transmit ( nic );
|
|
296
|
+ } else {
|
|
297
|
+ for ( i = 0 ; i < UIP_CONNS ; i++ ) {
|
|
298
|
+ uip_periodic ( i );
|
|
299
|
+ if ( uip_len > 0 )
|
|
300
|
+ uip_transmit ( nic );
|
|
301
|
+ }
|
|
302
|
+ }
|
|
303
|
+ }
|
|
304
|
+}
|
|
305
|
+
|
|
306
|
+/*****************************************************************************
|
|
307
|
+ *
|
|
308
|
+ * Main program
|
|
309
|
+ *
|
|
310
|
+ */
|
|
311
|
+
|
|
312
|
+int main ( int argc, char **argv ) {
|
|
313
|
+ struct tester_options options;
|
|
314
|
+ struct hijack_device hijack_dev;
|
|
315
|
+ static unsigned char node_addr[ETH_ALEN];
|
|
316
|
+ static unsigned char packet[ETH_FRAME_LEN];
|
|
317
|
+ struct nic nic = {
|
|
318
|
+ .node_addr = node_addr,
|
|
319
|
+ .packet = packet,
|
|
320
|
+ };
|
|
321
|
+
|
|
322
|
+ /* Parse command-line options */
|
|
323
|
+ if ( parse_options ( argc, argv, &options ) < 0 )
|
|
324
|
+ exit ( 1 );
|
|
325
|
+
|
|
326
|
+ /* Open the hijack device */
|
|
327
|
+ hijack_dev.name = options.interface;
|
|
328
|
+ if ( ! hijack_probe ( &nic, &hijack_dev ) )
|
|
329
|
+ exit ( 1 );
|
|
330
|
+
|
|
331
|
+ /* Run the stack to completion */
|
|
332
|
+ run_stack ( &nic );
|
|
333
|
+
|
|
334
|
+ /* Close the hijack device */
|
|
335
|
+ hijack_disable ( &nic, &hijack_dev );
|
|
336
|
+
|
|
337
|
+ return 0;
|
|
338
|
+}
|