| ... | ... | @@ -32,6 +32,7 @@ pub const IpAddress = extern union { |
| 32 | 32 | error.InvalidEnd, |
| 33 | 33 | error.InvalidCharacter, |
| 34 | 34 | error.Incomplete, |
| 35 | error.InvalidIpv4Mapping, |
| 35 | 36 | => {}, |
| 36 | 37 | } |
| 37 | 38 | |
| ... | ... | @@ -50,19 +51,22 @@ pub const IpAddress = extern union { |
| 50 | 51 | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { |
| 51 | 52 | var result = IpAddress{ |
| 52 | 53 | .in6 = os.sockaddr_in6{ |
| 53 | | .scope_id = undefined, |
| 54 | .scope_id = 0, |
| 54 | 55 | .port = mem.nativeToBig(u16, port), |
| 55 | 56 | .flowinfo = 0, |
| 56 | 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 | 64 | var x: u16 = 0; |
| 62 | 65 | var saw_any_digits = false; |
| 63 | 66 | var index: u8 = 0; |
| 64 | 67 | var scope_id = false; |
| 65 | | for (buf) |c| { |
| 68 | var abbrv = false; |
| 69 | for (buf) |c, i| { |
| 66 | 70 | if (scope_id) { |
| 67 | 71 | if (c >= '0' and c <= '9') { |
| 68 | 72 | const digit = c - '0'; |
| ... | ... | @@ -77,7 +81,12 @@ pub const IpAddress = extern union { |
| 77 | 81 | } |
| 78 | 82 | } else if (c == ':') { |
| 79 | 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 | 91 | if (index == 14) { |
| 83 | 92 | return error.InvalidEnd; |
| ... | ... | @@ -93,14 +102,26 @@ pub const IpAddress = extern union { |
| 93 | 102 | if (!saw_any_digits) { |
| 94 | 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 | 105 | scope_id = true; |
| 103 | 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 | 125 | } else { |
| 105 | 126 | const digit = try std.fmt.charToDigit(c, 16); |
| 106 | 127 | if (@mulWithOverflow(u16, x, 16, &x)) { |
| ... | ... | @@ -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 | 138 | return error.Incomplete; |
| 118 | 139 | } |
| 119 | 140 | |
| 120 | | if (scope_id) { |
| 121 | | return result; |
| 122 | | } |
| 123 | | |
| 124 | 141 | if (index == 14) { |
| 125 | 142 | ip_slice[14] = @truncate(u8, x >> 8); |
| 126 | 143 | ip_slice[15] = @truncate(u8, x); |
| 127 | 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 | 155 | pub fn parseIp4(buf: []const u8, port: u16) !IpAddress { |
| ... | ... | @@ -246,10 +268,6 @@ pub const IpAddress = extern union { |
| 246 | 268 | ); |
| 247 | 269 | }, |
| 248 | 270 | os.AF_INET6 => { |
| 249 | | const ZeroRun = struct { |
| 250 | | index: usize, |
| 251 | | count: usize, |
| 252 | | }; |
| 253 | 271 | const port = mem.bigToNative(u16, self.in6.port); |
| 254 | 272 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr); |
| 255 | 273 | const native_endian_parts = switch (builtin.endian) { |
| ... | ... | @@ -262,44 +280,21 @@ pub const IpAddress = extern union { |
| 262 | 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 | 283 | try output(context, "["); |
| 289 | 284 | var i: usize = 0; |
| 290 | | while (i < native_endian_parts.len) { |
| 291 | | if (i != 0) try output(context, ":"); |
| 292 | | |
| 293 | | if (longest_zero_run) |lzr| { |
| 294 | | if (lzr.index == i) { |
| 295 | | i += lzr.count; |
| 296 | | continue; |
| 285 | var abbrv = false; |
| 286 | while (i < native_endian_parts.len) : (i += 1) { |
| 287 | if (native_endian_parts[i] == 0) { |
| 288 | if (!abbrv) { |
| 289 | try output(context, if (i == 0) "::" else ":"); |
| 290 | abbrv = true; |
| 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 | 299 | try std.fmt.format(context, Errors, output, "]:{}", port); |
| 305 | 300 | }, |
| ... | ... | @@ -807,6 +802,7 @@ fn linuxLookupNameFromHosts( |
| 807 | 802 | error.InvalidCharacter, |
| 808 | 803 | error.Incomplete, |
| 809 | 804 | error.InvalidIPAddressFormat, |
| 805 | error.InvalidIpv4Mapping, |
| 810 | 806 | => continue, |
| 811 | 807 | }; |
| 812 | 808 | try addrs.append(LookupAddr{ .addr = addr }); |