123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- // +build windows, linux, darwin
- package net
- /*
- Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
- For other protocols and their features, see subdirectories of this package.
- */
- /*
- Copyright 2022 Tetralux <[email protected]>
- Copyright 2022 Colin Davidson <[email protected]>
- Copyright 2022 Jeroen van Rijn <[email protected]>.
- Made available under Odin's BSD-3 license.
- List of contributors:
- Tetralux: Initial implementation
- Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver
- Jeroen van Rijn: Cross platform unification, code style, documentation
- */
- import "core:strconv"
- import "core:strings"
- import "core:fmt"
- /*
- Expects an IPv4 address with no leading or trailing whitespace:
- - a.b.c.d
- - a.b.c.d:port
- - [a.b.c.d]:port
- If the IP address is bracketed, the port must be present and valid (though it will be ignored):
- - [a.b.c.d] will be treated as a parsing failure.
- The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
- If `allow_non_decimal` is false, `aton` is told each component must be decimal and max 255.
- */
- parse_ip4_address :: proc(address_and_maybe_port: string, allow_non_decimal := false) -> (addr: IP4_Address, ok: bool) {
- res := aton(address_and_maybe_port, .IP4, !allow_non_decimal) or_return
- return res.?
- }
- /*
- Parses an IP address in "non-decimal" `inet_aton` form.
- e.g."00377.0x0ff.65534" = 255.255.255.254
- 00377 = 255 in octal
- 0x0ff = 255 in hexadecimal
- This leaves 16 bits worth of address
- .65534 then accounts for the last two digits
- For the address part the allowed forms are:
- a.b.c.d - where each part represents a byte
- a.b.c - where `a` & `b` represent a byte and `c` a u16
- a.b - where `a` represents a byte and `b` supplies the trailing 24 bits
- a - where `a` gives the entire 32-bit value
- The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
- */
- aton :: proc(address_and_maybe_port: string, family: Address_Family, allow_decimal_only := false) -> (addr: Address, ok: bool) {
- switch family {
- case .IP4:
- // There is no valid address shorter than `0.0.0.0`.
- if len(address_and_maybe_port) < 7 {
- return {}, false
- }
- address, _ := split_port(address_and_maybe_port) or_return // This call doesn't allocate
- buf: [4]u64 = {}
- i := 0
- max_value := u64(max(u32))
- bases := DEFAULT_DIGIT_BASES
- if allow_decimal_only {
- max_value = 255
- bases = {.Dec}
- }
- for len(address) > 0 {
- if i == 4 {
- return {}, false
- }
- // Decimal-only addresses may not have a leading zero.
- if allow_decimal_only && len(address) > 1 && address[0] == '0' && address[1] != '.' {
- return
- }
- number, consumed, number_ok := parse_ip_component(address, max_value, bases)
- if !number_ok || consumed == 0 {
- return {}, false
- }
- buf[i] = number
- address = address[consumed:]
- if len(address) > 0 && address[0] == '.' {
- address = address[1:]
- }
- i += 1
- }
- // Distribute parts.
- switch i {
- case 1:
- buf[1] = buf[0] & 0xffffff
- buf[0] >>= 24
- fallthrough
- case 2:
- buf[2] = buf[1] & 0xffff
- buf[1] >>= 16
- fallthrough
- case 3:
- buf[3] = buf[2] & 0xff
- buf[2] >>= 8
- }
- a: [4]u8 = ---
- for v, j in buf {
- if v > 255 { return {}, false }
- a[j] = u8(v)
- }
- return IP4_Address(a), true
- case .IP6:
- return parse_ip6_address(address_and_maybe_port)
- case:
- return nil, false
- }
- }
- /*
- The minimum length of a valid IPv6 address string is 2, e.g. `::`
- The maximum length of a valid IPv6 address string is 45, when it embeds an IPv4,
- e.g. `0000:0000:0000:0000:0000:ffff:255.255.255.255`
- An IPv6 address must contain at least 3 pieces, e.g. `::`,
- and at most 9 (using `::` for a trailing or leading 0)
- */
- IPv6_MIN_STRING_LENGTH :: 2
- IPv6_MAX_STRING_LENGTH :: 45
- IPv6_MIN_COLONS :: 2
- IPv6_PIECE_COUNT :: 8
- parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, ok: bool) {
- // If we have an IPv6 address of the form [IP]:Port, first get us just the IP.
- address, _ := split_port(address_and_maybe_port) or_return
- // Early bailouts based on length and number of pieces.
- if len(address) < IPv6_MIN_STRING_LENGTH || len(address) > IPv6_MAX_STRING_LENGTH { return }
- /*
- Do a pre-pass on the string that checks how many `:` and `.` we have,
- if they're in the right order, and if the things between them are digits as expected.
- It's not strictly necessary considering we could use `strings.split`,
- but this way we can avoid using an allocator and return earlier on bogus input. Win-win.
- */
- colon_count := 0
- dot_count := 0
- pieces_temp: [IPv6_PIECE_COUNT + 1]string
- piece_start := 0
- piece_end := 0
- for ch, i in address {
- switch ch {
- case '0'..='9', 'a'..='f', 'A'..='F':
- piece_end += 1
- case ':':
- // If we see a `:` after a `.`, it means an IPv4 part was sandwiched between IPv6, instead of it being the tail: invalid.
- if dot_count > 0 { return }
- pieces_temp[colon_count] = address[piece_start:piece_end]
- colon_count += 1
- if colon_count > IPv6_PIECE_COUNT { return }
- // If there's anything left, put it in the next piece.
- piece_start = i + 1
- piece_end = piece_start
- case '.':
- // IPv4 address is treated as one piece. No need to update `piece_*`.
- dot_count += 1
- case: // Invalid character, return early
- return
- }
- }
- if colon_count < IPv6_MIN_COLONS { return }
- // Assign the last piece string.
- pieces_temp[colon_count] = address[piece_start:]
- // `pieces` now holds the same output as it would if had used `strings.split`.
- pieces := pieces_temp[:colon_count + 1]
- // Check if we have what looks like an embedded IPv4 address.
- ipv4: IP4_Address
- have_ipv4: bool
- if dot_count > 0 {
- /*
- If we have an IPv4 address accounting for the last 32 bits,
- this means we can have at most 6 IPv6 pieces, like so: `x:x:X:x:x:x:d.d.d.d`
- Or, put differently: 6 pieces IPv6 (5 colons), a colon, 1 piece IPv4 (3 dots),
- for a total of 6 colons and 3 dots.
- */
- if dot_count != 3 || colon_count > 6 { return }
- /*
- Try to parse IPv4 address.
- If successful, we have our least significant 32 bits.
- If not, it invalidates the whole address and we can bail.
- */
- ipv4, have_ipv4 = parse_ip4_address(pieces_temp[colon_count])
- if !have_ipv4 { return }
- }
- // Check for `::` being used more than once, and save the skip.
- zero_skip := -1
- for i in 1..<colon_count {
- if pieces[i] == "" {
- // Return if skip has already been set.
- if zero_skip != -1 { return }
- zero_skip = i
- }
- }
- /*
- Now check if we have the necessary number pieces, accounting for any `::`,
- and how many were skipped by it if applicable.
- */
- before_skip := 0
- after_skip := 0
- num_skipped := 0
- if zero_skip != -1 {
- before_skip = zero_skip
- after_skip = colon_count - zero_skip
- // An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
- if have_ipv4 {
- after_skip += 1
- }
- // Adjust for leading `::`.
- if pieces[0] == "" {
- before_skip -= 1
- // Leading `:` can only be part of `::`.
- if before_skip > 0 { return }
- }
- // Adjust for trailing `::`.
- if pieces[colon_count] == "" {
- after_skip -= 1
- // Trailing `:` can only be part of `::`.
- if after_skip > 0 { return }
- }
- /*
- Calculate how many zero pieces we skipped.
- It should be at least one, considering we encountered a `::`.
- */
- num_skipped = IPv6_PIECE_COUNT - before_skip - after_skip
- if num_skipped < 1 { return }
- } else {
- /*
- No zero skip means everything is part of "before the skip".
- An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
- */
- piece_count := colon_count + 1
- if have_ipv4 {
- piece_count += 1
- }
- // Do we have the complete set?
- if piece_count != IPv6_PIECE_COUNT { return }
- // Validate leading and trailing empty parts, as they can only be part of a `::`.
- if pieces[0] == "" || pieces[colon_count] == "" { return }
- before_skip = piece_count
- after_skip = 0
- num_skipped = 0
- }
- // Now try to parse the pieces into a 8 16-bit pieces.
- piece_values: [IPv6_PIECE_COUNT]u16be
- idx := 0
- val_idx := 0
- for _ in 0..<before_skip {
- /*
- An empty piece is the default zero. Otherwise, try to parse as an IPv6 hex piece.
- If we have an IPv4 address, stop on the penultimate index.
- */
- if have_ipv4 && val_idx == 6 {
- break
- }
- piece := pieces[idx]
- // An IPv6 piece can at most contain 4 hex digits.
- if len(piece) > 4 { return }
- if piece != "" {
- val, _ := parse_ip_component(piece, 65535, {.IPv6}) or_return
- piece_values[val_idx] = u16be(val)
- }
- idx += 1
- val_idx += 1
- }
- if before_skip == 0 {
- idx += 1
- }
- if num_skipped > 0 {
- idx += 1
- val_idx += num_skipped
- }
- if after_skip > 0 {
- for _ in 0..<after_skip {
- /*
- An empty piece is the default zero. Otherwise, try to parse as an IPv6 hex piece.
- If we have an IPv4 address, stop on the penultimate index.
- */
- if have_ipv4 && val_idx == 6 {
- break
- }
- piece := pieces[idx]
- // An IPv6 piece can contain at most 4 hex digits.
- if len(piece) > 4 { return }
- if piece != "" {
- val, _ := parse_ip_component(piece, 65535, {.IPv6}) or_return
- piece_values[val_idx] = u16be(val)
- }
- idx += 1
- val_idx += 1
- }
- }
- // Distribute IPv4 address into last two pieces, if applicable.
- if have_ipv4 {
- val := u16(ipv4[0]) << 8
- val |= u16(ipv4[1])
- piece_values[6] = u16be(val)
- val = u16(ipv4[2]) << 8
- val |= u16(ipv4[3])
- piece_values[7] = u16be(val)
- }
- return transmute(IP6_Address)piece_values, true
- }
- /*
- Try parsing as an IPv6 address.
- If it's determined not to be, try as an IPv4 address, optionally in non-decimal format.
- */
- parse_address :: proc(address_and_maybe_port: string, non_decimal_address := false) -> Address {
- if addr6, ok6 := parse_ip6_address(address_and_maybe_port); ok6 {
- return addr6
- }
- if addr4, ok4 := parse_ip4_address(address_and_maybe_port, non_decimal_address); ok4 {
- return addr4
- }
- return nil
- }
- parse_endpoint :: proc(endpoint_str: string) -> (ep: Endpoint, ok: bool) {
- if addr_str, port, split_ok := split_port(endpoint_str); split_ok {
- if addr := parse_address(addr_str); addr != nil {
- return Endpoint { address = addr, port = port }, true
- }
- }
- return
- }
- Host :: struct {
- hostname: string,
- port: int,
- }
- Host_Or_Endpoint :: union {
- Host,
- Endpoint,
- }
- // Takes a string consisting of a hostname or IP address, and an optional port,
- // and return the component parts in a useful form.
- parse_hostname_or_endpoint :: proc(endpoint_str: string) -> (target: Host_Or_Endpoint, err: Parse_Endpoint_Error) {
- host, port, port_ok := split_port(endpoint_str)
- if !port_ok {
- return nil, .Bad_Port
- }
- if addr := parse_address(host); addr != nil {
- return Endpoint{addr, port}, .None
- }
- if !validate_hostname(host) {
- return nil, .Bad_Hostname
- }
- return Host{host, port}, .None
- }
- // Takes an endpoint string and returns its parts.
- // Returns ok=false if port is not a number.
- split_port :: proc(endpoint_str: string) -> (addr_or_host: string, port: int, ok: bool) {
- // IP6 [addr_or_host]:port
- if i := strings.last_index(endpoint_str, "]:"); i >= 0 {
- addr_or_host = endpoint_str[1:i]
- port, ok = strconv.parse_int(endpoint_str[i+2:], 10)
- if port > 65535 {
- ok = false
- }
- return
- }
- if n := strings.count(endpoint_str, ":"); n == 1 {
- // IP4 addr_or_host:port
- i := strings.last_index(endpoint_str, ":")
- assert(i != -1)
- addr_or_host = endpoint_str[:i]
- port, ok = strconv.parse_int(endpoint_str[i+1:], 10)
- if port > 65535 {
- ok = false
- }
- return
- } else if n > 1 {
- // IP6 address without port
- }
- // No port
- addr_or_host = endpoint_str
- port = 0
- ok = true
- return
- }
- // Joins an address or hostname with a port.
- join_port :: proc(address_or_host: string, port: int, allocator := context.allocator) -> string {
- addr_or_host, _, ok := split_port(address_or_host)
- if !ok {
- return addr_or_host
- }
- b := strings.builder_make(allocator)
- addr := parse_address(addr_or_host)
- if addr == nil {
- // hostname
- fmt.sbprintf(&b, "%v:%v", addr_or_host, port)
- } else {
- switch _ in addr {
- case IP4_Address:
- fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port)
- case IP6_Address:
- fmt.sbprintf(&b, "[%v]:%v", address_to_string(addr), port)
- }
- }
- return strings.to_string(b)
- }
- // TODO(tetra): Do we need this?
- map_to_ip6 :: proc(addr: Address) -> Address {
- if addr6, ok := addr.(IP6_Address); ok {
- return addr6
- }
- addr4 := addr.(IP4_Address)
- addr4_u16 := transmute([2]u16be) addr4
- addr6: IP6_Address
- addr6[4] = 0xffff
- copy(addr6[5:], addr4_u16[:])
- return addr6
- }
- /*
- Returns a temporarily-allocated string representation of the address.
- See RFC 5952 section 4 for IPv6 representation recommendations.
- */
- address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> string {
- b := strings.builder_make(allocator)
- switch v in addr {
- case IP4_Address:
- fmt.sbprintf(&b, "%v.%v.%v.%v", v[0], v[1], v[2], v[3])
- case IP6_Address:
- // First find the longest run of zeroes.
- Zero_Run :: struct {
- start: int,
- end: int,
- }
- /*
- We're dealing with 0-based indices, appropriately enough for runs of zeroes.
- Still, it means we need to initialize runs with some value outside of the possible range.
- */
- run := Zero_Run{-1, -1}
- best := Zero_Run{-1, -1}
- addr := transmute([8]u16be)v
- last := u16be(1)
- for val, i in addr {
- /*
- If we encounter adjacent zeroes, then start a new run if not already in one.
- Also remember the rightmost index regardless, because it'll be the new
- frontier of both new and existing runs.
- */
- if last == 0 && val == 0 {
- run.end = i
- if run.start == -1 {
- run.start = i - 1
- }
- }
- /*
- If we're in a run check if its length is better than the best recorded so far.
- If so, update the best run's start and end.
- */
- if run.start != -1 {
- length_to_beat := best.end - best.start
- length := run.end - run.start
- if length > length_to_beat {
- best = run
- }
- }
- // If we were in a run, this is where we reset it.
- if val != 0 {
- run = {-1, -1}
- }
- last = val
- }
- for val, i in addr {
- if best.start == i || best.end == i {
- // For the left and right side of the best zero run, print a `:`.
- fmt.sbprint(&b, ":")
- } else if i < best.start {
- /*
- If we haven't made it to the best run yet, print the digit.
- Make sure we only print a `:` after the digit if it's not
- immediately followed by the run's own leftmost `:`.
- */
- fmt.sbprintf(&b, "%x", val)
- if i < best.start - 1 {
- fmt.sbprintf(&b, ":")
- }
- } else if i > best.end {
- /*
- If there are any digits after the zero run, print them.
- But don't print the `:` at the end of the IP number.
- */
- fmt.sbprintf(&b, "%x", val)
- if i != 7 {
- fmt.sbprintf(&b, ":")
- }
- }
- }
- }
- return strings.to_string(b)
- }
- // Returns a temporarily-allocated string representation of the endpoint.
- // If there's a port, uses the `ip4address:port` or `[ip6address]:port` format, respectively.
- endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string {
- if ep.port == 0 {
- return address_to_string(ep.address, allocator)
- } else {
- s := address_to_string(ep.address, context.temp_allocator)
- b := strings.builder_make(allocator)
- switch a in ep.address {
- case IP4_Address: fmt.sbprintf(&b, "%v:%v", s, ep.port)
- case IP6_Address: fmt.sbprintf(&b, "[%v]:%v", s, ep.port)
- }
- return strings.to_string(b)
- }
- }
- to_string :: proc{address_to_string, endpoint_to_string}
- family_from_address :: proc(addr: Address) -> Address_Family {
- switch _ in addr {
- case IP4_Address: return .IP4
- case IP6_Address: return .IP6
- case:
- unreachable()
- }
- }
- family_from_endpoint :: proc(ep: Endpoint) -> Address_Family {
- return family_from_address(ep.address)
- }
- Digit_Parse_Base :: enum u8 {
- Dec = 0, // No prefix
- Oct = 1, // Leading zero
- Hex = 2, // 0x prefix
- IPv6 = 3, // Unprefixed IPv6 piece hex. Can't be used with other bases.
- }
- Digit_Parse_Bases :: bit_set[Digit_Parse_Base; u8]
- DEFAULT_DIGIT_BASES :: Digit_Parse_Bases{.Dec, .Oct, .Hex}
- /*
- Parses a single unsigned number in requested `bases` from `input`.
- `max_value` represents the maximum allowed value for this number.
- Returns the `value`, the `bytes_consumed` so far, and `ok` to signal success or failure.
- An out-of-range or invalid number will return the accumulated value so far (which can be out of range),
- the number of bytes consumed leading up the error, and `ok = false`.
- When `.` or `:` are encountered, they'll be considered valid separators and will stop parsing,
- returning the valid number leading up to it.
- Other non-digit characters are treated as an error.
- Octal numbers are expected to have a leading zero, with no 'o' format specifier.
- Hexadecimal numbers are expected to be preceded by '0x' or '0X'.
- Numbers will otherwise be considered to be in base 10.
- */
- parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := DEFAULT_DIGIT_BASES) -> (value: u64, bytes_consumed: int, ok: bool) {
- // Default to base 10
- base := u64(10)
- input := input
- /*
- We keep track of the number of prefix bytes and digit bytes separately.
- This way if a prefix is consumed and we encounter a separator or the end of the string,
- the number is only considered valid if at least 1 digit byte has been consumed and the value is within range.
- */
- prefix_bytes := 0
- digit_bytes := 0
- /*
- IPv6 hex bytes are unprefixed and can't be disambiguated from octal or hex unless the digit is out of range.
- If we got the `.IPv6` option, skip prefix scanning and other flags aren't also used.
- */
- if .IPv6 in bases {
- if bases != {.IPv6} { return } // Must be used on its own.
- base = 16
- } else {
- // Scan for and consume prefix, if applicable.
- if len(input) >= 2 && input[0] == '0' {
- if .Hex in bases && (input[1] == 'x' || input[1] == 'X') {
- base = 16
- input = input[2:]
- prefix_bytes = 2
- }
- if prefix_bytes == 0 && .Oct in bases {
- base = 8
- input = input[1:]
- prefix_bytes = 1
- }
- }
- }
- parse_loop: for ch in input {
- switch ch {
- case '0'..='7':
- digit_bytes += 1
- value = value * base + u64(ch - '0')
- case '8'..='9':
- digit_bytes += 1
- if base == 8 {
- // Out of range for octal numbers.
- return value, digit_bytes + prefix_bytes, false
- }
- value = value * base + u64(ch - '0')
- case 'a'..='f':
- digit_bytes += 1
- if base == 8 || base == 10 {
- // Out of range for octal and decimal numbers.
- return value, digit_bytes + prefix_bytes, false
- }
- value = value * base + (u64(ch - 'a') + 10)
- case 'A'..='F':
- digit_bytes += 1
- if base == 8 || base == 10 {
- // Out of range for octal and decimal numbers.
- return value, digit_bytes + prefix_bytes, false
- }
- value = value * base + (u64(ch - 'A') + 10)
- case '.', ':':
- /*
- Number separator. Return early.
- We don't need to check if the number is in range.
- We do that each time through the loop.
- */
- break parse_loop
- case:
- // Invalid character encountered.
- return value, digit_bytes + prefix_bytes, false
- }
- if value > max_value {
- // Out-of-range number.
- return value, digit_bytes + prefix_bytes, false
- }
- }
- // If we consumed at least 1 digit byte, `value` *should* continue a valid number in an appropriate base in the allowable range.
- return value, digit_bytes + prefix_bytes, digit_bytes >= 1
- }
- // Returns an address for each interface that can be bound to.
- get_network_interfaces :: proc() -> []Address {
- // TODO: Implement using `enumerate_interfaces` and returning only the addresses of active interfaces.
- return nil
- }
|