• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / 1436

08 Feb 2026 11:56PM UTC coverage: 76.729%. First build
1436

push

buildkite

web-flow
Only allow dotted quad IPv4 addresses (#40257)

See #40255

This commit makes Class A addresses a parse error in Julia because they
are probably not what the user wanted anyway.

3 of 5 new or added lines in 1 file covered. (60.0%)

62991 of 82095 relevant lines covered (76.73%)

23130205.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.9
/stdlib/Sockets/src/IPAddr.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    IPAddr
5

6
Abstract supertype for IP addresses. [`IPv4`](@ref) and [`IPv6`](@ref) are subtypes of this.
7
"""
8
abstract type IPAddr end
9

10
Base.isless(a::T, b::T) where {T<:IPAddr} = isless(a.host, b.host)
18✔
11
(dt::Type{<:Integer})(ip::IPAddr) = dt(ip.host)::dt
15✔
12

13
# Allow IP addresses to broadcast as unwrapped scalars
14
Base.Broadcast.broadcastable(ip::IPAddr) = Ref(ip)
12✔
15

16
struct IPv4 <: IPAddr
17
    host::UInt32
18
    IPv4(host::UInt32) = new(host)
1,097✔
19
    IPv4(a::UInt8,b::UInt8,c::UInt8,d::UInt8) = new(UInt32(a)<<24|
12✔
20
                                                    UInt32(b)<<16|
21
                                                    UInt32(c)<<8|
22
                                                    d)
23
    function IPv4(a::Integer,b::Integer,c::Integer,d::Integer)
18✔
24
        if !(0<=a<=255 && 0<=b<=255 && 0<=c<=255 && 0<=d<=255)
18✔
25
            throw(ArgumentError("IPv4 field out of range (must be 0-255)"))
6✔
26
        end
27
        IPv4(UInt8(a),UInt8(b),UInt8(c),UInt8(d))
12✔
28
    end
29
end
30

31
"""
32
    IPv4(host::Integer) -> IPv4
33

34
Return an IPv4 object from IP address `host` formatted as an [`Integer`](@ref).
35

36
# Examples
37
```jldoctest
38
julia> IPv4(3223256218)
39
ip"192.30.252.154"
40
```
41
"""
42
function IPv4(host::Integer)
43
    if host < 0
720✔
44
        throw(ArgumentError("IPv4 address must be positive"))
×
45
    elseif typemax(typeof(host)) > typemax(UInt32) && host > typemax(UInt32)
720✔
46
        throw(ArgumentError("IPv4 address must fit within 32 bits"))
×
47
    else
48
        return IPv4(UInt32(host))
720✔
49
    end
50
end
51

52
"""
53
    IPv4(str::AbstractString) -> IPv4
54

55
Parse an IPv4 address string into an `IPv4` object.
56

57
# Examples
58
```jldoctest
59
julia> IPv4("127.0.0.1")
60
ip"127.0.0.1"
61
```
62
"""
63
IPv4(str::AbstractString) = parse(IPv4, str)
482✔
64

65
show(io::IO,ip::IPv4) = print(io,"ip\"",ip,"\"")
6✔
66
print(io::IO,ip::IPv4) = print(io,string((ip.host&(0xFF000000))>>24),".",
493✔
67
                                  string((ip.host&(0xFF0000))>>16),".",
68
                                  string((ip.host&(0xFF00))>>8),".",
69
                                  string(ip.host&0xFF))
70

71
struct IPv6 <: IPAddr
72
    host::UInt128
73
    IPv6(host::UInt128) = new(host)
197✔
74
    IPv6(a::UInt16,b::UInt16,c::UInt16,d::UInt16,
3✔
75
     e::UInt16,f::UInt16,g::UInt16,h::UInt16) = new(UInt128(a)<<(7*16)|
76
                            UInt128(b)<<(6*16)|
77
                            UInt128(c)<<(5*16)|
78
                            UInt128(d)<<(4*16)|
79
                            UInt128(e)<<(3*16)|
80
                            UInt128(f)<<(2*16)|
81
                            UInt128(g)<<(1*16)|
82
                            h)
83
    function IPv6(a::Integer,b::Integer,c::Integer,d::Integer,
9✔
84
          e::Integer,f::Integer,g::Integer,h::Integer)
85
        if !(0<=a<=0xFFFF && 0<=b<=0xFFFF && 0<=c<=0xFFFF && 0<=d<=0xFFFF &&
9✔
86
             0<=e<=0xFFFF && 0<=f<=0xFFFF && 0<=g<=0xFFFF && 0<=h<=0xFFFF)
87
            throw(ArgumentError("IPv6 field out of range (must be 0-65535)"))
6✔
88
        end
89
        IPv6(UInt16(a),UInt16(b),UInt16(c),UInt16(d),
3✔
90
             UInt16(e),UInt16(f),UInt16(g),UInt16(h))
91
    end
92
end
93

94
"""
95
    IPv6(host::Integer) -> IPv6
96

97
Return an IPv6 object from IP address `host` formatted as an [`Integer`](@ref).
98

99
# Examples
100
```jldoctest
101
julia> IPv6(3223256218)
102
ip"::c01e:fc9a"
103
```
104
"""
105
function IPv6(host::Integer)
15✔
106
    if host < 0
15✔
107
        throw(ArgumentError("IPv6 address must be positive"))
3✔
108
        # We allow passing bigger integer types, but need to be careful to avoid overflow
109
        # Let's hope promotion rules are sensible
110
    elseif typemax(typeof(host)) > typemax(UInt128) && host > typemax(UInt128)
12✔
111
        throw(ArgumentError("IPv6 address must fit within 128 bits"))
×
112
    else
113
        return IPv6(UInt128(host))
12✔
114
    end
115
end
116

117
"""
118
    IPv6(str::AbstractString) -> IPv6
119

120
Parse an IPv6 address string into an `IPv6` object.
121

122
# Examples
123
```jldoctest
124
julia> IPv6("::1")
125
ip"::1"
126
```
127
"""
128
IPv6(str::AbstractString) = parse(IPv6, str)
9✔
129

130
# Suppress leading '0's and "0x"
131
print_ipv6_field(io,field::UInt16) = print(io,string(field, base = 16))
×
132

133
print_ipv6_field(io,ip,i) = print_ipv6_field(io,ipv6_field(ip,i))
×
134
function ipv6_field(ip::IPv6,i)
6✔
135
    if i < 0 || i > 7
9✔
136
        throw(BoundsError())
6✔
137
    end
138
    UInt16((ip.host&(UInt128(0xFFFF)<<(i*16))) >> (i*16))
×
139
end
140

141
show(io::IO, ip::IPv6) = print(io,"ip\"",ip,"\"")
15✔
142
# RFC 5952 compliant show function
143
# https://tools.ietf.org/html/rfc5952
144
function print(io::IO,ip::IPv6)
×
145
    i = 8
×
146
    m = 0
×
147
    longest_sub_i = -1
×
148
    while i!=0
×
149
        i-=1
×
150
        field = ipv6_field(ip,i)
×
151
        if field == 0 && longest_sub_i == -1
×
152
            # Find longest subsequence of 0
153
            longest_sub_i,j,m,c = i,i,1,1
×
154
            while j != 0
×
155
                j-=1
×
156
                if ipv6_field(ip,j) == 0
×
157
                    c += 1
×
158
                else
159
                    c = 0
×
160
                end
161
                if c > m
×
162
                    if j+c != longest_sub_i+1
×
163
                        longest_sub_i = j+c-1
×
164
                    end
165
                    m = c
×
166
                end
167
            end
×
168
            # Prevent single 0 from contracting to :: as required
169
            if m == 1
×
170
                longest_sub_i = 9
×
171
            end
172
        end
173
        if i == longest_sub_i
×
174
            print(io,":")
×
175
            i -= m-1
×
176
            if i == 0
×
177
                print(io,":")
×
178
                break
×
179
            end
180
        else
181
            if i != 7
×
182
                print(io,":")
×
183
            end
184
            print_ipv6_field(io,field)
×
185
        end
186
    end
×
187
end
188

189
# Parsing
190

191
const ipv4_leading_zero_error = """
192
Leading zeros in IPv4 addresses are disallowed due to ambiguity.
193
If the address is in octal or hexadecimal, convert it to decimal, otherwise remove the leading zero.
194
"""
195

196
function parse(::Type{IPv4}, str::AbstractString)
484✔
197
    fields = split(str,'.')
484✔
198
    i = 1
484✔
199
    ret = 0
484✔
200
    if length(fields) != 4
484✔
NEW
201
        throw(ArgumentError("IPv4 addresses must be specified as a dotted quad"))
×
202
    end
203
    for f in fields
484✔
204
        if isempty(f)
1,936✔
205
            throw(ArgumentError("empty field in IPv4 address"))
×
206
        end
207
        if length(f) > 1 && f[1] == '0'
2,581✔
208
            throw(ArgumentError(ipv4_leading_zero_error))
×
209
        else
210
            r = parse(Int, f, base = 10)
1,936✔
211
        end
212
        if r < 0 || r > 255
3,872✔
NEW
213
            throw(ArgumentError("IPv4 field out of range (must be 0-255)"))
×
214
        end
215
        ret |= UInt32(r) << ((4-i)*8)
1,936✔
216
        i+=1
1,936✔
217
    end
1,936✔
218
    IPv4(ret)
484✔
219
end
220

221
function parseipv6fields(fields,num_fields)
222
    if length(fields) > num_fields
×
223
        throw(ArgumentError("too many fields in IPv6 address"))
×
224
    end
225
    cf = 7
×
226
    ret = UInt128(0)
×
227
    for f in fields
×
228
        if isempty(f)
×
229
            # ::abc:... and ..:abc::
230
            if cf != 7 && cf != 0
×
231
                cf -= num_fields-length(fields)
×
232
            end
233
            cf -= 1
×
234
            continue
×
235
        end
236
        ret |= UInt128(parse(Int, f, base = 16))<<(cf*16)
×
237
        cf -= 1
×
238
    end
×
239
    ret
×
240
end
241
parseipv6fields(fields) = parseipv6fields(fields,8)
×
242

243
function parse(::Type{IPv6}, str::AbstractString)
×
244
    fields = split(str,':')
×
245
    if length(fields) > 8
×
246
        throw(ArgumentError("too many fields in IPv6 address"))
×
247
    elseif length(fields) == 8
×
248
        return IPv6(parseipv6fields(fields))
×
249
    elseif in('.',fields[end])
×
250
        return IPv6((parseipv6fields(fields[1:(end-1)],6))
×
251
            | parse(IPv4, fields[end]).host )
252
    else
253
        return IPv6(parseipv6fields(fields))
×
254
    end
255
end
256

257
#
258
# This supports IP addresses in the common dot (IPv4) or colon (IPv6)
259
# separated formats. Most other common formats use a standard integer encoding
260
# of the appropriate size and should use the appropriate constructor
261
#
262

263
function parse(::Type{IPAddr}, str::AbstractString)
264
    if ':' in str
1,146✔
265
        return parse(IPv6, str)
×
266
    else
267
        return parse(IPv4, str)
1,146✔
268
    end
269
end
270

271
"""
272
    @ip_str str -> IPAddr
273

274
Parse `str` as an IP address.
275

276
# Examples
277
```jldoctest
278
julia> ip"127.0.0.1"
279
ip"127.0.0.1"
280

281
julia> @ip_str "2001:db8:0:0:0:0:2:1"
282
ip"2001:db8::2:1"
283
```
284
"""
285
macro ip_str(str::String)
283✔
286
    return parse(IPAddr, str)
283✔
287
end
288

289
struct InetAddr{T<:IPAddr}
290
    host::T
1,945✔
291
    port::UInt16
292
end
293

294
"""
295
    InetAddr(ip::IPAddr, port) -> InetAddr
296

297
Return an `InetAddr` object from ip address `ip` and port number `port`.
298

299
# Examples
300
```jldoctest
301
julia> Sockets.InetAddr(ip"127.0.0.1", 8000)
302
Sockets.InetAddr{IPv4}(ip"127.0.0.1", 8000)
303
```
304
"""
305
InetAddr(ip::IPAddr, port) = InetAddr{typeof(ip)}(ip, port)
1,925✔
306

307
"""
308
    InetAddr(str::AbstractString, port) -> InetAddr
309

310
Return an `InetAddr` object from ip address `str` formatted as [`AbstractString`](@ref)
311
and port number `port`.
312

313
!!! compat "Julia 1.3"
314
    This constructor requires at least Julia 1.3.
315

316
# Examples
317
```jldoctest
318
julia> Sockets.InetAddr("127.0.0.1", 8000)
319
Sockets.InetAddr{IPv4}(ip"127.0.0.1", 8000)
320
```
321
"""
322
InetAddr(str::AbstractString, port) = InetAddr(parse(IPAddr, str), port)
3✔
323

324
function show(io::IO, addr::InetAddr)
325
    show(io, typeof(addr))
3✔
326
    print(io, "(")
3✔
327
    show(io, addr.host)
3✔
328
    print(io, ", ", Int(addr.port), ")")
3✔
329
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc