How to write cross-platform packet capture from scratch in 1000 LOC.

How supports the both of Linux and macOS

RAW Socket

  1. Open socket descriptor with `PF_PACKET` as a protocol family, `SOCK_RAW` as a socket type and `htons(ETH_P_ALL)` as a protocol.
    int soc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))
  2. Retrieving information about network interface from the interface name.
    ioctl(soc, SIOCGIFINDEX, &if_req)
  3. Binding the socket descriptor to the interface.
    bind(soc, (struct sockaddr *) &sa, sizeof(sa))
  4. Get flags of the interface and enable promiscuous mode and set the interface up.
    ioctl(soc, SIOCGIFFLAGS, &if_req);
    if_req.ifr_flags = if_req.ifr_flags|IFF_PROMISC|IFF_UP;
    ioctl(soc, SIOCSIFFLAGS, &if_req);
struct timeval timeout;
fd_set mask;
int width, len, ready;
while (g_gotsig == 0) {
FD_ZERO(&mask);
FD_SET(soc, &mask);
width = doc + 1;
timeout.tv_sec = 8;
timeout.tv_usec = 0;
ready = select(width, &mask, NULL, NULL, &timeout);
if (ready == -1) {
perror("select");
break;
} else if (ready == 0) {
fprintf(stderr, "select timeout");
break;
}
if (FD_ISSET(sniffer->fd, &mask)){
if ((len = recv(soc, buffer, >buf_len, 0)) == -1){
perror("recv:");
return -1;
}
}
}

Berkeley Packet Filters

$ ls /dev/bpf?
/dev/bpf0 /dev/bpf1 /dev/bpf2 /dev/bpf3 /dev/bpf4 /dev/bpf5 /dev/bpf6 /dev/bpf7 /dev/bpf8 /dev/bpf9
  1. Open a bpf device.
    fd = open(params.device, O_RDWR)
  2. Set buffer length or get buffer length.
    ioctl(fd, BIOCSBLEN, &params.buf_len) : set buffer length
    ioctl(fd, BIOCGBLEN, &params.buf_len) : get buffer length
  3. Bind a BPF device into the interface.
    ioctl(fd, BIOCSETIF, &if_req)
  4. Enable promiscuous mode.
    ioctl(fd, BIOCPROMISC, NULL)
typedef struct {
int fd;
char device[11];
unsigned int buf_len;
char *buffer;
unsigned int last_read_len;
unsigned int read_bytes_consumed;
} Sniffer;
int
parse_bpf_packets(Sniffer *sniffer, CapturedInfo *info)
{
if (sniffer->read_bytes_consumed + sizeof(sniffer->buffer)
>= sniffer->last_read_len) {
return 0;
}
info->bpf_hdr = (struct bpf_hdr*)((long)sniffer->buffer +
(long)sniffer->read_bytes_consumed);
info->data = sniffer->buffer + \
(long)sniffer->read_bytes_consumed + \
info->bpf_hdr->bh_hdrlen;
sniffer->read_bytes_consumed += BPF_WORDALIGN(
info->bpf_hdr->bh_hdrlen + info->bpf_hdr->bh_caplen);
return info->bpf_hdr->bh_datalen;
}

References

  • https://github.com/bpk-t/packet_capture
  • https://github.com/google/gopacket/blob/master/bsdbpf/bsd_bpf_sniffer.go
  • https://www.freebsd.org/cgi/man.cgi?bpf(4)

--

--

--

Creator of go-prompt and kube-prompt. Optuna committer. Kubeflow/Katib reviewer. GitHub: c-bata

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Load Average in Linux Servers — Confusion Solved

Reduce Cost and Increase Productivity with Value Added IT Services from buzinessware — {link} -

Reduce Cost and Increase Productivity with Value Added IT Services from buzinessware — {link} -

How we Reduced Google BigQuery Cost by 50%

How we Reduced Google BigQuery Cost by 50%

Google BigQuery| CXL course review

JetBrains Toolbox: The best way to install IntelliJ IDEA on Linux

Mvastram.com customer care number 9832336299%9832336299

Ruby IntelliSense on VS Code with Solargraph

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Masashi SHIBATA

Masashi SHIBATA

Creator of go-prompt and kube-prompt. Optuna committer. Kubeflow/Katib reviewer. GitHub: c-bata

More from Medium

How to boot from USB via GRUB

How to study for the LFCS (Linux Foundation Certified System Administrator) exam

Converting and Optimizing Images From the Command Line

[Hands-on] Understanding multi-container host networking using vxlan overlay network feature.