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:
192
util/tap/tap.cc
192
util/tap/tap.cc
@@ -173,7 +173,7 @@ Accept(int fd, bool nodelay)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Connect(int fd, const string &host, int port)
|
Connect(int fd, const std::string &host, int port)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sockaddr;
|
struct sockaddr_in sockaddr;
|
||||||
if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
|
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);
|
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
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -201,13 +328,16 @@ main(int argc, char *argv[])
|
|||||||
bool listening = false;
|
bool listening = false;
|
||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
char *filter = NULL;
|
char *filter = NULL;
|
||||||
|
Ethernet *tap = NULL;
|
||||||
|
bool usetap = false;
|
||||||
char c;
|
char c;
|
||||||
int daemon = false;
|
int daemon = false;
|
||||||
string host;
|
std::string host;
|
||||||
|
int devfd;
|
||||||
|
|
||||||
program = basename(argv[0]);
|
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) {
|
switch (c) {
|
||||||
case 'b':
|
case 'b':
|
||||||
bufsize = atoi(optarg);
|
bufsize = atoi(optarg);
|
||||||
@@ -224,6 +354,9 @@ main(int argc, char *argv[])
|
|||||||
case 'p':
|
case 'p':
|
||||||
port = atoi(optarg);
|
port = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
usetap = true;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose++;
|
verbose++;
|
||||||
break;
|
break;
|
||||||
@@ -268,31 +401,14 @@ main(int argc, char *argv[])
|
|||||||
host = *argv;
|
host = *argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
if (usetap) {
|
||||||
memset(errbuf, 0, sizeof errbuf);
|
if (filter)
|
||||||
pcap_t *pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
|
panic("-f parameter not valid with a tap device!");
|
||||||
if (pcap == NULL)
|
tap = new Tap(device);
|
||||||
panic("pcap_open_live failed: %s\n", errbuf);
|
} else {
|
||||||
|
tap = new PCap(device, filter);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eth_t *ethernet = eth_open(device);
|
|
||||||
if (!ethernet)
|
|
||||||
panic("cannot open the ethernet device for writing\n");
|
|
||||||
|
|
||||||
pollfd pfds[3];
|
pollfd pfds[3];
|
||||||
pfds[0].fd = Socket(true);
|
pfds[0].fd = Socket(true);
|
||||||
pfds[0].events = POLLIN;
|
pfds[0].events = POLLIN;
|
||||||
@@ -303,7 +419,7 @@ main(int argc, char *argv[])
|
|||||||
else
|
else
|
||||||
Connect(pfds[0].fd, host, port);
|
Connect(pfds[0].fd, host, port);
|
||||||
|
|
||||||
pfds[1].fd = pcap_fileno(pcap);
|
pfds[1].fd = tap->getfd();
|
||||||
pfds[1].events = POLLIN;
|
pfds[1].events = POLLIN;
|
||||||
pfds[1].revents = 0;
|
pfds[1].revents = 0;
|
||||||
|
|
||||||
@@ -341,16 +457,16 @@ main(int argc, char *argv[])
|
|||||||
listen_pfd->revents = 0;
|
listen_pfd->revents = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DPRINTF("tap events: %x\n", tap_pfd->revents);
|
||||||
if (tap_pfd && tap_pfd->revents) {
|
if (tap_pfd && tap_pfd->revents) {
|
||||||
if (tap_pfd->revents & POLLIN) {
|
if (tap_pfd->revents & POLLIN) {
|
||||||
pcap_pkthdr hdr;
|
const char *data; int len;
|
||||||
const u_char *data = pcap_next(pcap, &hdr);
|
if (tap->read(data, len) && client_pfd) {
|
||||||
if (data && client_pfd) {
|
DPRINTF("Received packet from ethernet len=%d\n", len);
|
||||||
DPRINTF("Received packet from ethernet len=%d\n", hdr.len);
|
DDUMP(data, len);
|
||||||
DDUMP(data, hdr.len);
|
u_int32_t swaplen = htonl(len);
|
||||||
u_int32_t len = htonl(hdr.len);
|
write(client_pfd->fd, &swaplen, sizeof(swaplen));
|
||||||
write(client_pfd->fd, &len, sizeof(len));
|
write(client_pfd->fd, data, len);
|
||||||
write(client_pfd->fd, data, hdr.len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +495,7 @@ main(int argc, char *argv[])
|
|||||||
while (data_len != 0 &&
|
while (data_len != 0 &&
|
||||||
buffer_offset >= data_len + sizeof(u_int32_t)) {
|
buffer_offset >= data_len + sizeof(u_int32_t)) {
|
||||||
char *data = buffer + 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);
|
DPRINTF("Sent packet to ethernet len = %d\n", data_len);
|
||||||
DDUMP(data, data_len);
|
DDUMP(data, data_len);
|
||||||
|
|
||||||
@@ -412,8 +528,8 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete [] buffer;
|
delete [] buffer;
|
||||||
pcap_close(pcap);
|
delete tap;
|
||||||
eth_close(ethernet);
|
|
||||||
if (listen_pfd)
|
if (listen_pfd)
|
||||||
close(listen_pfd->fd);
|
close(listen_pfd->fd);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user