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>
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!");
133 if (::setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&i
,
135 panic("setsockopt() SO_REUSEADDR failed!");
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!");
153 if (::listen(fd
, 1) == -1)
154 panic("listen() failed!");
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!");
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", 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 pcap_t
*pcap
= pcap_open_live(device
, 1500, 1, -1, errbuf
);
274 panic("pcap_open_live failed: %s\n", errbuf
);
277 bpf_u_int32 localnet
, netmask
;
278 if (!pcap_lookupnet(device
, &localnet
, &netmask
, errbuf
))
279 panic("pcap_lookupnet failed: %s\n", errbuf
);
281 if (pcap_compile(pcap
, &program
, filter
, 1, netmask
) == -1)
282 panic("pcap_compile failed, invalid filter:\n%s\n", filter
);
284 if (pcap_setfilter(pcap
, &program
) == -1)
285 panic("pcap_setfilter failed\n");
287 eth_t
*ethernet
= eth_open(device
);
290 pfds
[0].fd
= Socket(true);
291 pfds
[0].events
= POLLIN
;
295 Listen(pfds
[0].fd
, port
);
297 Connect(pfds
[0].fd
, host
, port
);
299 pfds
[1].fd
= pcap_fileno(pcap
);
300 pfds
[1].events
= POLLIN
;
304 pfds
[2].events
= POLLIN
|POLLERR
;
307 pollfd
*listen_pfd
= listening
? &pfds
[0] : NULL
;
308 pollfd
*tap_pfd
= &pfds
[1];
309 pollfd
*client_pfd
= listening
? NULL
: &pfds
[0];
312 int32_t buffer_offset
= 0;
313 int32_t data_len
= 0;
316 int ret
= ::poll(pfds
, npfds
, INFTIM
);
320 if (listen_pfd
&& listen_pfd
->revents
) {
321 if (listen_pfd
->revents
& POLLIN
) {
322 int fd
= Accept(listen_pfd
->fd
, false);
324 DPRINTF("Connection rejected\n");
327 DPRINTF("Connection accepted\n");
328 client_pfd
= &pfds
[2];
333 listen_pfd
->revents
= 0;
336 if (tap_pfd
&& tap_pfd
->revents
) {
337 if (tap_pfd
->revents
& POLLIN
) {
339 const u_char
*data
= pcap_next(pcap
, &hdr
);
340 if (data
&& client_pfd
) {
341 DPRINTF("Received packet from ethernet len=%d\n", hdr
.len
);
342 DDUMP(data
, hdr
.len
);
343 u_int32_t len
= htonl(hdr
.len
);
344 write(client_pfd
->fd
, &len
, sizeof(len
));
345 write(client_pfd
->fd
, data
, hdr
.len
);
349 tap_pfd
->revents
= 0;
352 if (client_pfd
&& client_pfd
->revents
) {
353 if (client_pfd
->revents
& POLLIN
) {
354 if (buffer_offset
< data_len
+ sizeof(u_int32_t
)) {
355 int len
= read(client_pfd
->fd
, buffer
+ buffer_offset
,
356 bufsize
- buffer_offset
);
363 buffer_offset
+= len
;
365 data_len
= ntohl(*(u_int32_t
*)buffer
);
367 DPRINTF("Received data from peer: len=%d buffer_offset=%d "
368 "data_len=%d\n", len
, buffer_offset
, data_len
);
371 while (data_len
!= 0 &&
372 buffer_offset
>= data_len
+ sizeof(u_int32_t
)) {
373 char *data
= buffer
+ sizeof(u_int32_t
);
374 eth_send(ethernet
, data
, data_len
);
375 DPRINTF("Sent packet to ethernet len = %d\n", data_len
);
376 DDUMP(data
, data_len
);
378 buffer_offset
-= data_len
+ sizeof(u_int32_t
);
379 if (buffer_offset
> 0 && data_len
> 0) {
380 memmove(buffer
, data
+ data_len
, buffer_offset
);
381 data_len
= ntohl(*(u_int32_t
*)buffer
);
387 if (client_pfd
->revents
& POLLERR
) {
389 DPRINTF("Error on client socket\n");
390 close(client_pfd
->fd
);
400 client_pfd
->revents
= 0;
409 close(listen_pfd
->fd
);
412 close(client_pfd
->fd
);