TCP/IP Fingerprinting and p0f
Before any TLS or HTTP is exchanged, the first TCP packet of a connection already says something about the operating system that sent it. p0f is the best-known tool that reads those clues passively. This guide shows which header fields carry them, how p0f matches them, why a proxy can create a mismatch, and what an OS fingerprint setting on the proxy line changes.
What to take from this
- The opening SYN packet carries an initial TTL, a window size, a maximum segment size and an ordered list of TCP options. Each operating system fills them differently.
- p0f compares those values with a signature database and also estimates how far away the sender is and what kind of link it uses. It never sends a packet of its own.
- Through an HTTP or SOCKS5 proxy, the site's TCP connection starts at the proxy device, so its packets carry the device's operating system defaults, not your browser's.
- An OS fingerprint setting makes the line's packets follow a chosen operating system profile. Set it to match the browser you actually use; it does not change TLS, browser signals or IP reputation.
What TCP/IP headers reveal
Every TCP connection opens with a three-way handshake, and the client's first packet, the SYN, has to describe how the client wants to talk. The fields are standard, defined in RFC 791 for IP and RFC 9293 for TCP, with window scaling and timestamps in RFC 7323. The values are left to the implementation, and implementations differ.
The Linux kernel documentation lists the relevant defaults for that system: ip_default_ttl is 64, and window scaling, selective acknowledgment and timestamps are on unless changed. Those defaults are what a stock Linux server, router or proxy host sends. Microsoft's TCP/IP parameter reference gives 128 as the DefaultTTL, which is why a received TTL a little under 128 usually points to Windows.
A site does not see the initial TTL directly; it sees what is left after the routers on the path. Passive tools round up to the nearest common starting value and treat the difference as the hop count. This small function does the same:
"""Guess the initial TTL and hop count from an observed TTL, the way passive tools do."""
COMMON_INITIAL_TTLS = (32, 64, 128, 255)
def initial_ttl(observed: int) -> tuple[int, int]:
for start in COMMON_INITIAL_TTLS:
if observed <= start:
return start, start - observed
raise ValueError("TTL above 255 is not valid")
for observed in (57, 118, 64, 49, 241):
start, hops = initial_ttl(observed)
print(f"observed {observed:>3} -> started at {start:>3}, about {hops} hops away")
observed 57 -> started at 64, about 7 hops away
observed 118 -> started at 128, about 10 hops away
observed 64 -> started at 64, about 0 hops away
observed 49 -> started at 64, about 15 hops away
observed 241 -> started at 255, about 14 hops away
A received TTL of 118 points to a system that started at 128 about ten hops away. A TTL of 57 points to one that started at 64. That single number already separates most Windows machines from Linux and Android ones.
To see your own SYN, run a packet capture on your machine while opening an HTTPS site, for example sudo tcpdump -n -v -c 1 'tcp[tcpflags] & tcp-syn != 0 and dst port 443', and read the ttl, win, and options fields in the output.
| Field | What it is | Why it identifies the sender |
|---|---|---|
| Initial TTL | The hop limit set when the packet leaves the machine; each router lowers it by one | Systems start from a few fixed values: the Linux kernel documents 64, Microsoft's reference lists 128 for Windows, and some network equipment uses 255 |
| Window size | How much data the sender will accept before an acknowledgment | Often set as a multiple of the segment size, with a per-system pattern |
| Window scale | A multiplier that lets the window grow beyond 64 KB | The chosen factor differs between systems and versions |
| MSS | The largest segment the sender will accept | Follows the link's MTU, so tunnels and some mobile links lower it |
| TCP options and their order | MSS, selective acknowledgment, timestamps, window scale, no-op padding | The order is a strong signal; p0f's documentation calls it one of the most valuable |
| Quirks | Flags such as don't-fragment, a non-zero IP ID, zero timestamps | Small implementation habits that rarely change |
How p0f matches
p0f was written by Michaล Zalewski, and version 3 is documented in its README. The tool describes itself as using "purely passive traffic fingerprinting mechanisms" to identify the systems behind a TCP connection, "often as little as a single normal SYN", without sending anything.
Each TCP signature in p0f's database is one line with nine fields: ver:ittl:olen:mss:wsize,scale:olayout:quirks:pclass. In order, they are the IP version the signature applies to, the initial TTL, the length of IP options, the MSS, the window size and scaling factor, the layout of TCP options, a list of quirks, and whether the packet carries a payload. The README is specific about which parts matter most: the option layout "is one of the most valuable TCP fingerprinting signals", and almost all systems use an initial TTL of 64, 128 or 255.
Signatures allow some flexibility. The window can be written as a multiple of the MSS or MTU, MSS can be a wildcard when it depends on the link, and the matcher tolerates a few quirks appearing or disappearing. When MSS is a wildcard, p0f uses the actual value to guess the type of network link instead, which is how it can tell that traffic passed through a tunnel or a link with a smaller MTU.
The README lists what p0f can report beyond the operating system: distance in hops, how long the system has been running (from TCP timestamps), link type, and detection of "connection sharing / NAT, load balancing, and application-level proxying setups". It also flags "dishonest clients" whose declarations, such as a User-Agent header, contradict what their packets show. That last capability is the reason p0f matters to anyone using a proxy.
Active fingerprinting is a different technique. Tools such as Nmap's OS detection send crafted probes and analyze the answers. Websites cannot probe visitors that way without being noticed, so passive reading of normal connections is what bot-defense and fraud systems use. FoxIO's JA4T applies the same passive idea in its JA4+ family, as noted in our JA3 vs JA4 guide.
The mismatch: desktop browser, Linux proxy host
With an HTTP proxy, an HTTPS request starts with a CONNECT. The proxy opens its own TCP connection to the site and relays bytes. With SOCKS5 the same happens. In both cases, the SYN the site receives was built by the proxy device's operating system.
Most proxy infrastructure runs on Linux, and many mobile devices run Linux-based systems too. So a session can look like this to the site:
- The browser's User-Agent and client hints say Windows 11, Chrome.
- The TLS fingerprint matches Chrome, because your browser performed the handshake through the tunnel.
- The TCP SYN shows an initial TTL of 64 and a Linux option layout, because the proxy host opened the connection.
Each signal is normal by itself. Together they describe a Windows browser whose packets come from Linux, which p0f's documentation would call a dishonest client and which many detection systems record as a proxy indicator. It is rarely the only reason for a block, but it moves a borderline score in the wrong direction. Our overview of how websites detect proxies shows where this layer sits among the others.
Two related effects are worth knowing. A VPN or tunnel adds overhead and lowers the MSS, which p0f reads as a link-type clue. And some carrier networks rewrite or clamp MSS for their own reasons, so a mobile exit has a mobile-looking link profile, which is consistent with a phone and inconsistent with a desktop on fiber.
What an OS fingerprint setting changes
An OS fingerprint setting makes the proxy line build its outgoing packets according to a chosen operating system profile: initial TTL, window and scaling, MSS and the TCP option layout. If your browser reports Windows, the line's SYN can carry Windows-style values, and the TCP layer stops contradicting the browser.
What it does not change:
- The TLS fingerprint. That still comes from your client. Use a real browser if you want a browser fingerprint.
- Browser signals. User agent, client hints, screen, fonts, WebRTC and time zone are set in the browser profile.
- The IP address and its reputation. The network label is the carrier's either way.
- Behavior. Request rates and navigation patterns are yours.
The rule for using it is the same as for every other layer: match what you actually are. Set the profile to the operating system of the browser that sends the traffic. Picking a profile that differs from your browser creates the mismatch the setting exists to remove. If you test mobile apps on an Android device through the line, the default Linux-family profile may already be the consistent choice.
On Coronium, some lines let you set this TCP/IP OS fingerprint, often called the p0f setting, to match your device. The dashboard and the API show which lines carry it. The setting is a consistency tool, not an invisibility switch; the other layers still decide most outcomes.
Where Coronium offers it today
The table below is generated from the live catalog when this page is built, and refreshed hourly. It lists carriers whose lines in stock include the p0f OS fingerprint setting, with the regions where those lines are and the current 24-hour price. When only some of a carrier's lines have the setting, the table says how many. For a country not shown, the dashboard tells you whether a line supports the setting before you buy.
Each line is a physical device with its own SIM, rented to one customer, with HTTP and SOCKS5, data that is not metered, and IP changes by dashboard button, API, rotation link or timer. For the wider product, see Coronium mobile proxies.
Country pages with every carrier and live prices: Georgia, Germany, Netherlands, Poland, Singapore.
| Carrier and country | Lines with the setting | Regions | 24 hours |
|---|---|---|---|
| Magti, Georgia | Every line in stock | Tbilisi | From $7 |
| Geocell, Georgia | Every line in stock | Tbilisi | From $9 |
| O2, Germany | 8 of 55 lines in stock | Berlin | From $7 |
| Odido NL, Netherlands | Every line in stock | Groningen, Amsterdam | From $9 |
| Vodafone NL, Netherlands | 1 of 2 lines in stock | Groningen, Amsterdam | From $9 |
| Play, Poland | Every line in stock | Zielona Gora | From $9 |
| M1, Singapore | Every line in stock | Singapore | From $19 |
| Singtel, Singapore | Every line in stock | Singapore | From $19 |
Sources and review scope
Sources reviewed October 30, 2026. Vendor documentation, standards and public filings were checked on that date. Coronium sells mobile proxies; the vendors described here were not consulted, and descriptions of their systems rely on what they publish. Code examples ran against local fixtures or vendor test keys. Nothing here is a method for getting past a particular site.
- p0f v3 README
Signature format, matching rules and capabilities, by Michaล Zalewski.
- RFC 791: Internet Protocol
Time to live field.
- RFC 9293: Transmission Control Protocol
SYN, window and options.
- RFC 7323: TCP Extensions for High Performance
Window scaling and timestamps.
- Linux kernel: IP sysctl documentation
ip_default_ttl 64 and TCP option defaults.
- Microsoft: TCP/IP and NBT configuration parameters
DefaultTTL of 128.
- Nmap: Remote OS detection
Active fingerprinting, for contrast.
Frequently asked questions
More on bot defenses and proxy errors
Each guide reads one vendor or one symptom from primary documentation and ends with the checks to run.
Related workflows
The full detection stack, layer by layer.
The TLS layer above TCP.
Carriers, regions and live prices in Germany.
Short answers on blocks, fingerprints and proxy errors.
Where to get a dedicated line
A Coronium mobile proxy is one physical device with its own SIM, rented to one customer. It connects over HTTP or SOCKS5, the IP changes by dashboard button, API link or timer, and data is not metered on dedicated lines. Brazil lines are the exception: 20 GB of data a month and a new IP on request only, with no timer. Stock and prices differ by country and carrier.