Skip to content

Instantly share code, notes, and snippets.

@BobBurns
Last active February 1, 2021 14:54
Show Gist options
  • Save BobBurns/95f9a57f9a2c43a8e45fbb46977bcd17 to your computer and use it in GitHub Desktop.
Save BobBurns/95f9a57f9a2c43a8e45fbb46977bcd17 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <net/bpf.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/ethernet.h> // ETHERTYPE_IP
#include <netinet/in.h> // IPPROTO_TCP
#include <unistd.h>
#include <time.h>
#define ETHLEN 14
#define IPHLEN 40
#define UDPLEN 8
int
main (int argc, char *argv[])
{
printf("To capture DUID, bounce the interface connected to DHCPv6 capable endpoint\n");
char buf[11] = { 0 };
int bpf = 0;
for( int i = 0; i < 99; i++ )
{
sprintf( buf, "/dev/bpf%i", i );
bpf = open( buf, O_RDWR );
if( bpf != -1 )
break;
}
const char * interface = "en0";
struct ifreq net_if;
bcopy (interface, net_if.ifr_name, sizeof(interface));
if (ioctl (bpf, BIOCSETIF, &net_if) == -1 )
{
perror("ioctl");
exit(EXIT_FAILURE);
}
if (ioctl (bpf, BIOCPROMISC) < 0 )
{
perror("promisc");
exit(EXIT_FAILURE);
}
/**************************** filter machine program ************************/
struct bpf_insn bf_insns[] = {
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), // ethertype
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x86dd, 0, 15), // ipv6 type
BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, ETHLEN), //
BPF_STMT(BPF_LD+BPF_B+BPF_IND, 6), // Next header
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x11, 0, 12), // UDP 17
BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, ETHLEN+IPHLEN), // begin UDP header
BPF_STMT(BPF_LD+BPF_H+BPF_IND, 2), // dest port
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 547, 0, 9), // DHCPV6
BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, ETHLEN+IPHLEN+UDPLEN), // begin UDP header
BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0), // DHCPv6 message type
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 3, 0, 6), // DHCPV6 message type request
BPF_STMT(BPF_LD+BPF_H+BPF_IND, 4), // DHCPv6 Option
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 1, 0, 4), // DHCPV6 option client Identifier
BPF_STMT(BPF_LD+BPF_H+BPF_IND, 6), // DHCPv6 CID len
BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 8), // add offset
BPF_STMT(BPF_RET+BPF_A, -1), // return all bytes up to DUID
BPF_STMT(BPF_RET+BPF_K, 0), // drop
};
/************************ end filter machine program ***************************/
struct bpf_program bprog = {
sizeof(bf_insns) / sizeof(struct bpf_insn),
bf_insns
};
if (ioctl (bpf, BIOCSETFNR, &bprog) < 0 )
{
perror("BIOCSETFNR");
exit(EXIT_FAILURE);
}
int buf_len = 1;
// activate immediate mode (therefore, buf_len is initially set to "1")
if( ioctl( bpf, BIOCIMMEDIATE, &buf_len ) == -1 ) {
perror("BIOCIMMEDIATE");
exit(EXIT_FAILURE);
}
// request buffer length
if( ioctl( bpf, BIOCGBLEN, &buf_len ) == -1 ) {
perror("BIOCGBLEN");
exit(EXIT_FAILURE);
}
int read_bytes = 0;
// struct bpf_hdr* bpf_buf = calloc(buf_len, sizeof(struct bpf_hdr));
int i;
struct bpf_hdr* bhdr;
unsigned char* bpf_buf = malloc(buf_len);
#ifdef __APPLE__
struct timeval32 tsmp;
#else
struct timeval tsmp;
#endif
char *t;
for (;;) {
if (( read_bytes = read (bpf, bpf_buf, buf_len)) > 0)
{
bhdr = (struct bpf_hdr *)bpf_buf;
tsmp = bhdr->bh_tstamp;
t = ctime(&tsmp.tv_sec);
printf("time of packet:%s\n", t);
bpf_buf += bhdr->bh_hdrlen;
// assuming type 1
if (bpf_buf[(bhdr->bh_caplen)-15] != 0x0e) {
printf("Sorry not type 1 DUID. Exiting...");
break;
}
printf("DUID (first 3 bytes are length and type)\n");
printf("--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\n");
for (i = (bhdr->bh_caplen-15); i < bhdr->bh_caplen; i++) {
printf("%02X ", bpf_buf[i]);
}
printf("\nend\n");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment