Cf-Pseudo-IPv4 header not always present on HTTP requests

We’re working on a website that securely logs client info (for support use) for our platform, and one of the things we need to log is IPv4 addresses.

We’ve enabled the Cf-Pseudo-IPv4 header, and that seems to work most of the time, but for some clients it’s consistently not present. We can always get an IP (v4 or v6) via Cf-Connecting-IP, but we need to consistently log v4.

I have a pretty weak understanding of how the Cf-Pseudo-IPv4 header works, so I’m hoping someone can teach me a bit about it, and if I can make it work for our purpose. Thanks

It’s actually explained in detail at https://support.cloudflare.com/hc/en-us/articles/229666767-Understanding-and-configuring-Cloudflare-s-IPv6-support#h_877db671-916a-4085-9676-8eb27eaa2a91.

If you have the right settings for that header and don’t get the header, the client won’t have connected via IPv6.

If you always want to use IPv4, choose “Overwrite Headers” and only use Cf-Connecting-IP.

2 Likes

Hi sandro, thanks for the reply. I’ve taken a look at the docs, and I think I’ve covered all of the steps listed there. With both add and override modes, we were still getting an IPv6 with one of our testers, but it’s possible that I had it misconfigured.

My check goes as follows:
Check “Cf-Pseudo-IPv4”, if not, check “Cf-Connecting-IP”, if not, reload page.

Obviously on override mode, “Cf-Pseudo-IPv4” will not be present, but it falls back to “Cf-Connecting-IP”. To clarify, on both add and override, our one tester kept returning an IPv6.

Is such a thing possible, or am I potentially missing something?

As I mentioned, you should not evaluate that header at all.

Ah I see what you’re saying now. I’ll give that a try, and report back.

Alright, so I’ve set Pseudo IPv4 mode to overwrite mode, and now I’m only checking “Cf-Connecting-IP”. I cleared out our database, and the results seem the same; most people log IPv4 address, but the select few still only log IPv6.

const userIP = request.headers.get("CF-Connecting-IP");

asd2

Is the IP address in this screenshot exclusively set via userIP and the header? If not, that client may have connected directly to your server.

But if you

  • can guarantee that the header is exclusively logged via the header
  • can guarantee that people can’t connect directly
  • do not have an unorthodox setup with additional proxies
  • are sure that you picked “Overwrite”

that may be an error with Cloudflare. Double check these four items and if you are absolutely sure that Cloudflare still sends an IPv6 address, then open a ticket at [email protected] and post the ticket number here.

Thanks again for your reply, I’ll try to fill that in; let me know if I miss anything.

  1. I can confirm that userIP isn’t being modified or recorded anywhere else. It looks roughly like this:
const userIP = request.headers.get("CF-Connecting-IP");
// Other properties...

const sIP: Partial<SecureIP> = {
    ip: userIP,
    // Other properties...
};

const id = await fetch(`https://api.xxx.xxx`, {
    // Other headers and such...
    body: JSON.stringify(sIP)
});

—and then, our API stores that formatted body in our database.

  1. Our API requires authentication headers, so there’s no chance of uploading any data directly to the API (without a key).

  2. Right now, both our API and support site (and lots more) are hosted entirely on Pages and Workers, so (I hope :face_with_spiral_eyes:) nothing is proxying them.

  3. Here, I meant to send this in my last reply, but I can only send one image per post.

I’ll post a link to this thread, and then I’ll reply back here if I get a ticket number. Thanks again for your support.

All right, so we should be able to assume the IP address really gets populated exclusively via the header. You didn’t really address my question regarding direct connections, however

  1. even if they connected directly, you’d be still using the header and they would need to “fake” the header with an IPv6 address. While not impossible, I’d assume that wouldn’t be the case.
  2. Your “hosted” statement actually may give an idea.

Are you saying the code that accesses the header is running off Cloudflare infrastructure? If that is the case, these requests may be direct requests to your default Worker URL. Any IPv6 settings will only apply to your domain. Should someone access it via the Worker hostname, the default Cloudflare settings should take effect and I’d assume they may simply provide the actual IPv6 address.

Ah yes, the website itself takes the IP and converts it into a payload; the API itself does not read the header. Of course, because reading the header at the API level returns the IP of the website’s hosted node (unless a user is connecting directly), rather than the original users IP. In this case, I can confirm that the user isn’t connecting directly to the API URL, they’re only loading the support site.

So for that to be overwritten, if I’m not confused, that would mean that Cloudflare is modifying the request body, not just the headers. I’m fairly confident that part is working, though. When I test the website locally using Wrangler, it properly inserts an entry for 127.0.0.1 in the database, so I know that the IP evaluation is happening at the support site’s level.

Here’s the ticket number: 2510075

The API is completely irrelevant in this context. I was solely referring to the code where you determine the IP address. I’d probably also save request.url in your object and then check which hostnames these IPv6 addresses actually connect to. If this is anything else than your actual domain, your IPv6 settings won’t apply.

I’ve gone ahead and done so (good idea btw). I had the user load the page with a VPN, and without a VPN; with the VPN I got an IPv4, without I got an IPv6. On both of those, request.url was correct. That being said, I think that rules out any circumstantial stuff on their end, unless you can think of any other ways something might be interfering.

All right, if the URL had the correct hostname, it should be clear that the request actually had the domain settings applied.

There were some issues in the context of Cloudflare’s tunnel product Warp, however they were rather about general IPv6 connectivity and not about the header not being set correctly.

I forwarded your ticket earlier to support and it should have been reopened. I am afraid at this point this really will be something for support and the community won’t be able to help any more. The settings you selected should be correct.

I’m just happy to hear that it wasn’t just me. Thanks for all your help!

No worries. Still not entirely sure that this is a Cloudflare issue, but going by your statements, it might be.

I pushed it with support a few times, but they will only response on the ticket at this point. Have you got something from them?

Nothing yet, I just replied to an automated response last night. We’ll see where it goes.

Sure, unfortunately tickets always take a bit when they are not on Enterprise plans, but at least the ticket should be open and they should check it out.

Maybe really check everything again, as I’d still assume the IPv4 rewrite should actually work :slight_smile:

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.