2 * Copyright (c) 2003-2005 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.
28 * Authors: Nathan Binkert
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
53 #include "base/cprintf.hh"
55 #define panic(arg...) \
56 do { cprintf("Panic: " arg); exit(1); } while (0)
58 char *program
= "ethertap";
64 "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
65 "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
71 #define DPRINTF(args...) do { \
76 #define DDUMP(args...) do { \
78 dump((const u_char *)args); \
82 dump(const u_char
*data
, int len
)
86 for (i
= 0; i
< len
; i
+= 16) {
91 for (j
= 0; j
< c
; j
++) {
92 cprintf("%02x ", data
[i
+ j
] & 0xff);
93 if ((j
& 0xf) == 7 && j
> 0)
101 for (j
= 0; j
< c
; j
++) {
102 int ch
= data
[i
+ j
] & 0x7f;
103 cprintf("%c", (char)(isprint(ch
) ? ch
: ' '));
115 quit_now(int sigtype
)
117 DPRINTF("User requested exit\n");
125 int fd
= ::socket(PF_INET
, SOCK_STREAM
, 0);
127 panic("Can't create socket!\n");
131 if (::setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&i
,
133 panic("setsockopt() SO_REUSEADDR failed!\n");
140 Listen(int fd
, int port
)
142 struct sockaddr_in sockaddr
;
143 sockaddr
.sin_family
= PF_INET
;
144 sockaddr
.sin_addr
.s_addr
= INADDR_ANY
;
146 sockaddr
.sin_port
= htons(port
);
147 int ret
= ::bind(fd
, (struct sockaddr
*)&sockaddr
, sizeof (sockaddr
));
149 panic("bind() failed!\n");
151 if (::listen(fd
, 1) == -1)
152 panic("listen() failed!\n");
155 // Open a connection. Accept will block, so if you don't want it to,
156 // make sure a connection is ready before you call accept.
158 Accept(int fd
, bool nodelay
)
160 struct sockaddr_in sockaddr
;
161 socklen_t slen
= sizeof (sockaddr
);
162 int sfd
= ::accept(fd
, (struct sockaddr
*)&sockaddr
, &slen
);
164 panic("accept() failed!\n");
168 ::setsockopt(sfd
, IPPROTO_TCP
, TCP_NODELAY
, (char *)&i
, sizeof(i
));
174 Connect(int fd
, const std::string
&host
, int port
)
176 struct sockaddr_in sockaddr
;
177 if (::inet_aton(host
.c_str(), &sockaddr
.sin_addr
) == 0) {
179 hp
= ::gethostbyname(host
.c_str());
181 panic("Host %s not found\n", host
);
183 sockaddr
.sin_family
= hp
->h_addrtype
;
184 memcpy(&sockaddr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
187 sockaddr
.sin_port
= htons(port
);
188 if (::connect(fd
, (struct sockaddr
*)&sockaddr
, sizeof(sockaddr
)) != 0)
189 panic("could not connect to %s on port %d\n", host
, port
);
191 DPRINTF("connected to %s on port %d\n", host
, port
);
200 virtual ~Ethernet() {}
202 int getfd() const { return fd
; }
203 virtual bool read(const char *&data
, int &len
) = 0;
204 virtual bool write(const char *data
, int len
) = 0;
207 class Tap
: public Ethernet
216 virtual bool read(const char *&data
, int &len
);
217 virtual bool write(const char *data
, int len
);
220 class PCap
: public Ethernet
227 PCap(char *device
, char *filter
= NULL
);
229 virtual bool read(const char *&data
, int &len
);
230 virtual bool write(const char *data
, int len
);
233 PCap::PCap(char *device
, char *filter
)
235 char errbuf
[PCAP_ERRBUF_SIZE
];
236 memset(errbuf
, 0, sizeof errbuf
);
237 pcap
= pcap_open_live(device
, 1500, 1, -1, errbuf
);
239 panic("pcap_open_live failed: %s\n", errbuf
);
243 bpf_u_int32 localnet
, netmask
;
244 if (pcap_lookupnet(device
, &localnet
, &netmask
, errbuf
) == -1) {
245 DPRINTF("pcap_lookupnet failed: %s\n", errbuf
);
246 netmask
= 0xffffff00;
249 if (pcap_compile(pcap
, &program
, filter
, 1, netmask
) == -1)
250 panic("pcap_compile failed, invalid filter:\n%s\n", filter
);
252 if (pcap_setfilter(pcap
, &program
) == -1)
253 panic("pcap_setfilter failed\n");
256 ethernet
= eth_open(device
);
258 panic("cannot open the ethernet device for writing\n");
260 fd
= pcap_fileno(pcap
);
270 PCap::read(const char *&data
, int &len
)
273 data
= (const char *)pcap_next(pcap
, &hdr
);
282 PCap::write(const char *data
, int len
)
284 eth_send(ethernet
, data
, len
);
287 Tap::Tap(char *device
)
289 fd
= open(device
, O_RDWR
, 0);
291 panic("could not open %s: %s\n", device
, strerror(errno
));
300 Tap::read(const char *&data
, int &len
)
302 DPRINTF("tap read!\n");
304 len
= ::read(fd
, buffer
, sizeof(buffer
));
312 Tap::write(const char *data
, int len
)
314 int result
= ::write(fd
, data
, len
);
322 main(int argc
, char *argv
[])
326 bool listening
= false;
329 Ethernet
*tap
= NULL
;
336 program
= basename(argv
[0]);
338 while ((c
= getopt(argc
, argv
, "b:df:lp:tv")) != -1) {
341 bufsize
= atoi(optarg
);
367 signal(SIGINT
, quit_now
);
368 signal(SIGTERM
, quit_now
);
369 signal(SIGHUP
, quit_now
);
375 panic("Fork failed\n");
383 char *buffer
= new char[bufsize
];
404 panic("-f parameter not valid with a tap device!");
405 tap
= new Tap(device
);
407 tap
= new PCap(device
, filter
);
411 pfds
[0].fd
= Socket(true);
412 pfds
[0].events
= POLLIN
;
416 Listen(pfds
[0].fd
, port
);
418 Connect(pfds
[0].fd
, host
, port
);
420 pfds
[1].fd
= tap
->getfd();
421 pfds
[1].events
= POLLIN
;
425 pfds
[2].events
= POLLIN
|POLLERR
;
428 pollfd
*listen_pfd
= listening
? &pfds
[0] : NULL
;
429 pollfd
*tap_pfd
= &pfds
[1];
430 pollfd
*client_pfd
= listening
? NULL
: &pfds
[0];
433 int32_t buffer_offset
= 0;
434 int32_t data_len
= 0;
436 DPRINTF("Begin poll loop\n");
438 int ret
= ::poll(pfds
, npfds
, INFTIM
);
442 if (listen_pfd
&& listen_pfd
->revents
) {
443 if (listen_pfd
->revents
& POLLIN
) {
444 int fd
= Accept(listen_pfd
->fd
, false);
446 DPRINTF("Connection rejected\n");
449 DPRINTF("Connection accepted\n");
450 client_pfd
= &pfds
[2];
455 listen_pfd
->revents
= 0;
458 DPRINTF("tap events: %x\n", tap_pfd
->revents
);
459 if (tap_pfd
&& tap_pfd
->revents
) {
460 if (tap_pfd
->revents
& POLLIN
) {
461 const char *data
; int len
;
462 if (tap
->read(data
, len
) && client_pfd
) {
463 DPRINTF("Received packet from ethernet len=%d\n", len
);
465 u_int32_t swaplen
= htonl(len
);
466 write(client_pfd
->fd
, &swaplen
, sizeof(swaplen
));
467 write(client_pfd
->fd
, data
, len
);
471 tap_pfd
->revents
= 0;
474 if (client_pfd
&& client_pfd
->revents
) {
475 if (client_pfd
->revents
& POLLIN
) {
476 if (buffer_offset
< data_len
+ sizeof(u_int32_t
)) {
477 int len
= read(client_pfd
->fd
, buffer
+ buffer_offset
,
478 bufsize
- buffer_offset
);
485 buffer_offset
+= len
;
487 data_len
= ntohl(*(u_int32_t
*)buffer
);
489 DPRINTF("Received data from peer: len=%d buffer_offset=%d "
490 "data_len=%d\n", len
, buffer_offset
, data_len
);
493 while (data_len
!= 0 &&
494 buffer_offset
>= data_len
+ sizeof(u_int32_t
)) {
495 char *data
= buffer
+ sizeof(u_int32_t
);
496 tap
->write(data
, data_len
);
497 DPRINTF("Sent packet to ethernet len = %d\n", data_len
);
498 DDUMP(data
, data_len
);
500 buffer_offset
-= data_len
+ sizeof(u_int32_t
);
501 if (buffer_offset
> 0 && data_len
> 0) {
502 memmove(buffer
, data
+ data_len
, buffer_offset
);
503 data_len
= ntohl(*(u_int32_t
*)buffer
);
509 if (client_pfd
->revents
& POLLERR
) {
511 DPRINTF("Error on client socket\n");
512 close(client_pfd
->fd
);
518 DPRINTF("Calling it quits because of poll error\n");
524 client_pfd
->revents
= 0;
532 close(listen_pfd
->fd
);
535 close(client_pfd
->fd
);