Add arp-request.c
This commit is contained in:
parent
e29fd159d3
commit
7486c135a8
3 changed files with 197 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
*.swp
|
*.swp
|
||||||
*.o
|
*.o
|
||||||
ethertype-dump
|
ethertype-dump
|
||||||
|
arp-request
|
||||||
|
|
13
Makefile
13
Makefile
|
@ -7,24 +7,29 @@ CFLAGS += -Os -g -Wall -Wextra -pedantic
|
||||||
CPPFLAGS +=
|
CPPFLAGS +=
|
||||||
LDFLAGS +=
|
LDFLAGS +=
|
||||||
|
|
||||||
|
BINS := ethertype-dump arp-request
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
.PHONY: all install uninstall clean distclean
|
.PHONY: all install uninstall clean distclean
|
||||||
|
|
||||||
all: ethertype-dump
|
all: $(BINS)
|
||||||
|
|
||||||
ethertype-dump: ethertype-dump.o
|
ethertype-dump: ethertype-dump.o
|
||||||
$(CC) -o $@ $< $(LDFLAGS)
|
$(CC) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
|
arp-request: arp-request.o
|
||||||
|
$(CC) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
|
||||||
|
|
||||||
install: all
|
install: $(BINS)
|
||||||
install ethertype-dump $(BINDIR)
|
install $(BINS) $(BINDIR)
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm $(BINDIR)/ethertype-dump
|
cd $(BINDIR) && rm $(BINS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f ethertype-dump *.o
|
rm -f ethertype-dump *.o
|
||||||
|
|
187
arp-request.c
Normal file
187
arp-request.c
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
#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 <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>
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s interface ip\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *interface_name = argv[1];
|
||||||
|
const char *target_ip = argv[2];
|
||||||
|
|
||||||
|
// Create a packet socket
|
||||||
|
errno = 0;
|
||||||
|
int 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the Ethernet frame with ARP packet inside it
|
||||||
|
//
|
||||||
|
// NOTE: This uses network byte order. That is, most significant
|
||||||
|
// byte goes first, not last like with x86
|
||||||
|
//
|
||||||
|
// -- Ethernet --
|
||||||
|
// 0 Destination MAC (6B) == FF:FF:FF:FF:FF:FF (broadcast address)
|
||||||
|
// 6 Source MAC (6B)
|
||||||
|
// 12 EtherType (2B) == 0x0806
|
||||||
|
// -- ARP --
|
||||||
|
// 14 Hardware type (2B) == 0x0001 (Ethernet)
|
||||||
|
// 16 Protocol type (2B) == 0x0800 (IPv4 EtherType)
|
||||||
|
// 18 Hardware address length (1B) == 6
|
||||||
|
// 19 Protocol address length (1B) == 4
|
||||||
|
// 20 Opcode (2B) == 0x0001 (request)
|
||||||
|
// 22 Sender hardware address (6B for Ethernet)
|
||||||
|
// 28 Sender protocol address (4B for IPv4)
|
||||||
|
// 32 Target hardware address (6B for Ethernet) == FF:FF:FF:FF:FF:FF (the value is ignored)
|
||||||
|
// 38 Target protocol address (4B for IPv4)
|
||||||
|
//
|
||||||
|
// = 42B
|
||||||
|
unsigned char frame[42];
|
||||||
|
memset(frame, 0, sizeof(frame));
|
||||||
|
|
||||||
|
// Destination MAC
|
||||||
|
memset(&frame[0], 0xff, 6);
|
||||||
|
|
||||||
|
// Source 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(&frame[6], ifr.ifr_hwaddr.sa_data, 6);
|
||||||
|
|
||||||
|
// EtherType
|
||||||
|
frame[12] = 0x08;
|
||||||
|
frame[13] = 0x06;
|
||||||
|
|
||||||
|
// Hardware type
|
||||||
|
frame[14] = 0x00;
|
||||||
|
frame[15] = 0x01;
|
||||||
|
|
||||||
|
// Protocol type
|
||||||
|
frame[16] = 0x08;
|
||||||
|
frame[17] = 0x00;
|
||||||
|
|
||||||
|
// Hardware address length
|
||||||
|
frame[18] = 6;
|
||||||
|
|
||||||
|
// Protocol address length
|
||||||
|
frame[19] = 4;
|
||||||
|
|
||||||
|
// Opcode
|
||||||
|
frame[20] = 0x00;
|
||||||
|
frame[21] = 0x01;
|
||||||
|
|
||||||
|
// Sender hardware address
|
||||||
|
// This is the same as source MAC in the Ethernet header
|
||||||
|
memcpy(&frame[22], &frame[6], 6);
|
||||||
|
|
||||||
|
// Sender protocol address
|
||||||
|
errno = 0;
|
||||||
|
strncpy(ifr.ifr_name, interface_name, IFNAMSIZ);
|
||||||
|
if (ioctl(packet_socket, SIOCGIFADDR, &ifr) == -1) {
|
||||||
|
err(1, "ioctl");
|
||||||
|
}
|
||||||
|
if (ifr.ifr_addr.sa_family != AF_INET) {
|
||||||
|
errx(1, "Somehow, we've gotten a non-IPv4 address from kernel");
|
||||||
|
}
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
|
||||||
|
memcpy(&frame[28], &sin.sin_addr.s_addr, 4);
|
||||||
|
|
||||||
|
// Target hardware address
|
||||||
|
memset(&frame[32], 0xff, 6);
|
||||||
|
|
||||||
|
// Target protocol address
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
errno = 0;
|
||||||
|
if (inet_pton(AF_INET, target_ip, &sin.sin_addr) == -1) {
|
||||||
|
err(1, "inet_pton");
|
||||||
|
}
|
||||||
|
memcpy(&frame[38], &sin.sin_addr.s_addr, 4);
|
||||||
|
|
||||||
|
// Send the frame
|
||||||
|
errno = 0;
|
||||||
|
if (write(packet_socket, frame, sizeof(frame)) != sizeof(frame)) {
|
||||||
|
err(1, "write");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the socket (tho I'm not 100% sure it's needed)
|
||||||
|
errno = 0;
|
||||||
|
if (close(packet_socket) == -1) {
|
||||||
|
err(1, "close");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue