Firewalling and other packet stuff

From Helpful
Jump to: navigation, search
Linux-related notes
Linux user notes

Shell, admin, and both:

Shell - command line and bash notes · shell login - profiles and scripts ·· find and xargs and parallel · screen and tmux ·· Shell and process nitty gritty ·· Isolating shell environments

Linux admin - disk and filesystem · Linux networking · Init systems and service management (upstart notes, systemd notes) · users and permissions · Debugging · security enhanced linux · PAM notes · health and statistics · kernel modules · YP notes · unsorted and muck

Logging and graphing - Logging · RRDtool and munin notes
Network admin - Firewalling and other packet stuff ·

Remote desktops

For other network related things, see:


On ports

On port allocation

One division:

for common services, and OSes may deny user programs to listen to these ports, for security reasons (e.g. making it a little harder to replace common services).

  • IANA considers registerable ports to be 1024 through 49151, and above that to be "dynamic and/or private ports"

  • The concept of ephemeral ports is the range that is used for network calls that don't care what port gets used
primarily outgoing connections (allocated by the OS)
incoming connections for services that should not occupy the listening port (notably HTTP) (verify)
the precise range of posts considered ephemeral varies per OS (and sometimes version of it)
most OSes make a split between ephemeral and non-ephemeral
ephemeral is regularly some range within 50K-65K (staying above the IANA registerable range), and most OSes allocate at least 4000 ephemeral ports, so there is usually no need to change this.
your basic workstation only really needs them when making making outbound connections, and often at most a few dozen at a time. Even things like peer-to-peer protocols often don't reach this limit
some very busy servers may wish to expand the range of their ephemeral ports (in part because a port can't be reused for a minute or so due to the TIME_WAIT detail of TCP)

Ephemeral ranges according to...:

  • Windows
    • before Vista used 1025 through 5000.
    • since Vista it uses 49152 through 65535.
  • Linux
    • often 32768 through 61000 (verify)
    • see /proc/sys/net/ipv4/ip_local_port_range
  • BSD
    • 1024 through 4999
    • freeBSD ≥4.6 uses ≥49152

In practice, these ranges are not very strict.

Various services choose ports in any of these ranges.

See also:

Some interesting ports

  • Remote login (and some transfer)
    • 22:SSH (also SCP, SFTP, also rsync over SSH and others)
    • 5900+n:VNC, where n is the display number and most uses stay under a handful (a hundred down (5800+ etc) is the java client you can mostly ignore)
    • 23:telnet
    • 177:XDMCP, 6000+:X windows
  • Internetty metadata
    • 53/UDP:DNS (apparently 53/TCP is used to sync DNS servers)
    • 520:RIP, 521:RIPng, 513 (router stuff)
    • 43:WHOIS
  • Web pages
    • 80:HTTP
    • 443:HTTPS
    • 8080, 8880, 8888 and such: conventions for HTTP-served containers, small services and such
  • Mail:
    • 25:SMTP
    • 110:POP3
    • 995:POP3/SSL
    • 143:IMAP
    • 993:IMAP/SSL (it seems syncing with exchange)
    • 465:SMTP/SSL
    • 691:SMTP/LSA (Only exchange?(verify))
  • LAN, file, and servery stuff:
    • 67 and 68:DHCP/BOOTP server and client, 69:TFTP
    • 524:NCP (Netware Core Protocol)
    • 631:IPP (Internet Printing Protocol)
    • 860:iSCSI
    • 5000:UPnP, 1900:SSDP (UPnP discovery)
    • 389:LDAP, 636:LDAP/SSL
    • 137/UDP:NETBIOS nameservice, 138/UDP:NETBIOS datagram, 139/UDP:NETBIOS session, 445/TCP:SMB-over-TCP
    • 1512:WINS
    • 5432:PostgreSQL, 1521:OracleSQL, 1433:MSSQL, 3306:MySQL
    • 1812 and 1813:RADIUS
    • 21:FTPcommand, 20:FTPdata, 873:rsync (unless over ssh),
    • 2049:NFS, 111:sunrpc portmapper
    • 161:SNMP (also 162),
    • 1194:OpenVPN, 1723:MS PPTP VPN, 1701:l2tp
  • Chat and such:
    • 6667:IRC (convention; may differ. IRC over SSL regularly uses port 994)
    • 5222:Jabber client-to-server, 5269:Jabber server-to-server, 5223:Jabber-secure

For longer lists, see:


This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Packet paths

The short introduction

You usually only care about packets following one of these three paths:

  • network → PREROUTING → INPUT → local process (data coming in for your apps)
  • local process → OUTPUT → POSTROUTING → network (data going out, from your apps)
  • network → PREROUTING → FORWARD → POSTROUTING → network (data passing through)

This means

usually, INPUT, OUTPUT, and FORWARD are interesting chains for filtering (...different kinds of traffic)
while PREROUTING and POSTROUTING are there for doing complex things such as packet alteration for fun, profit, routing, NAT, and such

Networking is an 'as fast as possible' sort of resource, so rules are compiled to their simplest-to-evaluate binary form of, usually, little more than a few bitmasks and comparisons. Even in the text form you write, they will be mostly numeric already, (Speed is also served by using "use only the first rule that applies, nothing else" logic.

Some of the more complex rules (e.g. l7 stuff) takes a little longer to evaluate, so don't use those when you care about speed. Or at least put all the common fast stuff above them (l7 stuff tends to be fallback rejections).

A slightly longer story; Tables and chains from a few perspectives

Soooo, netfilter largely consists of:

  • tables
    • mostly for organization.
    • Within each chain in a path, each table could apply. That is, any table may have that chain, and if it does, it will be used. (in a predefined order, apparently conntrack, mangle, nat, filter (unsure -- (verify)))
    • May use some (or all) of the commonly predefined chains - see the common capitalized names below. May introduce new chains, but rarely do.
    • On the common tables:
      • filter
        • you can assume you have this. It's all you need for an incoming-stuff firewall. Also the default table for iptables commands.
        • mostly used to filter out packets in the stages INPUT, FORWARD, and/or OUTPUT. (You can do it in other tables, but this tends to be unnecessary)
      • mangle
        • frequently present
        • often empty if you're not a router or fancy server
        • supports MARK, TOS, TTL targets
        • mangle/PREROUTING is used for things like altering TOS
        • mangle/INPUT is for mangling the packet just before it goes to the process -- not often a critical feature.
      • nat
        • often empty if you're not a router or fancy server
        • often for DNAT (in PREROUTING), SNAT (in POSTROUTING)
      • conntrack
        • less usually present
        • often empty if you're not a router or fancy server
        • only applies in PREROUTING and OUTPUT, and can't really be controlled directly (verify)
  • chains (and targets)
    • Predefined ones: {{comment|(PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING. These are created when modules are loaded.
    • can additionally define your own, usually for clarity of management or reuse (example: a chain containing trusted IPs, which you would probably unconditionally jump to at the start of filter's INPUT)
    • Chains mostly consist mostly of a list of rules
  • rules
    • ...that sit in specific chains. Each rule tends to represent a single case of filtering, alteration or such. Many have the function of throwing a packet over to another chain.

Also interesting but not part of the most central terminology:

  • Modules
    • ...refer to the fact that things can be loaded/added at runtime (as well as be compiled in).
    • usually add tables (usually what they're for)
    • may add new chains
    • may have specific targets (for example, mangle supports/adds MARK, TOS, TTL)
  • targets
    • can be jumped to (just like chain names), but represent behaviour (more specific than jumping around).
    • ACCEPT, REJECT, DROP, LOG, QUEUE, and RETURN are common targets,

The predefined chains (and other predefined names) are usually the most useful/important ones to getting packets in, out, and past, and doing so in an understandable way.

While you can customize it (for organization, a sort of conditional logic on streams of packets), in practice people rarely deviate from the images you see around various explanations, like:

first version; probably contains mistakes

There are some limitations of what type of rules are accepted in specific chains and specific tables.

In the end you're working in a flexible rule system, and it's not hard to create things that make make little sense, are very hard to predict the behaviour of, or are an unnecessarily complex.

Yet most people stick to minimal understandable things, not least because most examples try to be like that.

Probably the three most common paths, in a little more detail:

  • packets generated by a local process go via OUTPUT to POSTROUTING, often:
    • mangle/OUTPUT (often unused)
    • nat/OUTPUT
    • filter/OUTPUT (if you think this useful)
    • mangle/POSTROUTING
    • nat/POSTROUTING (mostly for SNAT, MASQUARADE)

  • packets destined for a local process go via PREROUTING and INPUT to that process
    • mangle/PREROUTING
    • nat/PREROUTING (mostly for DNAT)
    • mangle/INPUT
    • filter/INPUT (the place where most firewalling for this node happens)

  • packets routed through this node go from PREROUTING to FORWARD to POSTROUTING and onto some network again, often specifically:
    • mangle/PREROUTING
    • nat/PREROUTING (mostly for DNAT)
    • mangle/FORWARD (only necessary if you want to mangle in a way that affects routing decisions in the path -- otherwise it can go into another mangle step)
    • filter/FORWARD
    • mangle/POSTROUTING
    • nat/POSTROUTING (mostly for SNAT, MASQUARADE)

(note that PREROUTING can divert a packet to FORWARD through DNATting, in which case it's actually the next case...). As such, there is only a difference after PREROUTING -- there is a routing decision there that checks whether the packet is targeted at this node or not, and sends it to to INPUT or FORWARD accordingly.

Managing rules

is the classic CLI tool to manage netfilter - to the point netfilter and iptables are near-synonyms to many.

Rule format (the intersting bit)

Commands to add rules look something like like:

# accept all incoming traffic to interface eth0
iptables -t filter -A INPUT -i eth0 -j ACCEPT
# accept all incoming traffic with target IP
iptables -t filter -A INPUT -s -j ACCEPT
# Accept all incoming TCP traffic on port 6001 (most "accept/block service" rules will look like this)
iptables -t filter -A INPUT -p tcp -m tcp --dport 6001 -j ACCEPT
# apply source address translation (e.g. when we are a gateway) 
iptables -t nat    -A POSTROUTING -s -o eth0 -j SNAT --to-source
# Mark specific packets  (within local handling. done for further rules, or for statistics)
iptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --sport 21 -j MARK --set-mark 0x4

The first three are filtering rules (the first two of which are very similar in effect), the last two are more complex.

Let's pick some of them apart.

When creating chain contents, each rule has:

  • -t table. When omitted this defaults to
    , so often is omitted on firewall rules
  • -A chain to append to a chain (or -I to insert, possibly -R to replace)
  • -j: what target to jump the packet to. (There is also -g for goto, ((verify) the difference)

It quite likely has one of the general match options

  • -s and/or -d: source and destination address or network, specifically for (any subprotocol of) IP
  • -p protocol: ommited means 'all'; the other options are tcp, udp, and icmp.
  • -i interface: incoming interface (optional; default is all. Note that you can do things like eth+ to match eth0, eth1, etc.).
  • (-o interface analogously, for outgoing packets)

Many further options are specific values to specify the type of thing you are matching.

Match types are usually a specific type of filter. You can use more than one match in a rule.

Match types are pluggable at kernel/kernel-module level, so may or may not be available to you without a modprobe or some kernel recompilation.

The common match types that you can count on are tcp and udp, and also mport or multiport - these will serve all your port filtering needs.

Since you can construct illogical match combinations, there is the occasionaly apparent redundancy, and there may be dependencies. For example, when using -m tcp (or udp, mport, multiport(verify)), you also have to specify -p tcp or -p udp.

match types

Specified with -m. Many of these have to be compiled into the kernel and some are OS-specific. The most useful are:

  • tcp, udp: all packets of respective transport protocol
  • mport, multiport, in case you want ranges or lists of ports at a time
  • state: NEW, ESTABLISHED, RELATED, INVALID, useful to blindly allow packets belonging to connections which we scrutinized at establish time

Some of the following are generally interesting, a few depends on extra services, and you'll probably never use most:

  • recent: automatically maintain a blacklist. For example allows blockign people that try many connections in a short amount of time (e.g. to avoid being brute forced)
  • connbytes, connrate, limit, dstlimit, connlimit, hashlimit: allows matching/limiting of total connection trasfer, byte/packet rate/size or connection count, per service/net/etc.
  • psd: attempts to match on packets coming from portscans

  • iprange, mac: IP ranges, source MAC address. Mostly useful for filtering.
  • tcpmss, tos, ttl, conntrack, length, mark, connmark, pkttype: various packet property matches, including the MARK (see mangling). pkttype is link-layer type: unicast, broadcast, or multicast
  • u32: u32 matches up to 4-byte values in a packet, which is useful to pick out packet details without specific support

  • time: time-of-day, on weekdays, 'inside date range'.
  • random, nth: probability-based packet matcher, or every-n packet matcher
  • osf: passive OS fingerprinting
  • account, quota: packet counters, either for feedback via proc or for a quota system
  • owner: match uid, gid, command of locally generated packets


Targets can be basic chains: (or custom ones)


...special targets (common policies):

  • ACCEPT basically means "Sure, right. Just let it through to the next chain in line"
  • DROP is a packet trash can. It will make the client wait for a response, slowing it down. Used to be called DENY
  • REJECT: (common extension) respond with an ICMP-based rejection / problem signal packet
  • RETURN returns the packet to the previous chain it came from (allows complex as well as confusing logic)
  • QUEUE is a pass to userspace


  • SNAT (in nat-postrouting): Source Network Address Translation: source IP is changed, source port can be.
  • DNAT (in nat-postrouting): Destinaton Network Address Transation
  • MASQUERADE: dynamic version of the above
  • BALANCE: round-robin DNATting over a range of target IPs

(fancy stuff you'll probably never use)

...and others, various of which may need kernel support.

  • LOG, ULOG: Log to syslogd/syslog-ng/otehers, or a socket-based logger like ulogd (useful to e.g. redirect into a database). There are analysis tools for some of these targers (like there are for webserver logs)
  • TARPIT: accepts the initial connection, but no data. This slows down certain types of scans. (Not great against a DDoS since it also uses local resources)
  • TOS, TTL, TCPMSS, MARK, CONNMARK, IPMARK: Alter packet details
  • REDIRECT, NETMAP, SAME, MIRROR: More packet mangling, mostly IP address/net-related
  • ROUTE: override routing decision details
  • ...and more.

Note: Some of these have the effect of doing -j RETURN themselves. For example, you can -j LOG and it will continue processing in the chain that -j LOG is in.(verify)

tools to make it easier


"Uncomplicated Firewall"

Used by: Ubuntu

GUIs: gufw

interfaces via iptables(verify)

rule format and CLI are friendlier than bare iptables

config: main config at /etc/default/ufw, including things under /etc/ufw/ (verify)

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Used by: RedHat family

interfaces via iptables(verify)

config: xml files under /usr/lib/firewalld/ and /etc/firewalld/

DBus interface

Seeing whether your firewall is on, and which you have in the first place

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Checking which you have

Since most things manipulate netfilter, seeing something with iptables doesn't tell you what, if anything is managing these. So you have to poke around.

You can check for a service, but that requires knowing already, and I've more than once found a happy started service, (e.g. via
sudo systemctl status firewalld
that had an empty configuration.

Since two common firewalls these days are ufw and firewalld (defaults for ubuntu and redhat/centos/fedora, respectively), try querying their status:

sudo ufw status
sudo firewall-cmd --state    # or maybe --list-all

There's a bunch of others, like IPCop, Shorewall, Vuurmuur (and a bunch more network OSes, that is, ones intended to be run alone on network devices, e.g. shielding others. This seems to include e.g. pfSense, VyOS, untangle), but these are more likely to be installed by your admin and you should talk to them.

Note also that older systems had an 'iptables' service that was not a manager, but just ran a script that ran a bunch of "iptables add" style rules (and often saved it to disk when stopping the service, to persist around reboot).

Since basically everything is just wrapping netfilter (and frequently via iptables(verify)), a somewhat better check of actual functionality is to just see the rules currently active within netfilter:

sudo iptables -S

(or iptables-save, but it's just silent when you forget to sudo, and sometimes around SELinux issues)

(Note that seeing things like FORWARD_IN_ZONES, FORWARD_OUT_ZONES, FWDO_public, FWDI_public is a sign of firewalld (verify))

To also estimate whether it does what you think is to see how many packets/bytes ends up on a rule, e.g. via:

sudo iptables -L -v

A more thorough check of the same is to (temporarily) log dropped packets, to see whether it's doing what it intends.

See e.g.

Slightly easier with ufw (
ufw logging on

Simple firewall

(Glossing over a lot of details...)

A simple and common approach is to whitelist things you want to allow, and deny everything else, for example:

# Allow packets from previously approved connections
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# Allow everything from-and-for localhost
iptables -A INPUT -s -j ACCEPT
# Allow ssh from anywhere
iptables -A INPUT -m tcp -p tcp --dport 22 -j ACCEPT
# Allow web requests from anywhere (assuming this computer has a web server)
iptables -A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
# Allow anything from my own workstation, by IP address
iptables -A INPUT -s -j ACCEPT
# Allow anything from my handheld device, by MAC address 01:23:45:67:89:ab
iptables -A INPUT -m mac --mac-source 01:23:45:67:89:ab -j ACCEPT
# Allow SMB file sharing for my housemates (on
iptables -A INPUT -m tcp -p tcp -s -m multiport --dports 139,445 -j ACCEPT
iptables -A INPUT -m udp -p udp -s -m multiport --dports 137,138 -j ACCEPT
# Allow ICMP traffic  (Ping and such)
iptables -A INPUT -m icmp -p icmp -j ACCEPT
# Deny everything else (could also be set as a table's default policy instead of an explicit last rule)
iptables -A INPUT -j REJECT --reject-with icmp-port-unreachable


  • Multiport is vaguely recent; if you don't have it, you may need to write multiple rules to the same effect.
  • Ports 137/udp, 138/udp, 139/tcp, 445/tcp (and arguably 135/tcp) are ports for SMB file sharing
  • Rejecting is usually done for all protocols (including the potentially useful ICMP, for pinging), or done per-protocol. The above allows all ICMP, some TCP and UDP ports, and rejects everything else (including protocols other than icmp, tcp, and udp, if you get/use any)
  • even if you want to reject ICMP pings, you should probably never block type 3 code 4 ('must fragment') on a serious site.
  • REJECT tells off the other end, DROP means no response is sent at all (meaning the connection has to time out on the client side, which will will slow down scanners a bit, but also honestly misguided connections)

Extra chains

Statistics and Logging


iptables keeps track of how much data comes through each chain, and has been handled by each rule. For an overview, see:

iptables -vL 

While this isn't so useful to do per-host or per-port analyses (there are prettier tools that do that already), it's potentially useful for somewhat more specific checks.

For example, the combination, to get an idea of how much your web server is being served by the LAN, versus from the internet, you can get a decent idea with:

-A OUTPUT -p tcp -m tcp -s --sport 80
-A OUTPUT -p tcp -m tcp ! -s --sport 80

Side note: altering the table seems to zero counters. You and any pretty-graph-makers should probably be aware of that.

(Note that this can also be a lot more efficient than logging, which is inevitably to disk, so you don't want to log everything, so you want to make a little diagram for what it does, particularly if you have any jumps in your rules, etc).

TODO: Read:


Logging is useful when you want to know more than how much traffic you have for a rule -- or at a particular point in your flowcharty firewall.

You might also look for specific fishing expeditions, such as summing up connections to port 8080 and other common ports, e.g. P2P you do not use, and see whether there are common origins.

Since this can be very spammy, you usually want to feed that into an analyzer. (and, for anything running permanently, maybe not feed it all via disk)

The LOG target sends to syslog.

For example, add something like:

-A INPUT -j LOG --log-prefix "iptables_INPUT "

...just before the final reject/drop.

That string is just something easy to grep for.

ULOG can be made to store packets basically as-is, rather than a text summary as LOG does. (It can also avoid syscall overhead)

It usually sends to a ulogd you set up, which decides what to do, which is often to store it in a database.

GUI wrappers

Tool notes

See also Network tools

tcpdump notes

This article is marked 'feel free.' Often because its authors know they won't spend as much time on it as they should. Your help is appreciated.

TCPdump snoops network traffic going getting to the host it runs on.

It can also filter what packets it shows/writes.

It can summarize the traffic on-screen (the default) or write it to the fairly common pcap-style files.

The 'tcp' in the name is misleading, because it suggests it captures at the network layer, and then specifically TCP. Actually, it captures at link layer, so you can get at a lot of interesting stuff.

Wireshark (previously Ethereal) serves much the same purpose. It has a GUI, more protocol decoding, a more advanced filter language that includes substring and regexp content filtering.

You may also be interested in tshark, which can do more than tcpdump

Usage notes

If the line reporting "packets dropped by kernel" doesn't say 0: This refers to to the packet capture interface (a kernel feature) and doesn't mean the kernel is screwing up your networking, nor does it refer to firewall drops.

The network is moving packets faster than the capturing program is reading them from the capture interface. That is, the kernel isn't waiting around for the capturer (tcpdump) to catch up, it's removing the packets exposed to the capturing.

It seems one reason is that tcpdump is waiting on its own DNS lookups - try tcpdump -n (numeric, no names) to see if that helps.

Interesting command line options

  • -n: don't resolve hostnames (faster)
  • -i interfacename: listen on a specific interface. Default is the first it can find. ("-i any" will capture from all interfaces but ''not'' be promiscuous)

  • -w filename: dump packet data to a file, instead of decoding and printing (tcpdump -r and other utilities take this)
  • -s 0: capture the whole packet instead of the first 68 bytes (68 is faster and enough for the scrolling screen summary, but not for deeper inspection. You probably want whole packets when writing traffic to files for later inspection)

  • -t: don't show timestamps (less clutter, though also not as informative)

Print packet as

  • -A: ASCII (safe to print; command characters are removed)
  • -x: hex
  • -X: hex and ASCII
  • (-xx and -XX are variations that also show the link-level header)


The filter expression is often enclosed in single quotes. This is not necessary, but is simpler than dealing with shell escaping.

Apparently the format is the one from BPF, so see things like [1]

Host, net, port

As to filters: Avoid shell interpretation of filter string by using single quotes. Also: note that the predefined primitives require a backslash before them.

Probably the most directly interesting types filters are things like:

  • port 53 (matches tcp and udp; "udp port 53" and "tcp port 53" are shorthands that imply the respective protos)
  • portrange 1024-65535
  • host (shorthand for "ether proto \ip and host ...")
  • net 192.168 (shorthand for "ip net ..."), and also:
    • net 192.168.5 mask
    • net 192.168.5/24
When not mentioning src or dst, you accept an address, net, port or such if it appears as either source or destination. So:
port 80
would capture your surfing and people connecting to your web server, while
src port 80
dst port 80
look at direction.

If you add a named hosts it is looked up, but redirects and round robin DNS resolving may throw you off (both may happen in the case of

Protocol constants

  • "ether proto" things
    • ip (shorthand for "ether proto \ip", and actual value is 0x0800)
    • arp (shorthand for "ether proto \arp", value is 0x0806)
    • rarp ("ether proto \rarp")
    • ip6, tr, fddi, decnet
    • Others, e.g. 0x8863 for PPPoE Discovery, 0x8864 for PPPoE Session


  • ICMP that isn't pinging:
    tcpdump 'icmp[icmptype]!=icmp-echo and icmp[icmptype]!=icmp-echoreply'
  • "ip proto" things:
    • tcp (shorthand for "ip proto \tcp")
    • udp (shorthand for "ip proto \udp")
    • icmp (shorthand for "ip proto \icmp")
    • Also: gre, ipx, decnet

(note the absence of backslashes in shorthands)

Logic in filters

Logical booleans:

  • and, &&
  • or, ||
  • not, !


  • 'not arp and not port 67' (show all except arp and dhcp)
  • 'net 192.168 && !host' (all traffic on this net not related to this specific host)
  • 'net 192.168 || net 145.99' (traffic on my private and public IP net)


  • eq, == and =
  • ne, !=
  • gt, >
  • lt, <
  • ge, >=
  • le, <=

Repetition and omission: lists and short forms

If the predicate is missing, the last is assumed. For example:

net 10 or 192

...does the same as

net 10 or net 192

Lists are supported through a similar sort of expansion:

host ourrouter and not \( ourmailserver or ourwebserver \)

Raw bit/byte testing, and bitwise operations

You can get at packet data, with decimal (or hexadecimal) offsets for a frame/packet at apparently any layer/decoded protocol, including things like ether[], link[], ip[], tcp[], udp[], and icmp[]. Some examples:

  • ip[8] = 1 (picks out a byte. This tests for TTL being 1)
  • tcp[0:2] = 80 (picks out a word using [start offset:length]. This one is equivalent to "src port 80")
  • tcp[20:4] = 0x48454C4F (one page's example; those are ASCII bytes for HELO, part of SMTP mail sending)
  • icmp[0]==8 || icmp[0]==0, ICMP packets that are either echo request or echo reply. Note that there are readable constants for these, used in an example somewhere above.

See links below for header references, and for further examples using this sort of test.

Value/bitwise operations that may be useful:

  • +, -, /, and *: integer math
  • & and |: bitwise and and or
  • <<, >>: bitshifts

Note that you only ever deal with whatever endianness is defined for the protocol. IP, TCP and UDP are always big-endian.

TCP flags

To show any packets with any of these three flags:

'tcp[tcpflags] & (tcp-syn|tcp-ack|tcp-rst) != 0'


Also interesting in this context is len, the packet packet length. I'm not sure at which level -- it seems that filtering for 1514 gives results and not 1500 or 1518, which would suggest it's counting at link level, except it's NOT counting ethernet's CRC.

Copy-paste examples

  • ICMP packets:
    tcpdump icmp
    (ping and ICMP portscans)
  • non-ping ICMP:
    tcpdump 'icmp[0]!=8 && icmp[0]!=0'
    (often mostly 'port unreachable' replies)
  • ARP packets:
    tcpdump arp
  • ARP and DHCP:
    tcpdump 'udp port 67 or udp port 68 or arp'
  • SYN packets:
    tcpdump '(tcp[13]&0x2)!=0 and (tcp[13]&0x10)==0'
    (initial establishment of TCP connections, SYN portscans) (Specifically packets with SYN set, ACK not set, and ignoring the other flags)

  • MAC filter:
    tcpdump 'ether host 00:0B:6A:11:22:33'
    (also see ether src and ether dst)
  • Ethernet broadcasts:
    tcpdump 'ether broadcast'
    (shows ARP requests and more)
  • Small data packets:
    tcpdump '(tcp or udp) and len<100'
  • IPv6:
    tcpdump ip6

There are various tricks you can pull when you combine other networking tools, or even general tools. For example, you can add pv to see how much data of a specific type (say HTTP) is being moved (at ethernet level):

tcpdump 'tcp port 80' -s 0 -w - | pv > /dev/null


Various wireless-related utilities dump or read the pcap format, so you can use tcpdump to read the results.

BSSIDs act as MACs, so you can filter for traffic to and from an AP using:

ether host 00:12:34:66:22:12

Tcpdump knows how to decode the 802.11 (WiFi) basics, but there seem to be no handy aliases yet. Since 801.11 is a different type of ethernet frame (the aliases seem for ethernetII), most of the interesting filters have to come from accessing the packet's link level data. See also wireless.

Interesting tests include

  • link[0]==0x80: Beacon
  • link[0]&0x0c==0x08: Data packets
    • link[0:2]&0x0c02==0x0802: WEP-encrypted data packets

See also

  • tcpslice, which manipulates dump files


Header reference / byte/bit-tests


wireshark and tshark notes

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

Wireshark captures network data and shows it visually. It's e.g. a great network debugging tool.

tshark is basically the command line variant of wireshark. This makes it like tcpdump, but a little more capable.

wireshark and tshark have a slightly confusing difference between capture filters and display filters

Capture filters

are what can be passed into libpcap/winpcap,
so is the same syntax that tcpdump, WinDump, and others.
cannot be changed during a capture
are intended mostly to limit the amount of data we need to keep in RAM / on disk (which is great on busy networks)

Display filters

are much more capable
if the program allow s(e.g. wireshark GUI), you can alter while capturing
only change the view on the already captured data

Yes, there is plenty of overlap - with different syntax, e.g.
tcp port 80
(capture filter) versus
tcp.port == 80
(display filter)

In wireshark you get asked at different times.

In tshark it's

  • -f <capture filter>
  • -Y <displaY filter>

...there are actually a few more filter related options, most of which are only relevant for more advanced use.

Capture filters


  • yes, there is plenty of overlap - with different syntax, e.g.
capture filter:
tcp port 80
display filter:
tcp.port == 80

  • because you usually use capture filters to reduce all data to just the bit you're interested in, you often use it for broad things like:
src net
dst net
ether broadcast or ether multicast
multicast and not broadcast
net or net or
specific types of traffic. There are aliases, but they're fairly low level stuff:
ether proto \arp

so for a lot of things you start having to filer by protocol and/or port

port 67 or port 68

You can use capture filters to be a lot more specific, like the following for a HTTP GET, but this gets awkward fast

port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420

See also:

Display filters

Display filters try to expose a lot of useful things as fields.

See also:

Complex tricks