Start working on the network-facing side of Ethermess
This commit is contained in:
parent
829cd7fdfb
commit
211473b48e
3 changed files with 205 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
*.o
|
*.o
|
||||||
ethertype-dump
|
ethertype-dump
|
||||||
arp-request
|
arp-request
|
||||||
|
ethermess
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -7,7 +7,7 @@ CFLAGS += -Os -g -Wall -Wextra -pedantic
|
||||||
CPPFLAGS +=
|
CPPFLAGS +=
|
||||||
LDFLAGS +=
|
LDFLAGS +=
|
||||||
|
|
||||||
BINS := ethertype-dump arp-request
|
BINS := ethertype-dump arp-request ethermess
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
@ -22,6 +22,9 @@ ethertype-dump: ethertype-dump.o
|
||||||
arp-request: arp-request.o
|
arp-request: arp-request.o
|
||||||
$(CC) -o $@ $< $(LDFLAGS)
|
$(CC) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
|
ethermess: ethermess.o
|
||||||
|
$(CC) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
|
200
ethermess.c
Normal file
200
ethermess.c
Normal file
|
@ -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 a new issue