540

I want to store the data returned by $_SERVER["REMOTE_ADDR"] in PHP into a DB field, pretty simple task, really. The problem is that I can't find any proper information about the maximum length of the textual representation of an IPv6 address, which is what a webserver provides through $_SERVER["REMOTE_ADDR"].

I'm not interested in converting the textual representation into the 128 bits the address is usually encoded in, I just want to know how many characters maximum are needed to store any IPv6 address returned by $_SERVER["REMOTE_ADDR"].

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Gilles
  • 7,183
  • 3
  • 21
  • 24
  • 6
    What about the zone index? – Robert Tupelo-Schneck Oct 25 '12 at 18:02
  • 6
    #define INET_ADDRSTRLEN (16) #define INET6_ADDRSTRLEN (48) –  Jun 08 '15 at 18:32
  • Source: lxr.free-electrons.com/source/include/linux/inet.h –  Jun 08 '15 at 18:34
  • 1
    The question http://stackoverflow.com/questions/1076714/max-length-for-client-ip-address has some similar but useful answers. – Edward Apr 17 '16 at 12:31
  • An IPv6 address have 8 16-bit fields, each in maximum 4 hex number format, separated by 7 `:` characters. That is `128 / 16 * 4 + 7`, which you can calculate using `dc(1)` on the command line `dc -e "128 16 / 4 * 7 + p`, if installed. That will give you the maximum of 39 characters. Can be shorter as `0` in beginning and in a range can be removed/reduced. That without counting the optional ending device name `%devname`. – Anders Sep 27 '22 at 16:55
  • A proper DB has a proper type for this, like `inet` in PostgreSQL and then you have nothing to worry about, you typically exchange text from/to the DB, and the DB engine takes care of storing (and normalizing) that properly. NEVER store things like this as "text". – Patrick Mevzek Oct 05 '22 at 18:00
  • And don't forget the netmask, which is 32 bit for IPv4 and 128 bit for IPv6 (CIDR) format. But best is to use database native format to store things like IP addresses. Not to store in text format. – Anders May 22 '23 at 19:53

6 Answers6

766

45 characters.

You might expect an address to be

0000:0000:0000:0000:0000:0000:0000:0000

8 * 4 + 7 = 39

8 groups of 4 digits with 7 : between them.

But if you have an IPv4-mapped IPv6 address, the last two groups can be written in base 10 separated by ., eg. [::ffff:192.168.100.228]. Written out fully:

0000:0000:0000:0000:0000:ffff:192.168.100.228

(6 * 4 + 5) + 1 + (4 * 3 + 3) = 29 + 1 + 15 = 45

Note, this is an input/display convention - it's still a 128 bit address and for storage it would probably be best to standardise on the raw colon separated format, i.e. [0000:0000:0000:0000:0000:ffff:c0a8:64e4] for the address above.

