2 * Copyright (c) 2003 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <arpa/inet.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
55 #include "base/cprintf.hh"
57 #define panic(arg...) \
58 do { cprintf("Panic: " arg); exit(1); } while (0)
60 char *program
= "ethertap";
66 "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
67 "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
73 #define DPRINTF(args...) do { \
78 #define DDUMP(args...) do { \
80 dump((const u_char *)args); \
84 dump(const u_char
*data
, int len
)
88 for (i
= 0; i
< len
; i
+= 16) {
93 for (j
= 0; j
< c
; j
++) {
94 cprintf("%02x ", data
[i
+ j
] & 0xff);
95 if ((j
& 0xf) == 7 && j
> 0)
103 for (j
= 0; j
< c
; j
++) {
104 int ch
= data
[i
+ j
] & 0x7f;
105 cprintf("%c", (char)(isprint(ch
) ? ch
: ' '));
117 quit_now(int sigtype
)
119 DPRINTF("User requested exit\n");
127 int fd
= ::socket(PF_INET
, SOCK_STREAM
, 0);
129 panic("Can't create socket!\n");
133 if (::setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&i
,
135 panic("setsockopt() SO_REUSEADDR failed!\n");
142 Listen(int fd
, int port
)
144 struct sockaddr_in sockaddr
;
145 sockaddr
.sin_family
= PF_INET
;
146 sockaddr
.sin_addr
.s_addr
= INADDR_ANY
;
148 sockaddr
.sin_port
= htons(port
);
149 int ret
= ::bind(fd
, (struct sockaddr
*)&sockaddr
, sizeof (sockaddr
));
151 panic("bind() failed!\n");
153 if (::listen(fd
, 1) == -1)
154 panic("listen() failed!\n");
157 // Open a connection. Accept will block, so if you don't want it to,
158 // make sure a connection is ready before you call accept.
160 Accept(int fd
, bool nodelay
)
162 struct sockaddr_in sockaddr
;
163 socklen_t slen
= sizeof (sockaddr
);
164 int sfd
= ::accept(fd
, (struct sockaddr
*)&sockaddr
, &slen
);
166 panic("accept() failed!\n");
170 ::setsockopt(sfd
, IPPROTO_TCP
, TCP_NODELAY
, (char *)&i
, sizeof(i
));
176 Connect(int fd
, const string
&host
, int port
)
178 struct sockaddr_in sockaddr
;
179 if (::inet_aton(host
.c_str(), &sockaddr
.sin_addr
) == 0) {
181 hp
= ::gethostbyname(host
.c_str());
183 panic("Host %s not found\n", host
);
185 sockaddr
.sin_family
= hp
->h_addrtype
;
186 memcpy(&sockaddr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
189 sockaddr
.sin_port
= htons(port
);
190 if (::connect(fd
, (struct sockaddr
*)&sockaddr
, sizeof(sockaddr
)) != 0)
191 panic("could not connect to %s on port %d\n", host
, port
);
193 DPRINTF("connected to %s on port %d\n", host
, port
);
197 main(int argc
, char *argv
[])
201 bool listening
= false;
208 program
= basename(argv
[0]);
210 while ((c
= getopt(argc
, argv
, "b:df:lp:v")) != -1) {
213 bufsize
= atoi(optarg
);
236 signal(SIGINT
, quit_now
);
237 signal(SIGTERM
, quit_now
);
238 signal(SIGHUP
, quit_now
);
244 panic("Fork failed\n");
252 char *buffer
= new char[bufsize
];
271 char errbuf
[PCAP_ERRBUF_SIZE
];
272 memset(errbuf
, 0, sizeof errbuf
);
273 pcap_t
*pcap
= pcap_open_live(device
, 1500, 1, -1, errbuf
);
275 panic("pcap_open_live failed: %s\n", errbuf
);
279 bpf_u_int32 localnet
, netmask
;
280 if (pcap_lookupnet(device
, &localnet
, &netmask
, errbuf
) == -1) {
281 DPRINTF("pcap_lookupnet failed: %s\n", errbuf
);
282 netmask
= 0xffffff00;
285 if (pcap_compile(pcap
, &program
, filter
, 1, netmask
) == -1)
286 panic("pcap_compile failed, invalid filter:\n%s\n", filter
);
288 if (pcap_setfilter(pcap
, &program
) == -1)
289 panic("pcap_setfilter failed\n");
292 eth_t
*ethernet
= eth_open(device
);
294 panic("cannot open the ethernet device for writing\n");
297 pfds
[0].fd
= Socket(true);
298 pfds
[0].events
= POLLIN
;
302 Listen(pfds
[0].fd
, port
);
304 Connect(pfds
[0].fd
, host
, port
);
306 pfds
[1].fd
= pcap_fileno(pcap
);
307 pfds
[1].events
= POLLIN
;
311 pfds
[2].events
= POLLIN
|POLLERR
;
314 pollfd
*listen_pfd
= listening
? &pfds
[0] : NULL
;
315 pollfd
*tap_pfd
= &pfds
[1];
316 pollfd
*client_pfd
= listening
? NULL
: &pfds
[0];
319 int32_t buffer_offset
= 0;
320 int32_t data_len
= 0;
322 DPRINTF("Begin poll loop\n");
324 int ret
= ::poll(pfds
, npfds
, INFTIM
);
328 if (listen_pfd
&& listen_pfd
->revents
) {
329 if (listen_pfd
->revents
& POLLIN
) {
330 int fd
= Accept(listen_pfd
->fd
, false);
332 DPRINTF("Connection rejected\n");
335 DPRINTF("Connection accepted\n");
336 client_pfd
= &pfds
[2];
341 listen_pfd
->revents
= 0;
344 if (tap_pfd
&& tap_pfd
->revents
) {
345 if (tap_pfd
->revents
& POLLIN
) {
347 const u_char
*data
= pcap_next(pcap
, &hdr
);
348 if (data
&& client_pfd
) {
349 DPRINTF("Received packet from ethernet len=%d\n", hdr
.len
);
350 DDUMP(data
, hdr
.len
);
351 u_int32_t len
= htonl(hdr
.len
);
352 write(client_pfd
->fd
, &len
, sizeof(len
));
353 write(client_pfd
->fd
, data
, hdr
.len
);
357 tap_pfd
->revents
= 0;
360 if (client_pfd
&& client_pfd
->revents
) {
361 if (client_pfd
->revents
& POLLIN
) {
362 if (buffer_offset
< data_len
+ sizeof(u_int32_t
)) {
363 int len
= read(client_pfd
->fd
, buffer
+ buffer_offset
,
364 bufsize
- buffer_offset
);
371 buffer_offset
+= len
;
373 data_len
= ntohl(*(u_int32_t
*)buffer
);
375 DPRINTF("Received data from peer: len=%d buffer_offset=%d "
376 "data_len=%d\n", len
, buffer_offset
, data_len
);
379 while (data_len
!= 0 &&
380 buffer_offset
>= data_len
+ sizeof(u_int32_t
)) {
381 char *data
= buffer
+ sizeof(u_int32_t
);
382 eth_send(ethernet
, data
, data_len
);
383 DPRINTF("Sent packet to ethernet len = %d\n", data_len
);
384 DDUMP(data
, data_len
);
386 buffer_offset
-= data_len
+ sizeof(u_int32_t
);
387 if (buffer_offset
> 0 && data_len
> 0) {
388 memmove(buffer
, data
+ data_len
, buffer_offset
);
389 data_len
= ntohl(*(u_int32_t
*)buffer
);
395 if (client_pfd
->revents
& POLLERR
) {
397 DPRINTF("Error on client socket\n");
398 close(client_pfd
->fd
);
404 DPRINTF("Calling it quits because of poll error\n");
410 client_pfd
->revents
= 0;
418 close(listen_pfd
->fd
);
421 close(client_pfd
->fd
);