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.
34 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
41 #include <sys/ioctl.h>
42 #include <sys/socket.h>
43 #include <sys/types.h>
54 #define panic(arg...) \
55 do { printf("Panic: " arg); exit(1); } while (0)
57 const char *program
= "ethertap";
63 "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
64 "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
70 #define DPRINTF(args...) do { \
75 #define DDUMP(args...) do { \
77 dump((const u_char *)args); \
81 dump(const u_char
*data
, int len
)
85 for (i
= 0; i
< len
; i
+= 16) {
90 for (j
= 0; j
< c
; j
++) {
91 printf("%02x ", data
[i
+ j
] & 0xff);
92 if ((j
& 0xf) == 7 && j
> 0)
100 for (j
= 0; j
< c
; j
++) {
101 int ch
= data
[i
+ j
] & 0x7f;
102 printf("%c", (char)(isprint(ch
) ? ch
: ' '));
114 quit_now(int sigtype
)
116 DPRINTF("User requested exit\n");
124 int fd
= ::socket(PF_INET
, SOCK_STREAM
, 0);
126 panic("Can't create socket!\n");
130 if (::setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&i
,
132 panic("setsockopt() SO_REUSEADDR failed!\n");
139 Listen(int fd
, int port
)
141 struct sockaddr_in sockaddr
;
142 sockaddr
.sin_family
= PF_INET
;
143 sockaddr
.sin_addr
.s_addr
= INADDR_ANY
;
145 sockaddr
.sin_port
= htons(port
);
146 int ret
= ::bind(fd
, (struct sockaddr
*)&sockaddr
, sizeof (sockaddr
));
148 panic("bind() failed!\n");
150 if (::listen(fd
, 1) == -1)
151 panic("listen() failed!\n");
154 // Open a connection. Accept will block, so if you don't want it to,
155 // make sure a connection is ready before you call accept.
157 Accept(int fd
, bool nodelay
)
159 struct sockaddr_in sockaddr
;
160 socklen_t slen
= sizeof (sockaddr
);
161 int sfd
= ::accept(fd
, (struct sockaddr
*)&sockaddr
, &slen
);
163 panic("accept() failed!\n");
167 ::setsockopt(sfd
, IPPROTO_TCP
, TCP_NODELAY
, (char *)&i
, sizeof(i
));
173 Connect(int fd
, const std::string
&host
, int port
)
175 struct sockaddr_in sockaddr
;
176 if (::inet_aton(host
.c_str(), &sockaddr
.sin_addr
) == 0) {
178 hp
= ::gethostbyname(host
.c_str());
180 panic("Host %s not found\n", host
.c_str());
182 sockaddr
.sin_family
= hp
->h_addrtype
;
183 memcpy(&sockaddr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
186 sockaddr
.sin_port
= htons(port
);
187 if (::connect(fd
, (struct sockaddr
*)&sockaddr
, sizeof(sockaddr
)) != 0)
188 panic("could not connect to %s on port %d\n", host
.c_str(), port
);
190 DPRINTF("connected to %s on port %d\n", host
.c_str(), port
);
199 virtual ~Ethernet() {}
201 int getfd() const { return fd
; }
202 virtual bool read(const char *&data
, int &len
) = 0;
203 virtual bool write(const char *data
, int len
) = 0;
206 class Tap
: public Ethernet
215 virtual bool read(const char *&data
, int &len
);
216 virtual bool write(const char *data
, int len
);
219 class PCap
: public Ethernet
225 PCap(char *device
, char *filter
= NULL
);
227 virtual bool read(const char *&data
, int &len
);
228 virtual bool write(const char *data
, int len
);
231 PCap::PCap(char *device
, char *filter
)
233 char errbuf
[PCAP_ERRBUF_SIZE
];
234 memset(errbuf
, 0, sizeof errbuf
);
235 pcap
= pcap_open_live(device
, 1500, 1, -1, errbuf
);
237 panic("pcap_open_live failed: %s\n", errbuf
);
241 bpf_u_int32 localnet
, netmask
;
242 if (pcap_lookupnet(device
, &localnet
, &netmask
, errbuf
) == -1) {
243 DPRINTF("pcap_lookupnet failed: %s\n", errbuf
);
244 netmask
= 0xffffff00;
247 if (pcap_compile(pcap
, &program
, filter
, 1, netmask
) == -1)
248 panic("pcap_compile failed, invalid filter:\n%s\n", filter
);
250 if (pcap_setfilter(pcap
, &program
) == -1)
251 panic("pcap_setfilter failed\n");
254 fd
= pcap_fileno(pcap
);
263 PCap::read(const char *&data
, int &len
)
266 data
= (const char *)pcap_next(pcap
, &hdr
);
275 PCap::write(const char *data
, int len
)
277 return pcap_inject(pcap
, data
, len
) == len
;
280 Tap::Tap(char *device
)
282 fd
= open(device
, O_RDWR
, 0);
284 panic("could not open %s: %s\n", device
, strerror(errno
));
293 Tap::read(const char *&data
, int &len
)
295 DPRINTF("tap read!\n");
297 len
= ::read(fd
, buffer
, sizeof(buffer
));
305 Tap::write(const char *data
, int len
)
307 int result
= ::write(fd
, data
, len
);
315 main(int argc
, char *argv
[])
319 bool listening
= false;
322 Ethernet
*tap
= NULL
;
329 program
= basename(argv
[0]);
332 while ((ret
= getopt(argc
, argv
, "b:df:lp:tv")) != -1) {
336 bufsize
= atoi(optarg
);
362 signal(SIGINT
, quit_now
);
363 signal(SIGTERM
, quit_now
);
364 signal(SIGHUP
, quit_now
);
370 panic("Fork failed\n");
378 char *buffer
= new char[bufsize
];
399 panic("-f parameter not valid with a tap device!");
400 tap
= new Tap(device
);
402 tap
= new PCap(device
, filter
);
406 pfds
[0].fd
= Socket(true);
407 pfds
[0].events
= POLLIN
;
411 Listen(pfds
[0].fd
, port
);
413 Connect(pfds
[0].fd
, host
, port
);
415 pfds
[1].fd
= tap
->getfd();
416 pfds
[1].events
= POLLIN
;
420 pfds
[2].events
= POLLIN
|POLLERR
;
423 pollfd
*listen_pfd
= listening
? &pfds
[0] : NULL
;
424 pollfd
*tap_pfd
= &pfds
[1];
425 pollfd
*client_pfd
= listening
? NULL
: &pfds
[0];
428 int32_t buffer_offset
= 0;
429 int32_t data_len
= 0;
431 DPRINTF("Begin poll loop\n");
433 int ret
= ::poll(pfds
, npfds
, -1);
437 if (listen_pfd
&& listen_pfd
->revents
) {
438 if (listen_pfd
->revents
& POLLIN
) {
439 int fd
= Accept(listen_pfd
->fd
, false);
441 DPRINTF("Connection rejected\n");
444 DPRINTF("Connection accepted\n");
445 client_pfd
= &pfds
[2];
450 listen_pfd
->revents
= 0;
453 DPRINTF("tap events: %x\n", tap_pfd
->revents
);
454 if (tap_pfd
&& tap_pfd
->revents
) {
455 if (tap_pfd
->revents
& POLLIN
) {
456 const char *data
; int len
;
457 if (tap
->read(data
, len
) && client_pfd
) {
458 DPRINTF("Received packet from ethernet len=%d\n", len
);
460 u_int32_t swaplen
= htonl(len
);
461 write(client_pfd
->fd
, &swaplen
, sizeof(swaplen
));
462 write(client_pfd
->fd
, data
, len
);
466 tap_pfd
->revents
= 0;
469 if (client_pfd
&& client_pfd
->revents
) {
470 if (client_pfd
->revents
& POLLIN
) {
471 if (buffer_offset
< data_len
+ sizeof(u_int32_t
)) {
472 int len
= read(client_pfd
->fd
, buffer
+ buffer_offset
,
473 bufsize
- buffer_offset
);
480 buffer_offset
+= len
;
482 data_len
= ntohl(*(u_int32_t
*)buffer
);
484 DPRINTF("Received data from peer: len=%d buffer_offset=%d "
485 "data_len=%d\n", len
, buffer_offset
, data_len
);
488 while (data_len
!= 0 &&
489 buffer_offset
>= data_len
+ sizeof(u_int32_t
)) {
490 char *data
= buffer
+ sizeof(u_int32_t
);
491 tap
->write(data
, data_len
);
492 DPRINTF("Sent packet to ethernet len = %d\n", data_len
);
493 DDUMP(data
, data_len
);
495 buffer_offset
-= data_len
+ sizeof(u_int32_t
);
496 if (buffer_offset
> 0 && data_len
> 0) {
497 memmove(buffer
, data
+ data_len
, buffer_offset
);
498 data_len
= ntohl(*(u_int32_t
*)buffer
);
504 if (client_pfd
->revents
& POLLERR
) {
506 DPRINTF("Error on client socket\n");
507 close(client_pfd
->fd
);
513 DPRINTF("Calling it quits because of poll error\n");
519 client_pfd
->revents
= 0;
527 close(listen_pfd
->fd
);
530 close(client_pfd
->fd
);