Jelajahi Sumber

BPF samples

David Marec 8 bulan lalu
induk
melakukan
a91a686ac9
4 mengubah file dengan 290 tambahan dan 0 penghapusan
  1. 3 0
      sockraw/.gitignore
  2. 24 0
      sockraw/Makefile
  3. 93 0
      sockraw/README.md
  4. 170 0
      sockraw/sockbpf.c

+ 3 - 0
sockraw/.gitignore

@@ -0,0 +1,3 @@
+# Ignore everything in this directory
+obj/*
+

+ 24 - 0
sockraw/Makefile

@@ -0,0 +1,24 @@
+CFLAGS+=-O3 -Wall -fPIE -fno-strict-aliasing
+CFLAGS+=-Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough
+CFLAGS+=-Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
+CFLAGS+=-fstack-clash-protection -fstack-protector-strong
+CFLAGS+=-fstrict-flex-arrays=3
+
+LDFLAGS+=-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now,--strip-all -pie
+LDFLAGS+=-Wl,-z,nodlopen -Wl,-z,noexecstack,--no-copy-dt-needed-entries
+
+BPF=sockbpf
+BPF_OBJS=sockbpf.o
+
+.PHONY: clean
+.MAIN: $(BPF)
+
+$(BPF): $(BPF_OBJS)
+	$(CC) -o ${.TARGET} ${.ALLSRC} $(LDFLAGS)
+
+%o: 
+	$(CC) -o ${.TARGET} -c ${.IMPSRC}
+
+clean:
+	rm -f *.o $(BPF)
+

+ 93 - 0
sockraw/README.md

@@ -0,0 +1,93 @@
+# BPF / raw sockets samples
+
+* [man 4 bpf](https://man.freebsd.org/cgi/man.cgi?query=bpf&manpath=FreeBSD+14.2-RELEASE+and+Ports)
+* [man 4 epair](https://man.freebsd.org/cgi/man.cgi?query=epair&manpath=FreeBSD+14.2-RELEASE+and+Ports)
+
+Adaption sur _FreeBSD_ sous _bpf_ de codes écrits pour _Linux_ qui utilisait les mécanismes _raw sockets_ pour tester des boucles _Ethernet_.
+
+## sockbpf
+
+Créez une interface de type `epair`:
+
+```sh
+ifconfig create epair
+ifconfig epair0a 192.168.2.1/24
+ifconfig epair0b 192.168.2.2/24
+```
+
+Surveillez le trafic:
+```sh
+tcpdump -vv -i epair0b
+```
+
+Envoyez des packets forgés par `sockpvf`, sur une extrémité de l'interface:
+
+```sh
+ sudo ./obj/sockbpf -i epair0a -m "04:04:04:08:08:08" -v
+Mot de passe :
+Prepare to send 10 packets to epair0a.
+Packet #1 sent.
+Packet #2 sent.
+Packet #3 sent.
+Packet #4 sent.
+Packet #5 sent.
+Packet #6 sent.
+Packet #7 sent.
+Packet #8 sent.
+Packet #9 sent.
+Packet #10 sent.
+```
+
+* `-i`: interface où envoyer des trames;
+* `-m`: adresse MAC de destination;
+* `-v`: mode verbeux;
+* `-p`: nombre de trames à envoyer;
+
+Vous devriez voir les paquets entrer de l'autre coté:
+```sh
+tcpdump: listening on epair0b, link-type EN10MB (Ethernet), snapshot length 262144 bytes
+19:28:07.619115 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) Null Supervisory, Receiver Ready, rcv seq 0, Flags [Final], length 64
+19:28:07.619117 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) 802.1B I Information, send seq 1, rcv seq 1, Flags [Command], length 64
+	0x0000:  0202 0202 0202 0202 0202 0202 0202 0202  ................
+	0x0010:  0202 0202 0202 0202 0202 0202 0202 0202  ................
+	0x0020:  0202 0202 0202 0202 0202 0202 0202 0202  ................
+	0x0030:  0202 0202 0202 0202 0202 0202 0202 0202  ................
+19:28:07.619118 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) 802.1B I Unnumbered, ui, Flags [Response], length 64
+	0x0000:  0303 0303 0303 0303 0303 0303 0303 0303  ................
+	0x0010:  0303 0303 0303 0303 0303 0303 0303 0303  ................
+	0x0020:  0303 0303 0303 0303 0303 0303 0303 0303  ................
+	0x0030:  0303 0303 0303 0303 0303 0303 0303 0303  ................
+19:28:07.619118 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) SNA Information, send seq 2, rcv seq 2, Flags [Command], length 64
+	0x0000:  0404 0404 0404 0404 0404 0404 0404 0404  ................
+	0x0010:  0404 0404 0404 0404 0404 0404 0404 0404  ................
+	0x0020:  0404 0404 0404 0404 0404 0404 0404 0404  ................
+	0x0030:  0404 0404 0404 0404 0404 0404 0404 0404  ................
+19:28:07.619118 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) SNA Supervisory, Receiver not Ready, rcv seq 2, Flags [Final], length 64
+19:28:07.619120 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) IP Information, send seq 3, rcv seq 3, Flags [Command], length 64
+	0x0000:  0606 0606 0606 0606 0606 0606 0606 0606  ................
+	0x0010:  0606 0606 0606 0606 0606 0606 0606 0606  ................
+	0x0020:  0606 0606 0606 0606 0606 0606 0606 0606  ................
+	0x0030:  0606 0606 0606 0606 0606 0606 0606 0606  ................
+19:28:07.619123 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) IP Unnumbered, 07, Flags [Response], length 64
+	0x0000:  0707 0707 0707 0707 0707 0707 0707 0707  ................
+	0x0010:  0707 0707 0707 0707 0707 0707 0707 0707  ................
+	0x0020:  0707 0707 0707 0707 0707 0707 0707 0707  ................
+	0x0030:  0707 0707 0707 0707 0707 0707 0707 0707  ................
+19:28:07.619123 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) Unknown DSAP 0x08 Information, send seq 4, rcv seq 4, Flags [Command], length 64
+	0x0000:  0808 0808 0808 0808 0808 0808 0808 0808  ................
+	0x0010:  0808 0808 0808 0808 0808 0808 0808 0808  ................
+	0x0020:  0808 0808 0808 0808 0808 0808 0808 0808  ................
+	0x0030:  0808 0808 0808 0808 0808 0808 0808 0808  ................
+19:28:07.619126 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) Unknown DSAP 0x08 Supervisory, Reject, rcv seq 4, Flags [Final], length 64
+19:28:07.619126 02:a8:7b:88:0b:0a (oui Unknown) > 04:04:04:08:08:08 (oui Unknown) Unknown DSAP 0x0a Information, send seq 5, rcv seq 5, Flags [Command], length 64
+	0x0000:  0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a  ................
+	0x0010:  0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a  ................
+	0x0020:  0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a  ................
+	0x0030:  0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a  ................
+```
+
+Il s'agit de trames sans protocole identifié: le code correspond à la taille du cargo (_IEEE 802.3_).
+
+
+
+

+ 170 - 0
sockraw/sockbpf.c

@@ -0,0 +1,170 @@
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/bpf.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+
+#define	DEVICE_BPF	"/dev/bpf"
+static int verbose;
+static const char *out_net = "tap0";
+struct ether_addr *daddr;
+
+#define PAYLOAD_LEN 64
+union __attribute__((packed)) frame {
+	struct {
+		struct ether_header header;
+		unsigned char payload[PAYLOAD_LEN];
+	} frame;
+
+	unsigned char buffer[ETHER_MAX_LEN];
+} out_buffer ;
+
+
+/* bpf */
+int bpf = -1;
+
+static const char *fake_dest = "6:66:6:66:6:66";
+
+#define VPRINTF(...) if(verbose) {printf(__VA_ARGS__);};
+#define EPRINTF(...) do  {fprintf(stderr, __VA_ARGS__); } while(0);
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+	fputs("\nUsage:\n", stderr);
+	fputs("sockraw [--if net][--mac mac][--packets samples][--verbose]\n", stderr);
+	fputs("  --if     : interface\n", stderr);
+	fputs("  --mac    : destination MAC address\n", stderr);
+	fputs("  --packets: packets samples to sent\n", stderr);
+	fputs("  --verbose: verbose\n", stderr);
+	exit(EXIT_SUCCESS);
+}
+
+/* open BPF interface */
+static int get_first_bpf(void)
+{
+	size_t i = 0;
+	char buf[16] = {0};
+
+	for(; i < 99; ) {
+		sprintf(buf, "%s%zu", DEVICE_BPF, i++);
+		bpf = open(buf, O_RDWR);
+		if (bpf != -1)
+			break;
+
+		/* must have root access*/
+		if (errno == EACCES)
+			break;
+	}
+
+	return bpf;
+}
+
+static void sender(size_t nb)
+{
+	static unsigned char dummy;
+	size_t total = nb + 1;
+
+	printf("Prepare to send %zu packets to %s.\n", nb, out_net);
+
+	out_buffer.frame.header.ether_type = htons(PAYLOAD_LEN);
+	memcpy(out_buffer.frame.header.ether_dhost, daddr, ETHER_ADDR_LEN);
+
+	while (nb) {
+		memset(out_buffer.frame.payload, ++dummy, sizeof out_buffer.frame.payload);
+		ssize_t r = write(bpf, out_buffer.buffer,
+				sizeof out_buffer.frame.payload + sizeof(struct ether_header));
+
+		if (r == -1)
+			warn("Unable to send packet #%zu.\n", nb);
+		else
+			VPRINTF("Packet #%zu sent.\n", total - nb);
+
+		--nb;
+	}
+	printf("Done.\n");
+}
+
+int main(int argc, char *argv[])
+{
+	size_t packets = 10;
+	struct ifreq out_if = {0};
+	const char *mac_address = fake_dest;
+
+	/* options */
+	int ch;
+	static struct option longopts[] = {
+		{ "if"     , required_argument, NULL, 'i' },
+		{ "verbose", no_argument      , NULL, 'v' },
+		{ "mac"    , required_argument, NULL, 'm' },
+		{ "packets", required_argument, NULL, 'p' },
+		{ NULL,	0, NULL, 0 }
+	};
+	while ((ch = getopt_long(argc, argv, "vi:o:p:m:", longopts, NULL)) != -1) {
+		switch (ch) {
+			case 'v':
+				verbose = 1;
+				break;
+			case 'i':
+				out_net = optarg;
+				break;
+			case 'p':
+				packets = strtoul(optarg, NULL, 10);
+				break;
+			case 'm':
+				mac_address = optarg;
+				break;
+			case 0:
+				/* long option */
+				break;
+			default:
+				usage();
+		}
+	}
+
+	if (argc - optind != 0)
+		usage();
+
+	/* sanity checks */
+	daddr = ether_aton(mac_address);
+	if (daddr == NULL)
+		err(EXIT_FAILURE, "Cannot get mac destination");
+	if (strlcpy(out_if.ifr_name, out_net, sizeof(out_if.ifr_name)) >= sizeof(out_if.ifr_name))
+		errx(EXIT_FAILURE, "%s is not a valid interface name.\n", out_net);
+
+	/* man 4 BPF */
+	if (get_first_bpf() < 0)
+		err(EXIT_FAILURE, "Cannot open bpf interface");
+
+	/* Get net device index */
+	if (ioctl(bpf, BIOCSETIF, &out_if) == -1) {
+		warn("Cannot open %s interface.\n", out_net);
+		goto last;
+	}
+
+	/*
+	 * pointless until we do not read _from_ interface
+	 * static int dummy_true = 1;
+	 * if( ioctl( bpf, BIOCIMMEDIATE, &dummy_true ) == -1 ) {
+	 *		warn("Can not activate immediate mode.\n");
+	 *	}
+	 * if( ioctl( bpf, BIOCGBLEN, &buf_len ) == -1 ) {
+	 *                warn("Can not request buffer length\n");
+	 *                exit(1);
+	 *        }
+	 */
+	sender(packets);
+
+last:
+	close(bpf);
+
+	return EXIT_SUCCESS;
+}
+