I typed curl 127.1 while debugging something and it still hit localhost. That seemed wrong, so I chased it.
On macOS (and other BSD-ish systems) that string is not going through DNS. Once the parser sees a ., it treats the input as an IPv4 address and runs the old inet_aton() rules. Those rules still allow short forms.
What “abbreviated” means#
A dotted IPv4 string can have 1, 2, 3, or 4 parts. The last part eats whatever bits are left in the 32-bit address:
| Form | Bit layout | Example input | Expands to |
|---|---|---|---|
a.b.c.d | 8.8.8.8 | 8.8.8.8 | 8.8.8.8 |
a.b.c | 8.8.16 | 8.8.16 | 8.8.0.16 |
a.b | 8.24 | 8.24 | 8.0.0.24 |
a | 32 | 2130706433 | 127.0.0.1 |
So for 127.1:
127 . 1
─── ─────────
8 bits 24-bit host number127 is the first octet. 1 fills the remaining 24 bits as 0.0.1. Put together: 127.0.0.1.
127.0.1 is the three-part version. The last piece is 16 bits, and you still get 127.0.0.1.
Seeing it in curl#
Ask curl for the remote IP it used, without dumping a response body:
curl -s -o /dev/null -w "%{remote_ip}\n" 127.1
curl -s -o /dev/null -w "%{remote_ip}\n" 0x7F.1
curl -s -o /dev/null -w "%{remote_ip}\n" 0x7F000001
curl -s -o /dev/null -w "%{remote_ip}\n" 2130706433
curl -s -o /dev/null -w "%{remote_ip}\n" 0177.1All five print 127.0.0.1:

Same 32-bit value, written five ways:
| Input | How it is read |
|---|---|
127.1 | Decimal a.b → 8 + 24 bits |
0x7F.1 | Hex first octet (0x7F = 127), decimal host |
0x7F000001 | Single 32-bit hex integer |
2130706433 | Same value in decimal (0x7F000001) |
0177.1 | Octal first octet (0177 = 127), decimal host |
A leading 0 means octal. A leading 0x means hex. Same base rules C has used forever; inet_aton() just copies them.
Where the behavior lives#
I started from <arpa/inet.h>, then followed inet_aton() into the libc that ships on macOS. Apple’s tree still has the FreeBSD implementation:
apple-oss-distributions/Libc net/FreeBSD/inet_addr.c
After the parser has the dotted parts, the useful bit is the switch on how many parts you gave it:

For two parts (127.1), that is:
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffU)
return (0);
val |= parts[0] << 24;
break;parts[0] is 127, shifted into the top byte. val still holds 1. OR them, convert to network byte order, and you get 127.0.0.1.
Three- and four-part forms do the same thing with a 16-bit or 8-bit final piece. One-part form means the whole address is already in val, which is why bare 2130706433 and 0x7F000001 work with no dots.
Verify it with a tiny C program#
curl is a handy demo. The parser is easier to see on its own:
#include <stdio.h>
#include <arpa/inet.h>
int main(void) {
const char *inputs[] = {
"127.1",
"0x7F.1",
"0x7F000001",
"2130706433",
"0177.1",
"8.8.16",
"8.24",
NULL
};
for (int i = 0; inputs[i] != NULL; i++) {
struct in_addr addr;
if (inet_aton(inputs[i], &addr)) {
printf("%-14s -> %s\n", inputs[i], inet_ntoa(addr));
} else {
printf("%-14s -> FAIL\n", inputs[i]);
}
}
return 0;
}Compile and run:
cc -o inet_aton_demo inet_aton_demo.c
./inet_aton_demoOn macOS:
127.1 -> 127.0.0.1
0x7F.1 -> 127.0.0.1
0x7F000001 -> 127.0.0.1
2130706433 -> 127.0.0.1
0177.1 -> 127.0.0.1
8.8.16 -> 8.8.0.16
8.24 -> 8.0.0.24inet_ntoa() only prints the normal dotted-quad. The expansion already happened inside inet_aton().
Why it bites#
Most of the time this is just a weird fact. Sometimes it breaks security checks.
Allowlists that string-match host == "127.0.0.1" or startswith("127.") miss 127.1, 0x7f.1, and 2130706433. If you need “is this loopback?”, parse to an address and test that. Do not pattern-match the original string.
Strict parsers and inet_pton() reject a lot of these forms. Loose parsers and BSD inet_aton() accept them. So the same URL can look invalid in one layer and connect in another.
The comments in that file still talk about classful layouts (a.b as 8.24). The internet moved on. This compatibility path did not.
I would not put 127.1 in a config on purpose. If a tool quietly accepts it, that is old libc behavior, not magic.
curl 127.1 works because the IPv4 parser never required four decimal octets. Short dotted forms, hex, octal, and a bare 32-bit integer are all legal inputs to inet_aton(). On Apple/FreeBSD libc, a.b is still the first octet plus a 24-bit host number.
Full implementation: inet_addr.c in Apple’s Libc.

