惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
云风的 BLOG
云风的 BLOG
D
Docker
Vercel News
Vercel News
IT之家
IT之家
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
V
Visual Studio Blog
Engineering at Meta
Engineering at Meta
腾讯CDC
Google DeepMind News
Google DeepMind News
I
InfoQ
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
The GitHub Blog
The GitHub Blog
博客园 - Franky
The Cloudflare Blog
A
About on SuperTechFans
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
T
Tenable Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Security Latest
Security Latest
H
Hackread – Cybersecurity News, Data Breaches, AI and More
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 聂微东
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google Online Security Blog
Google Online Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
The Last Watchdog
The Last Watchdog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
U
Unit 42
The Hacker News
The Hacker News
Martin Fowler
Martin Fowler
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
F
Full Disclosure
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
V2EX
Project Zero
Project Zero

dgl.cx

SSH port knocking with OpenBSD 7.9 SSH port knocking with OpenBSD 7.9 Bash a newline: Exploiting SSH via ProxyCommand, again (CVE-2025-61984) Switchable dark mode with 5 lines of JavaScript Images over DNS CVE-2025-48384: Breaking Git with a carriage return and cloning RCE Can your terminal do emojis? How big? Blink and you'll miss it — a URL handler surprise Using HAProxy to protect me from scrapers Déjà vu: Ghostly CVEs in my terminal title Restrict sftp with Linux user namespaces ""?! ANSI Terminal security in 2023 and finding 10 CVEs NAT-Again: IRC NAT helper flaws
ip.wtf and showing you your actual HTTP request
2022-04-29 · via dgl.cx

I've been running a site to show you your IP address for a while.

I originally wrote it because I was doing some bizarre networking tricks where the source port mattered (maybe another post on that one day), but none of the "what's my IP address" sites seemed to actually give me the source port. One even appeared to show the source port, but it wasn't right (presumably they added a reverse proxy at some point).

I also wanted to show you your actual HTTP request, exactly as sent to the server (i.e. a proxy on your side could change it, but not exposing any internal load balancing details on the hosting side).

Getting the raw HTTP request is fairly simple with Go (at least for HTTP/1.1), we can take advantage of interfaces and implement wrappers around net.Listener and net.Conn that store the data that is read, then make it available to the higher level HTTP code via the context.

Ignoring how the application queries the data it can be done with something like this:

// RecordingListener wraps a net.Listener and wraps the resulting accepted
// connections in a RecordingConn.
type RecordingListener struct {
        net.Listener
}

func (l RecordingListener) Accept() (net.Conn, error) {
        rw, err := l.Listener.Accept()
        return RecordingConn{Conn: rw, read: &readInfo{}}, err
}

// RecordingConn wraps a net.Conn and records the data returned by Read.
type RecordingConn struct {
        net.Conn
        read   *readInfo
}

type readInfo struct {
        read  []byte
        count int
}

func (c RecordingConn) Read(b []byte) (int, error) {
        // Forward to the underlying Read method.
        n, err := c.Conn.Read(b)
        if err != nil {
                return n, err
        }
        // Store the data returned by Read.
        c.read.read = append(c.read.read, b[:n]...)
        return n, err
}

For the full code see main.go on GitHub.

The problem with this is it implies there is not a HTTP proxy in front of the service, as that would change the request and it wouldn't be possible to show you the actual request as sent. I did host this on a dedicated IP address for a while, but given IPv4 address shortage is a thing, I want to be able to put this behind a proxy and serve other sites; on which I want to support HTTP/2 or other things seemingly incompatible with these low level needs. Enter haproxy.

The last time I wrote about haproxy was on how to use SSH and HTTPS on the same port, at the time it didn't natively support SSL, now it supports SSL and even HTTP/2 and many other new things. The flexibility it can give you really is quite amazing.

In this case the flexibility we want can be provided by using TCP content inspection (how the SSH trick also works) as well as switch-mode http. At its most basic, a configuration of:

frontend tcp-http
  # TCP mode, i.e. not HTTP
  mode tcp
  default_backend ipwtf
  acl ipwtf hdr(Host) -m end ip.wtf
  tcp-request inspect-delay 10s

  # The key line: If the acl "ipwtf" did not match, i.e. the host
  # isn't "ip.wtf", switch to HTTP mode.
  tcp-request content switch-mode http if !ipwtf
  # Otherwise use the "other" backend, which is HTTP.
  use_backend other if !ipwtf

backend ipwtf
  mode tcp
  default-server send-proxy-v2
  server ipwtf [::1]:8080

backend other
  mode http
  # some HTTP server here...

Means that if the host matches "ip.wtf" it will not switch to HTTP and instead proxy the entire TCP connection to the ipwtf backend. It will also wrap the connection in the PROXY v2 protocol so the backend can see what the source IP address is, without relying on HTTP headers (as that would change the request). This is pretty neat.

The actual configuration is a little more complex, as it does this over SSL too and uses the crt-list feature in haproxy to offer HTTP/2 via ALPN on some certificates (and keeping ip.wtf to HTTP/1.1 for now, as HTTP/2 is binary and not easy to display back to the user).

In order to do this in a "crt-list" file it has something like:

/etc/haproxy/ssl/ip.wtf.pem
/etc/haproxy/ssl/dgl.cx.pem [alpn h2,http/1.1]

So that the "ip.wtf" certificate does not offer HTTP/2 over ALPN, but the "dgl.cx" one does. It's important these be separate certificates as otherwise HTTP/2 connection coalescing would mean other hosts could be tried over the same connection, breaking our expectation of HTTP/1.1 only for "ip.wtf".

One noticeable aspect of haproxy's HTTP mode is for HTTP/2 reasons it lowercases headers, so we can see whether we are using haproxy's HTTP mode with curl:

$ curl -i ip.wtf
HTTP/1.1 200 OK
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
[...snip...]

...which is not using HTTP mode, compared to:

$ curl -i dgl.cx
HTTP/1.1 301 Moved Permanently
content-length: 0
location: https://dgl.cx/

...this site, which is using HTTP mode (and supports HTTP/2). The other advantage of all these tricks is silly easter eggs like curl ip.wtf/moo work. Have fun.

29th April 2022