| ... | @@ -32,6 +32,7 @@ pub const IpAddress = extern union { | ... | @@ -32,6 +32,7 @@ pub const IpAddress = extern union { |
| 32 | error.InvalidEnd, | 32 | error.InvalidEnd, |
| 33 | error.InvalidCharacter, | 33 | error.InvalidCharacter, |
| 34 | error.Incomplete, | 34 | error.Incomplete, |
| | 35 | error.InvalidIpv4Mapping, |
| 35 | => {}, | 36 | => {}, |
| 36 | } | 37 | } |
| 37 | | 38 | |
| ... | @@ -50,19 +51,22 @@ pub const IpAddress = extern union { | ... | @@ -50,19 +51,22 @@ pub const IpAddress = extern union { |
| 50 | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { | 51 | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { |
| 51 | var result = IpAddress{ | 52 | var result = IpAddress{ |
| 52 | .in6 = os.sockaddr_in6{ | 53 | .in6 = os.sockaddr_in6{ |
| 53 | .scope_id = undefined, | 54 | .scope_id = 0, |
| 54 | .port = mem.nativeToBig(u16, port), | 55 | .port = mem.nativeToBig(u16, port), |
| 55 | .flowinfo = 0, | 56 | .flowinfo = 0, |
| 56 | .addr = undefined, | 57 | .addr = undefined, |
| 57 | }, | 58 | }, |
| 58 | }; | 59 | }; |
| 59 | const ip_slice = result.in6.addr[0..]; | 60 | var ip_slice = result.in6.addr[0..]; |
| | 61 | |
| | 62 | var tail: [16]u8 = undefined; |
| 60 | | 63 | |
| 61 | var x: u16 = 0; | 64 | var x: u16 = 0; |
| 62 | var saw_any_digits = false; | 65 | var saw_any_digits = false; |
| 63 | var index: u8 = 0; | 66 | var index: u8 = 0; |
| 64 | var scope_id = false; | 67 | var scope_id = false; |
| 65 | for (buf) |c| { | 68 | var abbrv = false; |
| | 69 | for (buf) |c, i| { |
| 66 | if (scope_id) { | 70 | if (scope_id) { |
| 67 | if (c >= '0' and c <= '9') { | 71 | if (c >= '0' and c <= '9') { |
| 68 | const digit = c - '0'; | 72 | const digit = c - '0'; |
| ... | @@ -77,7 +81,12 @@ pub const IpAddress = extern union { | ... | @@ -77,7 +81,12 @@ pub const IpAddress = extern union { |
| 77 | } | 81 | } |
| 78 | } else if (c == ':') { | 82 | } else if (c == ':') { |
| 79 | if (!saw_any_digits) { | 83 | if (!saw_any_digits) { |
| 80 | return error.InvalidCharacter; | 84 | if (abbrv) return error.InvalidCharacter; // ':::' |
| | 85 | if (i != 0) abbrv = true; |
| | 86 | mem.set(u8, ip_slice[index..], 0); |
| | 87 | ip_slice = tail[0..]; |
| | 88 | index = 0; |
| | 89 | continue; |
| 81 | } | 90 | } |
| 82 | if (index == 14) { | 91 | if (index == 14) { |
| 83 | return error.InvalidEnd; | 92 | return error.InvalidEnd; |
| ... | @@ -93,14 +102,26 @@ pub const IpAddress = extern union { | ... | @@ -93,14 +102,26 @@ pub const IpAddress = extern union { |
| 93 | if (!saw_any_digits) { | 102 | if (!saw_any_digits) { |
| 94 | return error.InvalidCharacter; | 103 | return error.InvalidCharacter; |
| 95 | } | 104 | } |
| 96 | if (index == 14) { | | |
| 97 | ip_slice[index] = @truncate(u8, x >> 8); | | |
| 98 | index += 1; | | |
| 99 | ip_slice[index] = @truncate(u8, x); | | |
| 100 | index += 1; | | |
| 101 | } | | |
| 102 | scope_id = true; | 105 | scope_id = true; |
| 103 | saw_any_digits = false; | 106 | saw_any_digits = false; |
| | 107 | } else if (c == '.') { |
| | 108 | if (!abbrv or ip_slice[0] != 0xff or ip_slice[1] != 0xff) { |
| | 109 | // must start with '::ffff:' |
| | 110 | return error.InvalidIpv4Mapping; |
| | 111 | } |
| | 112 | const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1; |
| | 113 | const addr = (parseIp4(buf[start_index..], 0) catch { |
| | 114 | return error.InvalidIpv4Mapping; |
| | 115 | }).in.addr; |
| | 116 | ip_slice = result.in6.addr[0..]; |
| | 117 | ip_slice[10] = 0xff; |
| | 118 | ip_slice[11] = 0xff; |
| | 119 | |
| | 120 | ip_slice[12] = @truncate(u8, addr >> 24 & 0xff); |
| | 121 | ip_slice[13] = @truncate(u8, addr >> 16 & 0xff); |
| | 122 | ip_slice[14] = @truncate(u8, addr >> 8 & 0xff); |
| | 123 | ip_slice[15] = @truncate(u8, addr & 0xff); |
| | 124 | return result; |
| 104 | } else { | 125 | } else { |
| 105 | const digit = try std.fmt.charToDigit(c, 16); | 126 | const digit = try std.fmt.charToDigit(c, 16); |
| 106 | if (@mulWithOverflow(u16, x, 16, &x)) { | 127 | if (@mulWithOverflow(u16, x, 16, &x)) { |
| ... | @@ -113,21 +134,22 @@ pub const IpAddress = extern union { | ... | @@ -113,21 +134,22 @@ pub const IpAddress = extern union { |
| 113 | } | 134 | } |
| 114 | } | 135 | } |
| 115 | | 136 | |
| 116 | if (!saw_any_digits) { | 137 | if (!saw_any_digits and !abbrv) { |
| 117 | return error.Incomplete; | 138 | return error.Incomplete; |
| 118 | } | 139 | } |
| 119 | | 140 | |
| 120 | if (scope_id) { | | |
| 121 | return result; | | |
| 122 | } | | |
| 123 | | | |
| 124 | if (index == 14) { | 141 | if (index == 14) { |
| 125 | ip_slice[14] = @truncate(u8, x >> 8); | 142 | ip_slice[14] = @truncate(u8, x >> 8); |
| 126 | ip_slice[15] = @truncate(u8, x); | 143 | ip_slice[15] = @truncate(u8, x); |
| 127 | return result; | 144 | return result; |
| | 145 | } else { |
| | 146 | ip_slice[index] = @truncate(u8, x >> 8); |
| | 147 | index += 1; |
| | 148 | ip_slice[index] = @truncate(u8, x); |
| | 149 | index += 1; |
| | 150 | mem.copy(u8, result.in6.addr[16 - index ..], ip_slice[0..index]); |
| | 151 | return result; |
| 128 | } | 152 | } |
| 129 | | | |
| 130 | return error.Incomplete; | | |
| 131 | } | 153 | } |
| 132 | | 154 | |
| 133 | pub fn parseIp4(buf: []const u8, port: u16) !IpAddress { | 155 | pub fn parseIp4(buf: []const u8, port: u16) !IpAddress { |
| ... | @@ -246,10 +268,6 @@ pub const IpAddress = extern union { | ... | @@ -246,10 +268,6 @@ pub const IpAddress = extern union { |
| 246 | ); | 268 | ); |
| 247 | }, | 269 | }, |
| 248 | os.AF_INET6 => { | 270 | os.AF_INET6 => { |
| 249 | const ZeroRun = struct { | | |
| 250 | index: usize, | | |
| 251 | count: usize, | | |
| 252 | }; | | |
| 253 | const port = mem.bigToNative(u16, self.in6.port); | 271 | const port = mem.bigToNative(u16, self.in6.port); |
| 254 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr); | 272 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr); |
| 255 | const native_endian_parts = switch (builtin.endian) { | 273 | const native_endian_parts = switch (builtin.endian) { |
| ... | @@ -262,44 +280,21 @@ pub const IpAddress = extern union { | ... | @@ -262,44 +280,21 @@ pub const IpAddress = extern union { |
| 262 | break :blk buf; | 280 | break :blk buf; |
| 263 | }, | 281 | }, |
| 264 | }; | 282 | }; |
| 265 | | | |
| 266 | var longest_zero_run: ?ZeroRun = null; | | |
| 267 | var this_zero_run: ?ZeroRun = null; | | |
| 268 | for (native_endian_parts) |part, i| { | | |
| 269 | if (part == 0) { | | |
| 270 | if (this_zero_run) |*zr| { | | |
| 271 | zr.count += 1; | | |
| 272 | } else { | | |
| 273 | this_zero_run = ZeroRun{ | | |
| 274 | .index = i, | | |
| 275 | .count = 1, | | |
| 276 | }; | | |
| 277 | } | | |
| 278 | } else if (this_zero_run) |zr| { | | |
| 279 | if (longest_zero_run) |lzr| { | | |
| 280 | if (zr.count > lzr.count and zr.count > 1) { | | |
| 281 | longest_zero_run = zr; | | |
| 282 | } | | |
| 283 | } else { | | |
| 284 | longest_zero_run = zr; | | |
| 285 | } | | |
| 286 | } | | |
| 287 | } | | |
| 288 | try output(context, "["); | 283 | try output(context, "["); |
| 289 | var i: usize = 0; | 284 | var i: usize = 0; |
| 290 | while (i < native_endian_parts.len) { | 285 | var abbrv = false; |
| 291 | if (i != 0) try output(context, ":"); | 286 | while (i < native_endian_parts.len) : (i += 1) { |
| 292 | | 287 | if (native_endian_parts[i] == 0) { |
| 293 | if (longest_zero_run) |lzr| { | 288 | if (!abbrv) { |
| 294 | if (lzr.index == i) { | 289 | try output(context, if (i == 0) "::" else ":"); |
| 295 | i += lzr.count; | 290 | abbrv = true; |
| 296 | continue; | | |
| 297 | } | 291 | } |
| | 292 | continue; |
| | 293 | } |
| | 294 | try std.fmt.format(context, Errors, output, "{x}", native_endian_parts[i]); |
| | 295 | if (i != native_endian_parts.len - 1) { |
| | 296 | try output(context, ":"); |
| 298 | } | 297 | } |
| 299 | | | |
| 300 | const part = native_endian_parts[i]; | | |
| 301 | try std.fmt.format(context, Errors, output, "{x}", part); | | |
| 302 | i += 1; | | |
| 303 | } | 298 | } |
| 304 | try std.fmt.format(context, Errors, output, "]:{}", port); | 299 | try std.fmt.format(context, Errors, output, "]:{}", port); |
| 305 | }, | 300 | }, |
| ... | @@ -807,6 +802,7 @@ fn linuxLookupNameFromHosts( | ... | @@ -807,6 +802,7 @@ fn linuxLookupNameFromHosts( |
| 807 | error.InvalidCharacter, | 802 | error.InvalidCharacter, |
| 808 | error.Incomplete, | 803 | error.Incomplete, |
| 809 | error.InvalidIPAddressFormat, | 804 | error.InvalidIPAddressFormat, |
| | 805 | error.InvalidIpv4Mapping, |
| 810 | => continue, | 806 | => continue, |
| 811 | }; | 807 | }; |
| 812 | try addrs.append(LookupAddr{ .addr = addr }); | 808 | try addrs.append(LookupAddr{ .addr = addr }); |