Community
  • 1
  • 1
Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
  • 279
    Header files define INET6_ADDRSTRLEN to be 46, which fits with 45 chars plus a trailing null. – wisnij Jan 22 '10 at 16:33
  • 9
    Worth noting that the IPv6 address might also contain the scope zone http://stackoverflow.com/questions/5746082/ipv6-link-local-address-format, e.g. you get that from RemoteEndpointMessageProperty.Address – Rory Jun 18 '12 at 10:26
  • aren't ipv4 adresses written like ::ffff:127.0.0.1? – graywolf Sep 10 '12 at 14:17
  • @Paladin: That's the shorthand version I believe, yes. They still expand out to full addresses with zeros as above though which means you need to be able to account for that as well. – Matthew Scharley Sep 10 '12 at 23:03
  • @MatthewScharley well... you don't need to account for that.. you can just put it into db like that.. so you can use 39 chars instead of 45 chars. – graywolf Sep 11 '12 at 08:26
  • I have recently seen some IP4 addresses with double dots, like 183.60..244.37 from some malicious probes. So I think making it 50 would be better than 45 to be able to track bad IPs. – Elliptical view Feb 09 '14 at 03:16
  • 1
    does this take into account of percentage sign in ipv6 address? Refer - https://superuser.com/questions/99746/why-is-there-a-percent-sign-in-the-ipv6-address – Gaurav Dec 13 '18 at 10:18
  • 1
    @Ellipticalview No matter how large you make the buffer a malicious actor can always come up with a longer malformed string. It makes more sense to make the buffer large enough to hold the longest valid value and deal with bad input in other ways. – kasperd Feb 06 '19 at 09:29
  • @kasperd, Good point. I guess I was looking at a special use case: size needed to block malicious ips, and you're right that size could grow more. I needed a way to record and block a list of bad actors. – Elliptical view Feb 06 '19 at 18:13
  • 1
    @Ellipticalview If you log client IP addresses you are supposed to use trusted code on your own end to do the conversion from wire format to textual representation. In that case it isn't possible for a malicious actor to cause a malformed IP address to show up in your log. It's still sensible to validate input to guard against too long strings, but at that point you are defending against your own bugs not a malicious actor. – kasperd Feb 10 '19 at 13:30
  • Yes, the IPv6 format *is* 8 16 fields of 4 hex characters, with 7 separators. If you could store other formats in same field, you can use `[ ]` around the IPv6 address (used in web browser URL:s, for instance). Yes, you could add a device to that in format `%dev` but then you could have a really long address, twice the `39` (or optional `41`) character length. And device specification is only useful on link local addresses, as I know. Should probably be stored in another field, if link-local addresses should even be stored. And as mentioned, you should validate all external input. – Anders Sep 27 '22 at 17:12
  • And don't forget the netmask, 32 bti for IPv4 and 8 bit for IPv6 (CIDR format). – Anders Sep 27 '22 at 17:58
120

On Linux, see constant INET6_ADDRSTRLEN (include <arpa/inet.h>, see man inet_ntop). On my system (header "in.h"):

#define INET6_ADDRSTRLEN 46

The last character is for terminating NULL, as I belive, so the max length is 45, as other answers.

Yury
  • 3,000
  • 2
  • 24
  • 24
  • 7
    So what is this 48 I see? https://github.com/torvalds/linux/blob/master/include/linux/inet.h#L50 – eis Sep 20 '19 at 11:08
  • 1
    @eis probably was in 2013. Possibly incremented for struct alignment. – Iiridayn Apr 06 '20 at 21:21
  • I _think_ this is just how Linux store the IPv6 address _and_ link local additional net device name. Like fffe::1234:5678:9abc:def0%eth0. To explain what @eis saw, going from `46` to `48`. But I am only guessing. You should probably not store anything but binary form internally, and transfer to external by a `toString()` method or something similar to transfer to/from string and internal format. Then you can throw an exception if you don't support that format or if it is an error in your program. (not storing netmask in the structure, most of the time it is 128 or 64 or smaller.) – Anders Sep 27 '22 at 17:21
  • So for IPv4 the netmask need to store 32 bit, but for IPv6 you only need to store a byte (0-128). – Anders Sep 27 '22 at 17:55
20

As indicated a standard ipv6 address is at most 45 chars, but an ipv6 address can also include an ending % followed by a "scope" or "zone" string, which has no fixed length but is generally a small positive integer or a network interface name, so in reality it can be bigger than 45 characters. Network interface names are typically "eth0", "eth1", "wlan0", a small number of chars. The max interface name length in linux is 15 chars, so choosing 61 bytes will cover all interface names on linux.

