Start working on the network-facing side of Ethermess
This commit is contained in:
parent
829cd7fdfb
commit
211473b48e
|
@ -2,3 +2,4 @@
|
|||
*.o
|
||||
ethertype-dump
|
||||
arp-request
|
||||
ethermess
|
||||
|
|
5
Makefile
5
Makefile
|
@ -7,7 +7,7 @@ CFLAGS += -Os -g -Wall -Wextra -pedantic
|
|||
CPPFLAGS +=
|
||||
LDFLAGS +=
|
||||
|
||||
BINS := ethertype-dump arp-request
|
||||
BINS := ethertype-dump arp-request ethermess
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
@ -22,6 +22,9 @@ ethertype-dump: ethertype-dump.o
|
|||
arp-request: arp-request.o
|
||||
$(CC) -o $@ $< $(LDFLAGS)
|
||||
|
||||
ethermess: ethermess.o
|
||||
$(CC) -o $@ $< $(LDFLAGS)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
|
||||
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool running = true;
|
||||
|
||||
int packet_socket;
|
||||
|
||||
unsigned char own_mac[6];
|
||||
|
||||
char hexify(int nybble) {
|
||||
assert(0 <= nybble && nybble <= 16);
|
||||
return "0123456789abcdef"[nybble];
|
||||
}
|
||||
|
||||
void format_mac(const unsigned char binary_address[6], char formatted[18]) {
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
unsigned char byte = binary_address[i];
|
||||
formatted[3*i] = hexify(byte >> 4);
|
||||
formatted[3*i + 1] = hexify(byte & 0xf);
|
||||
formatted[3*i + 2] = ':';
|
||||
}
|
||||
formatted[17] = '\0';
|
||||
}
|
||||
|
||||
void drop_privileges(void) {
|
||||
uid_t uid = getuid();
|
||||
gid_t gid = getgid();
|
||||
|
||||
errno = 0;
|
||||
if (setresgid(gid, gid, gid) == -1) {
|
||||
err(1, "setresgid");
|
||||
}
|
||||
errno = 0;
|
||||
if (setresuid(uid, uid, uid) == -1) {
|
||||
err(1, "setresuid");
|
||||
}
|
||||
}
|
||||
|
||||
void read_command(void) {
|
||||
int cmd = getchar();
|
||||
if (cmd == EOF) {
|
||||
err(1, "getchar");
|
||||
}
|
||||
|
||||
if (cmd == 'q') {
|
||||
running = false;
|
||||
} else if (cmd == '\n') {
|
||||
// Ignore
|
||||
} else {
|
||||
fprintf(stderr, "?"); //debg
|
||||
}
|
||||
}
|
||||
|
||||
void process_frame(void) {
|
||||
unsigned char frame[1518]; // Largest a 802.3 frame can be without FCS
|
||||
|
||||
errno = 0;
|
||||
if (recv(packet_socket, frame, sizeof(frame), 0) == -1) {
|
||||
errx(1, "recv");
|
||||
}
|
||||
|
||||
fprintf(stderr, "."); // debg
|
||||
}
|
||||
|
||||
void eventloop(void) {
|
||||
// Listen on both stdin for commands and network interface for packets
|
||||
struct pollfd pollfds[2];
|
||||
|
||||
// stdin
|
||||
pollfds[0].fd = 0;
|
||||
pollfds[0].events = POLLIN;
|
||||
|
||||
// Network interface
|
||||
pollfds[1].fd = packet_socket;
|
||||
pollfds[1].events = POLLIN;
|
||||
|
||||
while (running) {
|
||||
errno = 0;
|
||||
int ready = poll(pollfds, sizeof(pollfds) / sizeof(*pollfds), -1);
|
||||
if (ready == -1) {
|
||||
err(1, "poll");
|
||||
}
|
||||
|
||||
// stdin
|
||||
if (ready > 0 && pollfds[0].revents != 0) {
|
||||
ready--;
|
||||
|
||||
if (pollfds[0].revents & POLLIN) {
|
||||
// Read a command
|
||||
read_command();
|
||||
} else {
|
||||
errx(1, "Got poll event %hd on stdin\n", pollfds[0].revents);
|
||||
}
|
||||
}
|
||||
|
||||
// packet_socket
|
||||
if (ready > 0 && pollfds[1].revents != 0) {
|
||||
ready--;
|
||||
|
||||
if (pollfds[1].revents & POLLIN) {
|
||||
// Process a frame
|
||||
process_frame();
|
||||
} else {
|
||||
errx(1, "Got poll event %hd on packet socket\n", pollfds[1].revents);
|
||||
}
|
||||
}
|
||||
|
||||
if (ready > 0) {
|
||||
errx(1, "poll(1) says we have ready fds, but neither was ready");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s interface\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *interface_name = argv[1];
|
||||
|
||||
// Create a packet socket
|
||||
errno = 0;
|
||||
packet_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (packet_socket == -1) {
|
||||
err(1, "socket");
|
||||
}
|
||||
|
||||
// Only creating the socket requires root privs
|
||||
drop_privileges();
|
||||
|
||||
// Find the index of the network interface
|
||||
struct ifreq ifr;
|
||||
strncpy(ifr.ifr_name, interface_name, IFNAMSIZ);
|
||||
errno = 0;
|
||||
if (ioctl(packet_socket, SIOCGIFINDEX, &ifr) == -1) {
|
||||
err(1, "ioctl");
|
||||
}
|
||||
|
||||
// Bind to the network interface
|
||||
struct sockaddr_ll sll;
|
||||
sll.sll_family = AF_PACKET;
|
||||
sll.sll_protocol = htons(ETH_P_ALL);
|
||||
sll.sll_ifindex = ifr.ifr_ifindex;
|
||||
errno = 0;
|
||||
if (bind(packet_socket, (const struct sockaddr*)&sll, sizeof(sll)) == -1) {
|
||||
err(1, "bind");
|
||||
}
|
||||
|
||||
// Get our own MAC
|
||||
errno = 0;
|
||||
strncpy(ifr.ifr_name, interface_name, IFNAMSIZ);
|
||||
if (ioctl(packet_socket, SIOCGIFHWADDR, &ifr) == -1) {
|
||||
err(1, "ioctl");
|
||||
}
|
||||
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
|
||||
errx(1, "Not an Ethernet interface");
|
||||
}
|
||||
memcpy(own_mac, ifr.ifr_hwaddr.sa_data, sizeof(own_mac));
|
||||
|
||||
// Print it out
|
||||
char own_mac_str[18];
|
||||
format_mac(own_mac, own_mac_str);
|
||||
fprintf(stderr, "%s\n", own_mac_str);
|
||||
|
||||
// Start the event loop
|
||||
eventloop();
|
||||
|
||||
// Close the socket (tho I'm not 100% sure it's needed)
|
||||
errno = 0;
|
||||
if (close(packet_socket) == -1) {
|
||||
err(1, "close");
|
||||
}
|
||||
|
||||
// Flush stdout
|
||||
errno = 0;
|
||||
if (fflush(stdout) == EOF) {
|
||||
err(1, "fflush");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue