Berkeley Packet Filters (BPF)

WiresharkBeginner
Practice Now

Introduction

Welcome to the Berkeley Packet Filters (BPF) lab!

Imagine trying to find a single, specific conversation in a crowded, noisy stadium. That is what analyzing raw network traffic feels like. A busy server might handle thousands of packets every second. To find the specific data you need, you require a highly precise strainer.

This is where Berkeley Packet Filters (BPF) come in. BPF is a deeply integrated, highly efficient technology that allows you to set up rules—like a specialized fishing net—to catch only the exact network traffic you care about, letting the rest pass by unnoticed.

The important idea is that filtering is not merely about convenience. It is about reducing noise before it becomes a problem. Without filters, packet analysis quickly turns into information overload. With filters, you can turn a huge, messy stream into a focused question such as "show me traffic from this host" or "show me only web requests to this port." That ability is one of the main reasons tcpdump remains useful even in large production environments.

In this lab, you will use tcpdump to practice writing these BPF rules. You will learn how to filter the chaotic network stream by specific IP addresses, control the direction of the traffic (sending vs. receiving), and target specific application ports. By the end, you will know how to combine these rules to surgically extract the exact events you need.

Filter by IP Address (Host/Network)

The most basic way to filter traffic is by focusing on a specific machine, identified by its IP address. When you run tcpdump without any filters, it relentlessly grabs every packet it sees. To tell it to ignore everything except traffic involving a particular machine, you use the host keyword followed by the IP address.

This is a good moment to separate two concepts that beginners often mix up: an interface is where you are listening, while an IP filter describes which conversations you want from that listening point. In other words, -i lo decides where your microphone is placed, and host 127.0.0.1 decides which speaker in the room you care about.

To ensure we have traffic to observe, a background script is already running in your environment. It is continuously sending data to your local machine, which always has the internal IP address 127.0.0.1 (also known as localhost).

Let's capture 5 packets that involve this local host. We will use -i lo to listen on the local loopback interface and -c 5 to stop automatically.

Run the following command in your terminal:

sudo tcpdump -i lo -c 5 host 127.0.0.1

Your screen will display an output similar to this:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:15:32.123456 IP localhost.45678 > localhost.http-alt: Flags [S], seq 123456789, win 65495, options [mss 65495,sackOK,TS val 123456 ecr 0,nop,wscale 7], length 0
10:15:32.123489 IP localhost.http-alt > localhost.45678: Flags [S.], seq 987654321, ack 123456790, win 65483, options [mss 65495,sackOK,TS val 123456 ecr 123456,nop,wscale 7], length 0
10:15:32.124000 IP localhost > localhost: ICMP echo request, id 1234, seq 1, length 64
...
5 packets captured

Notice that in every listed packet, localhost (which is the friendly name for 127.0.0.1) is present. The host filter is highly inclusive: it captures the packet regardless of whether the specified IP address sent the data or received it.

If you ever need to monitor an entire neighborhood of computers rather than a single house, you can swap the host keyword for net (for example, net 192.168.1.0/24). For now, we will stick to exploring our single host.

Filter by Direction (Source/Destination)

Knowing that a specific computer is involved in a conversation is helpful, but sometimes you need more precision. Imagine a post office: you might want to look only at the letters a person is sending out, completely ignoring the letters they are receiving.

Direction matters because send and receive traffic often answer different investigative questions. Outbound traffic can reveal what a host is trying to contact, which is useful when hunting malware callbacks or data exfiltration. Inbound traffic can reveal what services are being targeted, which is useful when investigating scans or attacks against a server.

BPF gives you the src (source) and dst (destination) modifiers to dictate the exact direction of the traffic.

Let's refine our filter to capture only the packets that are originating from 127.0.0.1. By combining the src modifier with our previous host keyword, we tell tcpdump exactly what to look for.

Execute the following command:

sudo tcpdump -i lo -c 3 src host 127.0.0.1

A quick tip: Writing src 127.0.0.1 works too because the word host is assumed, but spelling it out as src host is considered best practice as it makes your command incredibly easy to read.

Your output will look like this:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:20:15.555111 IP localhost.54321 > localhost.http-alt: Flags [P.], seq 1:85, ack 1, win 512, options [nop,nop,TS val 234567 ecr 234567], length 84
10:20:15.555888 IP localhost.http-alt > localhost.54321: Flags [.], ack 85, win 512, options [nop,nop,TS val 234568 ecr 234567], length 0
10:20:16.111222 IP localhost > localhost: ICMP echo request, id 5678, seq 1, length 64
3 packets captured

If you look closely at the output, the first part of the packet description (the section before the > symbol) represents the sender (source). Because we are capturing on the internal loopback interface, both sides say localhost, but in a real-world scenario spanning multiple computers, src guarantees you are only viewing the outbound traffic from that specific address.

Conversely, if you wanted to act as a receiver and only watch incoming traffic arriving at the machine, you would simply use dst host 127.0.0.1.

Filter by Port and Protocol

Filtering by IP addresses gets us to the right machine, but modern servers multitask heavily. A single server might simultaneously act as a web server, an email server, and a secure access point. These different services are kept separate by using numbered "doors" called ports.

Ports are not physical sockets. They are logical numbers used by the operating system to keep many conversations separate at the same time. This is why "same host" does not necessarily mean "same application." One machine can be involved in many unrelated network activities, and port filtering helps you isolate the exact service you intend to study.

For instance, regular web traffic almost always flows through port 80. To zoom in on a specific service and ignore the rest, we use the port keyword.

Our background script happens to be quietly generating web traffic on port 8080. Let's configure tcpdump to capture only the data passing through this specific doorway.

Run the following command:

sudo tcpdump -i lo -c 4 port 8080

Example output:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:25:10.123456 IP localhost.34567 > localhost.http-alt: Flags [S], seq 1122334455, win 65495, options [mss 65495,sackOK,TS val 345678 ecr 0,nop,wscale 7], length 0
10:25:10.123489 IP localhost.http-alt > localhost.34567: Flags [S.], seq 5544332211, ack 1122334456, win 65483, options [mss 65495,sackOK,TS val 345678 ecr 345678,nop,wscale 7], length 0
10:25:10.123501 IP localhost.34567 > localhost.http-alt: Flags [.], ack 1, win 512, options [nop,nop,TS val 345678 ecr 345678], length 0
10:25:10.124111 IP localhost.34567 > localhost.http-alt: Flags [P.], seq 1:85, ack 1, win 512, options [nop,nop,TS val 345679 ecr 345678], length 84
4 packets captured

You might recall from earlier steps that there were ICMP (ping) packets floating around. However, in this output, there is absolutely no sign of them. The port 8080 filter successfully ignored all unrelated chatter, providing a clean view of just the web service.

In addition to ports, you can also filter by the broad network protocol directly by just naming it, using keywords like tcp, udp, or icmp. Let's test this by capturing only the ICMP (ping) packets, effectively ignoring the busy web traffic.

Run this command:

sudo tcpdump -i lo -c 2 icmp

Example output:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:28:05.999111 IP localhost > localhost: ICMP echo request, id 9012, seq 1, length 64
10:28:05.999133 IP localhost > localhost: ICMP echo reply, id 9012, seq 1, length 64
2 packets captured

Using port and protocol keywords allows you to slice through the noise and zero in on exactly the application you are trying to investigate.

Combine Filters with Logic (AND/OR)

To truly master Berkeley Packet Filters, we must learn how to combine multiple rules together. Real-world investigations are rarely straightforward; you often need to define highly specific scenarios.

This is where BPF starts to feel less like a list of keywords and more like a small query language for packets. You are describing the traffic you want in a structured, logical way. Later in the course, this way of thinking will reappear in many tools: SIEM searches, intrusion detection rules, and even database-style log queries all rely on the same habit of narrowing a broad dataset into a precise condition.

BPF allows you to glue conditions together using standard logical operators:

  • and (both rules must be true)
  • or (at least one rule must be true)
  • not (the rule must explicitly be false)

An important tip: When using logical operators like these in the Linux terminal, it is a very good habit to wrap your entire BPF expression in quotation marks (like "port 80 and tcp"). This ensures the Linux shell does not accidentally confuse your filter commands for system commands.

Let's test this out. We want to capture traffic that is strictly using the TCP protocol and is actively headed to the destination port 8080.

Run the following command:

sudo tcpdump -i lo -c 4 "tcp and dst port 8080"

Example output:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:32:15.111222 IP localhost.45678 > localhost.http-alt: Flags [S], seq 2233445566, win 65495, options [mss 65495,sackOK,TS val 456789 ecr 0,nop,wscale 7], length 0
10:32:15.111255 IP localhost.45678 > localhost.http-alt: Flags [.], ack 3344556678, win 512, options [nop,nop,TS val 456789 ecr 456789], length 0
...
4 packets captured

In this tailored result, localhost.http-alt only ever appears on the right side of the > arrow, proving we only captured packets destined for that exact port.

Finally, let's look at the not operator. It is incredibly useful for filtering out the "known noise" so you can focus on the unknown. Imagine we want to monitor all traffic on the loopback interface, except for our noisy web traffic on port 8080.

Run this command:

sudo tcpdump -i lo -c 2 "not port 8080"

Example output:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:35:22.333444 IP localhost > localhost: ICMP echo request, id 3456, seq 1, length 64
10:35:22.333466 IP localhost > localhost: ICMP echo reply, id 3456, seq 1, length 64
2 packets captured

Because we explicitly told tcpdump to banish port 8080 from the results, it peacefully captured the underlying background ICMP ping packets instead. By strategically chaining and, or, and not, you can forge an incredibly precise lens to see exactly what you need on any network.

Summary

Congratulations! You have successfully stepped into the world of advanced packet filtering.

You have learned how to sift through a chaotic network stream to find exactly what you need. You practiced targeting specific computers using the host keyword and controlled the flow direction with src and dst. You isolated particular applications by filtering for a distinct port and protocol. Most importantly, you learned how to combine all these individual pieces together using logical operators (and, or, not) to construct surgical, highly specific searches.

These skills are indispensable. Whether you are a system administrator hunting down a rogue connection or a security analyst tracking a sophisticated attack, mastering Berkeley Packet Filters ensures you will never be overwhelmed by the noise of the network again. Keep experimenting with different combinations!