Sean F
  • 4,344
  • 16
  • 30
  • 6
    True, but this is only link-local addresses, and you aren't going to see any of those once your website is running on the Internet (and hopefully not even while developing it). – Michael Hampton Mar 05 '17 at 19:36
  • This answer deserves more attention. It's best to add 5 more characters than to debug such a weird issue for an hour, just to find out such exception. So, for people who want to know the true max amount of characters, this answer is the best of all. – Akito Aug 10 '21 at 11:20
  • 3
    Network interface naming conventions state that names cannot exceed more than 15 characters. Might as well add 45 + 1 (terminating null character) + 15 = 61 characters. Pad it by 3 more characters (for struct byte alignment) and we get 64 characters. – tom_mai78101 Apr 01 '22 at 13:38
  • Better yet is to add check when _reading in data_ from external sources so it doesn't exceed the maximum field size. Then when it is in the system, you can rely on the address to be ok. So for just the IPv6-address you only need `39` characters (not counting some end of line chars etc. 8 groups of 4 hex chars + 7 separator characters). (Ok, each time you calculate a new address should also be checked, and throw an error when not proper string format. Most easy to do with a binary Domain structure, with a `toString()` method that do the checking). – Anders Sep 27 '22 at 17:04
14

Answered my own question:

IPv6 addresses are normally written as eight groups of four hexadecimal digits, where each group is separated by a colon (:).

So that's 39 characters max.

Gilles
  • 7,183
  • 3
  • 21
  • 24
  • 14
    However there's apparently a caveat, see http://stackoverflow.com/a/7477384/3787376 ("Max length for client ip address") - Quote: "For IPv4 mapped IPv6 addresses, the string can be longer than 39 characters.". It says that an "IPv4-mapped IPv6" is 45 characters and is in the format "NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:192.168.158.190". The maximum should therefore be 45 characters. The answer at http://stackoverflow.com/a/166157/3787376 (this question) also seems to demonstrate this point. – Edward Apr 17 '16 at 12:26
  • That IPv4 mapping are STILL just 8 groups of 4 hex digits in IPv6 addresses. It is just a way of printing the IPv6 address. And yes, you could also add the device name with `%dev` suffix, for added size. I would store it in the same format, and transfer to appropriate format when showing/printing to users. Same with device, which actually is only used in link local addresses. So, 8 16:bit numbers, and add some flags for other formats and optional device name. – Anders Sep 27 '22 at 17:24
  • Not to mention the netmask, which is 32 bits for IPv4, but you only need a byte for IPv6 (as it uses CIDR format). – Anders Sep 27 '22 at 17:54
  • It seems like Google randomly latched onto this incorrect answer, since "ipv6 maximum length" responds with "39 characters". I wonder how many people have been bit by that... – Glenn Maynard Mar 17 '23 at 00:54
8

I think @Deepak answer in this link is more close to correct answer. Max length for client ip address. So correct size is 45 not 39. Sometimes we try to scrounge in fields size but it seems to better if we prepare enough storage size.

Community
  • 1
  • 1
QMaster
  • 3,743
  • 3
  • 43
  • 56
  • That is only correct for Linux. And now it is 47, not 45. But if you store in database, use native address format for the database. And don't forget to store the netmask, which need 32 bit for IPv4 and only 8 bit on IPv6, etc. etc. This show that it is a bad practice to store data in character format in databases. – Anders Sep 27 '22 at 17:57
  • @Anders That needs to be rechecked, and I want to prepare good information on the subject. – QMaster Mar 17 '23 at 13:50
3

Watch out for certain headers such as HTTP_X_FORWARDED_FOR that appear to contain a single IP address. They may actually contain multiple addresses (a chain of proxies I assume).

They will appear to be comma delimited - and can be a lot longer than 45 characters total - so check before storing in DB.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • 4
    A slightly conflicted -1 (conflicted because I've fallen into this trap before, and I guess this answer contains info relevant to some people who will be arriving on this page) because nonetheless this clearly isn't an answer to the question asked. It would probably be better as a comment on the question. – Mark Amery Apr 11 '17 at 21:16
  • 1
    Plus 1 just to counteract the pointless -1. – Glenn Maynard Mar 17 '23 at 00:55