|
#include "send_recv.h" |
|
|
|
char *names[]={ |
|
"<", /* incoming */ |
|
"B", /* broadcast */ |
|
"M", /* multicast */ |
|
"P", /* promisc */ |
|
">", /* outgoing */ |
|
}; |
|
|
|
int fd=-1; |
|
char *map; |
|
struct tpacket_req req = {0}; |
|
struct iovec *ring; |
|
|
|
void sigproc(int sig) |
|
{ |
|
struct tpacket_stats st; |
|
int len=sizeof(st); |
|
|
|
if (!getsockopt(fd,SOL_PACKET,PACKET_STATISTICS,(char *)&st,&len)) { |
|
fprintf(stderr, "recieved %u packets, dropped %u\n", |
|
st.tp_packets, st.tp_drops); |
|
} |
|
|
|
if ( map ) munmap(map, req.tp_block_size * req.tp_block_nr); |
|
if ( fd>=0 ) close(fd); |
|
if ( ring ) free(ring); |
|
|
|
exit(0); |
|
} |
|
|
|
int main ( int argc, char **argv ) |
|
{ |
|
struct pollfd pfd; |
|
struct sockaddr_ll addr; |
|
int i; |
|
|
|
signal(SIGINT, sigproc); |
|
|
|
/* Open the packet socket */ |
|
if ( (fd=socket(PF_PACKET, ETH_P_ALL, 0))<0 ) { |
|
perror("socket()"); |
|
return 1; |
|
} |
|
|
|
/* Setup the fd for mmap() ring buffer */ |
|
req.tp_block_size=8192; |
|
req.tp_frame_size=2048; |
|
req.tp_block_nr=512; |
|
req.tp_frame_nr=4*512; |
|
if ( (setsockopt(fd, |
|
SOL_PACKET, |
|
PACKET_RX_RING, |
|
(char *)&req, |
|
sizeof(req))) != 0 ) { |
|
perror("setsockopt()"); |
|
close(fd); |
|
return 1; |
|
}; |
|
|
|
/* mmap() the sucker */ |
|
map=mmap(NULL, |
|
req.tp_block_size * req.tp_block_nr, |
|
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0); |
|
if ( map==MAP_FAILED ) { |
|
perror("mmap()"); |
|
close(fd); |
|
return 1; |
|
} |
|
|
|
/* Setup our ringbuffer */ |
|
ring=malloc(req.tp_frame_nr * sizeof(struct iovec)); |
|
for(i=0; i<req.tp_frame_nr; i++) { |
|
ring[i].iov_base=(void *)((long)map)+(i*req.tp_frame_size); |
|
ring[i].iov_len=req.tp_frame_size; |
|
} |
|
|
|
/* bind the packet socket */ |
|
memset(&addr, 0, sizeof(addr)); |
|
addr.sll_family=AF_PACKET; |
|
addr.sll_protocol=htons(ETH_P_ALL); |
|
addr.sll_ifindex=2; |
|
addr.sll_hatype=0; |
|
addr.sll_pkttype=0; |
|
addr.sll_halen=0; |
|
if ( bind(fd, (struct sockaddr *)&addr, sizeof(addr)) ) { |
|
munmap(map, req.tp_block_size * req.tp_block_nr); |
|
perror("bind()"); |
|
close(fd); |
|
return 1; |
|
} |
|
|
|
struct ifreq ifopts; |
|
char ifname[] = "enp36s0"; // TODO: get from -i |
|
strncpy(ifopts.ifr_name, ifname, IFNAMSIZ); |
|
if (ioctl(fd, SIOCGIFFLAGS, &ifopts) == -1) perror("Getting socket flags failed when entering promiscuous mode "); |
|
ifopts.ifr_flags |= IFF_PROMISC; |
|
if (ioctl(fd, SIOCSIFFLAGS, &ifopts) == -1) perror("Setting socket flags failed when entering promiscuous mode "); |
|
|
|
long long int c = 0; |
|
FILE *file; |
|
|
|
// Initialize sha256 digest |
|
EVP_MD_CTX *mdctx; |
|
|
|
struct tpacket_stats st; |
|
int len = sizeof(st); |
|
|
|
// Initialize the counter |
|
if (!getsockopt(fd, SOL_PACKET, PACKET_STATISTICS, &st, &len)) { |
|
unsigned int total_drops = st.tp_drops; |
|
} |
|
|
|
for(i=0;;) { |
|
while(*(unsigned long*)ring[i].iov_base) { |
|
struct tpacket_hdr *h=ring[i].iov_base; |
|
struct sockaddr_ll *sll=(void *)h + TPACKET_ALIGN(sizeof(*h)); |
|
unsigned char *bp = (unsigned char *)h + h->tp_mac; |
|
struct ethhdr *eh = (struct ethhdr *)bp; |
|
|
|
// TODO: sometimes packets arrive and are not dropped, but they are not being handled here |
|
// this is clear from the exit report of received / dropped packets |
|
|
|
// TODO: syslog dropped packets |
|
// if (!getsockopt(fd, SOL_PACKET, PACKET_RX_RING, &st, &len)) { |
|
// printf("recieved %u packets, dropped %u\n", st.tp_packets, st.tp_drops); |
|
// if (st.tp_drops > 0) sigproc(SIGINT); |
|
// } |
|
|
|
// printf("%lld %u.%.6u: if%u %s %u bytes | ", |
|
// ++c, |
|
// h->tp_sec, h->tp_usec, |
|
// sll->sll_ifindex, |
|
// names[sll->sll_pkttype], |
|
// h->tp_len); |
|
|
|
// TODO: handle protocols via libraries |
|
// if compiled with, e.g., ethabac, then handle it with ethabac |
|
if (ntohs(eh->h_proto) == 0xabac) { // TODO: get from -e |
|
struct frame frame = parse_frame(bp); |
|
// if (frame.packet_nr % 10 == 0) { printf("."); fflush(stdout); } // TODO: use a spinner |
|
|
|
// frame 0 is the metadata |
|
// TODO: sometimes the first packet is dropped, so we need to check for that |
|
if (frame.packet_nr == 0) { // TODO: time how long it takes to recv all the packets to last_packet_nr |
|
print_frame(&frame); // TODO: if -v |
|
// TODO: syslog every recv |
|
if (frame.data[0] == 0x00) { // command |
|
// TODO: get command handler dir from -C |
|
// TODO: verify that the command handler is owned by the same owner as this program or exit |
|
// TOOD: run the command handler |
|
if (frame.data[1] == 0xcc && frame.data[2] == 0x01) { // exit |
|
sigproc(SIGINT); |
|
} |
|
} |
|
else { // file |
|
// open the file to recv |
|
file = fopen("filename", "wb"); // TODO: get from frame.data |
|
if (!file) { |
|
perror("fopen"); |
|
} |
|
mdctx = EVP_MD_CTX_new(); |
|
if (!mdctx) { |
|
perror("EVP_MD_CTX_new"); |
|
return 1; |
|
} |
|
if (!EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) { |
|
perror("EVP_DigestInit_ex"); |
|
return 1; |
|
} |
|
} |
|
} |
|
// frames 1-n are the file data |
|
else if (frame.packet_nr > 0 && frame.packet_nr <= frame.last_packet_nr) { |
|
print_frame(&frame); // TODO: if -vv |
|
if (1) { |
|
fwrite(frame.data, 1, frame.data_len, file); |
|
// add the buffer to the sha256 digest |
|
if (!EVP_DigestUpdate(mdctx, frame.data, frame.data_len)) { |
|
perror("EVP_DigestUpdate"); |
|
} |
|
} |
|
} |
|
// frame n+1 is the hash (all commands have the same hash) |
|
// TODO: sometimes the last packet is dropped, so we need to handle for that |
|
else if (frame.packet_nr > frame.last_packet_nr) { |
|
print_frame(&frame); // TODO: if -v |
|
fclose(file); |
|
// finalize the sha256 digest |
|
unsigned char hash[EVP_MAX_MD_SIZE]; |
|
unsigned int hash_len; |
|
if (!EVP_DigestFinal_ex(mdctx, hash, &hash_len)) { |
|
perror("EVP_DigestFinal_ex"); |
|
} |
|
// printf("hash exp: %s\n", hex(frame.data, frame.data_len)); |
|
// printf("hash act: %s\n", hex(hash, hash_len)); |
|
if (memcmp(hash, frame.data, hash_len) == 0) { |
|
printf("The hashes match.\n\n"); |
|
// TODO: verify that the callback script is owned by the same owner as this program or exit |
|
// TODO: execute the success callback script |
|
} else { |
|
printf("The hashes do not match.\n\n"); |
|
// TODO: verify that the callback script is owned by the same owner as this program or exit |
|
// TODO: execute the error callback script |
|
} |
|
} |
|
} |
|
else if (ntohs(eh->h_proto) == 0x1234) { // TODO: handle other protocols |
|
printf("TODO: handle other protocols\n"); |
|
} |
|
else if (ntohs(eh->h_proto) == 0x5678) { // TODO: handle other protocols |
|
printf("TODO: handle other protocols\n"); |
|
} |
|
else { |
|
// printf("TODO: handle other protocols\n"); |
|
} |
|
|
|
// tell the kernel this packet is done with |
|
h->tp_status=TP_STATUS_KERNEL; |
|
__sync_synchronize(); // mb(); // memory barrier |
|
|
|
i=(i==req.tp_frame_nr-1) ? 0 : i+1; |
|
} |
|
|
|
/* sleep when nothing is happening */ |
|
pfd.fd=fd; |
|
pfd.events=POLLIN|POLLERR; |
|
pfd.revents=0; |
|
poll(&pfd, 1, -1); |
|
} |
|
|
|
return 0; |
|
} |