Reorganize tap code so that more than one method can be used
for accessing physical packets. Add support for tap devices found on linux and bsd. --HG-- extra : convert_revision : 198b082f2e847da8471c3f22d6a55beb9f4b592e
This commit is contained in:
parent
10a906be52
commit
769234f69e
1 changed files with 154 additions and 38 deletions
192
util/tap/tap.cc
192
util/tap/tap.cc
|
@ -173,7 +173,7 @@ Accept(int fd, bool nodelay)
|
|||
}
|
||||
|
||||
void
|
||||
Connect(int fd, const string &host, int port)
|
||||
Connect(int fd, const std::string &host, int port)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
|
||||
|
@ -193,6 +193,133 @@ Connect(int fd, const string &host, int port)
|
|||
DPRINTF("connected to %s on port %d\n", host, port);
|
||||
}
|
||||
|
||||
class Ethernet
|
||||
{
|
||||
protected:
|
||||
int fd;
|
||||
|
||||
public:
|
||||
virtual ~Ethernet() {}
|
||||
|
||||
int getfd() const { return fd; }
|
||||
virtual bool read(const char *&data, int &len) = 0;
|
||||
virtual bool write(const char *data, int len) = 0;
|
||||
};
|
||||
|
||||
class Tap : public Ethernet
|
||||
{
|
||||
private:
|
||||
char buffer[65536];
|
||||
int fd;
|
||||
|
||||
public:
|
||||
Tap(char *device);
|
||||
~Tap();
|
||||
virtual bool read(const char *&data, int &len);
|
||||
virtual bool write(const char *data, int len);
|
||||
};
|
||||
|
||||
class PCap : public Ethernet
|
||||
{
|
||||
private:
|
||||
pcap_t *pcap;
|
||||
eth_t *ethernet;
|
||||
|
||||
public:
|
||||
PCap(char *device, char *filter = NULL);
|
||||
~PCap();
|
||||
virtual bool read(const char *&data, int &len);
|
||||
virtual bool write(const char *data, int len);
|
||||
};
|
||||
|
||||
PCap::PCap(char *device, char *filter)
|
||||
{
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
memset(errbuf, 0, sizeof errbuf);
|
||||
pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
|
||||
if (pcap == NULL)
|
||||
panic("pcap_open_live failed: %s\n", errbuf);
|
||||
|
||||
if (filter) {
|
||||
bpf_program program;
|
||||
bpf_u_int32 localnet, netmask;
|
||||
if (pcap_lookupnet(device, &localnet, &netmask, errbuf) == -1) {
|
||||
DPRINTF("pcap_lookupnet failed: %s\n", errbuf);
|
||||
netmask = 0xffffff00;
|
||||
}
|
||||
|
||||
if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
|
||||
panic("pcap_compile failed, invalid filter:\n%s\n", filter);
|
||||
|
||||
if (pcap_setfilter(pcap, &program) == -1)
|
||||
panic("pcap_setfilter failed\n");
|
||||
}
|
||||
|
||||
ethernet = eth_open(device);
|
||||
if (!ethernet)
|
||||
panic("cannot open the ethernet device for writing\n");
|
||||
|
||||
fd = pcap_fileno(pcap);
|
||||
}
|
||||
|
||||
PCap::~PCap()
|
||||
{
|
||||
pcap_close(pcap);
|
||||
eth_close(ethernet);
|
||||
}
|
||||
|
||||
bool
|
||||
PCap::read(const char *&data, int &len)
|
||||
{
|
||||
pcap_pkthdr hdr;
|
||||
data = (const char *)pcap_next(pcap, &hdr);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
len = hdr.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PCap::write(const char *data, int len)
|
||||
{
|
||||
eth_send(ethernet, data, len);
|
||||
}
|
||||
|
||||
Tap::Tap(char *device)
|
||||
{
|
||||
fd = open(device, O_RDWR, 0);
|
||||
if (fd < 0)
|
||||
panic("could not open %s: %s\n", device, strerror(errno));
|
||||
}
|
||||
|
||||
Tap::~Tap()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool
|
||||
Tap::read(const char *&data, int &len)
|
||||
{
|
||||
DPRINTF("tap read!\n");
|
||||
data = buffer;
|
||||
len = ::read(fd, buffer, sizeof(buffer));
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tap::write(const char *data, int len)
|
||||
{
|
||||
int result = ::write(fd, data, len);
|
||||
if (result < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -201,13 +328,16 @@ main(int argc, char *argv[])
|
|||
bool listening = false;
|
||||
char *device = NULL;
|
||||
char *filter = NULL;
|
||||
Ethernet *tap = NULL;
|
||||
bool usetap = false;
|
||||
char c;
|
||||
int daemon = false;
|
||||
string host;
|
||||
std::string host;
|
||||
int devfd;
|
||||
|
||||
program = basename(argv[0]);
|
||||
|
||||
while ((c = getopt(argc, argv, "b:df:lp:v")) != -1) {
|
||||
while ((c = getopt(argc, argv, "b:df:lp:tv")) != -1) {
|
||||
switch (c) {
|
||||
case 'b':
|
||||
bufsize = atoi(optarg);
|
||||
|
@ -224,6 +354,9 @@ main(int argc, char *argv[])
|
|||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 't':
|
||||
usetap = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
@ -268,31 +401,14 @@ main(int argc, char *argv[])
|
|||
host = *argv;
|
||||
}
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
memset(errbuf, 0, sizeof errbuf);
|
||||
pcap_t *pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
|
||||
if (pcap == NULL)
|
||||
panic("pcap_open_live failed: %s\n", errbuf);
|
||||
|
||||
if (filter) {
|
||||
bpf_program program;
|
||||
bpf_u_int32 localnet, netmask;
|
||||
if (pcap_lookupnet(device, &localnet, &netmask, errbuf) == -1) {
|
||||
DPRINTF("pcap_lookupnet failed: %s\n", errbuf);
|
||||
netmask = 0xffffff00;
|
||||
}
|
||||
|
||||
if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
|
||||
panic("pcap_compile failed, invalid filter:\n%s\n", filter);
|
||||
|
||||
if (pcap_setfilter(pcap, &program) == -1)
|
||||
panic("pcap_setfilter failed\n");
|
||||
if (usetap) {
|
||||
if (filter)
|
||||
panic("-f parameter not valid with a tap device!");
|
||||
tap = new Tap(device);
|
||||
} else {
|
||||
tap = new PCap(device, filter);
|
||||
}
|
||||
|
||||
eth_t *ethernet = eth_open(device);
|
||||
if (!ethernet)
|
||||
panic("cannot open the ethernet device for writing\n");
|
||||
|
||||
pollfd pfds[3];
|
||||
pfds[0].fd = Socket(true);
|
||||
pfds[0].events = POLLIN;
|
||||
|
@ -303,7 +419,7 @@ main(int argc, char *argv[])
|
|||
else
|
||||
Connect(pfds[0].fd, host, port);
|
||||
|
||||
pfds[1].fd = pcap_fileno(pcap);
|
||||
pfds[1].fd = tap->getfd();
|
||||
pfds[1].events = POLLIN;
|
||||
pfds[1].revents = 0;
|
||||
|
||||
|
@ -341,16 +457,16 @@ main(int argc, char *argv[])
|
|||
listen_pfd->revents = 0;
|
||||
}
|
||||
|
||||
DPRINTF("tap events: %x\n", tap_pfd->revents);
|
||||
if (tap_pfd && tap_pfd->revents) {
|
||||
if (tap_pfd->revents & POLLIN) {
|
||||
pcap_pkthdr hdr;
|
||||
const u_char *data = pcap_next(pcap, &hdr);
|
||||
if (data && client_pfd) {
|
||||
DPRINTF("Received packet from ethernet len=%d\n", hdr.len);
|
||||
DDUMP(data, hdr.len);
|
||||
u_int32_t len = htonl(hdr.len);
|
||||
write(client_pfd->fd, &len, sizeof(len));
|
||||
write(client_pfd->fd, data, hdr.len);
|
||||
const char *data; int len;
|
||||
if (tap->read(data, len) && client_pfd) {
|
||||
DPRINTF("Received packet from ethernet len=%d\n", len);
|
||||
DDUMP(data, len);
|
||||
u_int32_t swaplen = htonl(len);
|
||||
write(client_pfd->fd, &swaplen, sizeof(swaplen));
|
||||
write(client_pfd->fd, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +495,7 @@ main(int argc, char *argv[])
|
|||
while (data_len != 0 &&
|
||||
buffer_offset >= data_len + sizeof(u_int32_t)) {
|
||||
char *data = buffer + sizeof(u_int32_t);
|
||||
eth_send(ethernet, data, data_len);
|
||||
tap->write(data, data_len);
|
||||
DPRINTF("Sent packet to ethernet len = %d\n", data_len);
|
||||
DDUMP(data, data_len);
|
||||
|
||||
|
@ -412,8 +528,8 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
delete [] buffer;
|
||||
pcap_close(pcap);
|
||||
eth_close(ethernet);
|
||||
delete tap;
|
||||
|
||||
if (listen_pfd)
|
||||
close(listen_pfd->fd);
|
||||
|
||||
|
|
Loading…
Reference in a new issue