fix endian conversion issues (#82)

* fixes call to `bigEndian32` on a uint64 which breaks on big endian
platforms
* prefer endians2 for less and safer code
This commit is contained in:
Jacek Sieka 2020-07-12 18:22:47 +02:00 committed by GitHub
parent 8b8a1e793d
commit f856c885fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 43 deletions

View File

@ -1,5 +1,5 @@
packageName = "chronos"
version = "2.5.0"
version = "2.5.1"
author = "Status Research & Development GmbH"
description = "Chronos"
license = "Apache License 2.0 or MIT"
@ -7,7 +7,8 @@ skipDirs = @["tests"]
### Dependencies
requires "nim > 1.2.0"
requires "nim > 1.2.0",
"stew",
"bearssl"
task test, "Run all tests":

View File

@ -8,7 +8,7 @@
# MIT license (LICENSE-MIT)
## This module implements various IP network utility procedures.
import endians, strutils
import stew/endians2, strutils
import common
export common
@ -31,29 +31,21 @@ proc toNetworkOrder(mask: IpMask): IpMask {.inline.} =
## network order (which is big-endian) representation.
result = IpMask(family: mask.family)
if mask.family == AddressFamily.IPv4:
bigEndian32(cast[pointer](addr result.mask4),
cast[pointer](unsafeAddr mask.mask4))
result.mask4 = mask.mask4.toBE()
elif mask.family == AddressFamily.IPv6:
bigEndian64(cast[pointer](addr result.mask6[0]),
cast[pointer](unsafeAddr mask.mask6[0]))
bigEndian64(cast[pointer](addr result.mask6[1]),
cast[pointer](unsafeAddr mask.mask6[1]))
result.mask6[0] = mask.mask6[0].toBE()
result.mask6[1] = mask.mask6[1].toBE()
proc toHostOrder(mask: IpMask): IpMask {.inline.} =
## Converts ``mask`` from network order (which is big-endian) back to
## host representation (which can be big/little-endian).
when system.cpuEndian == bigEndian:
result = mask
else:
result = IpMask(family: mask.family)
if mask.family == AddressFamily.IPv4:
swapEndian32(cast[pointer](addr result.mask4),
cast[pointer](unsafeAddr mask.mask4))
elif mask.family == AddressFamily.IPv6:
swapEndian64(cast[pointer](addr result.mask6[0]),
cast[pointer](unsafeAddr mask.mask6[0]))
swapEndian64(cast[pointer](addr result.mask6[1]),
cast[pointer](unsafeAddr mask.mask6[1]))
result = IpMask(family: mask.family)
if mask.family == AddressFamily.IPv4:
result.mask4 =mask.mask4.fromBE()
elif mask.family == AddressFamily.IPv6:
result.mask6[0] = mask.mask6[0].fromBE()
result.mask6[1] = mask.mask6[1].fromBE()
proc `==`*(m1, m2: IpMask): bool {.inline.} =
## Returns ``true`` if masks ``m1`` and ``m2`` are equal in IP family and
@ -146,7 +138,7 @@ proc init*(t: typedesc[IpMask], netmask: string): IpMask =
else:
return
r = (r shl 4) or v
bigEndian32(addr res.mask4, addr r)
res.mask4 = r.toBE()
result = res
elif length == 32 or length == (2 + 32):
## IPv6 mask
@ -167,7 +159,7 @@ proc init*(t: typedesc[IpMask], netmask: string): IpMask =
return
r = (r shl 4) or v
offset += 16
bigEndian64(addr res.mask6[i], addr r)
res.mask6[i] = r.toBE()
result = res
proc toIPv6*(address: TransportAddress): TransportAddress =
@ -527,32 +519,21 @@ proc `not`*(address: TransportAddress): TransportAddress =
proc `+`*(address: TransportAddress, v: uint): TransportAddress =
## Add to IPv4/IPv6 transport ``address`` unsigned integer ``v``.
result = TransportAddress(family: address.family)
result = TransportAddress(family: address.family, port: address.port)
if address.family == AddressFamily.IPv4:
var a: uint64
let data = cast[ptr uint32](unsafeAddr address.address_v4[0])
when system.cpuEndian == bigEndian:
a = data
else:
swapEndian32(addr a, data)
var a = uint64(uint32.fromBytesBE(address.address_v4))
a = a + v
bigEndian32(cast[pointer](addr result.address_v4[0]), addr a)
result.address_v4[0..<4] = uint32(a).toBytesBE()
elif address.family == AddressFamily.IPv6:
var a1, a2: uint64
let data1 = cast[ptr uint64](unsafeAddr address.address_v6[0])
let data2 = cast[ptr uint64](unsafeAddr address.address_v6[8])
when system.cpuEndian == bigEndian:
a1 = data1
a2 = data2
else:
swapEndian64(addr a1, data1)
swapEndian64(addr a2, data2)
var a1 = uint64.fromBytesBE(address.address_v6[0..<8])
var a2 = uint64.fromBytesBE(address.address_v6[8..<16])
var a3 = a2 + v
if a3 < a2:
## Overflow
a1 = a1 + 1
bigEndian64(cast[pointer](addr result.address_v6[0]), addr a1)
bigEndian64(cast[pointer](addr result.address_v6[8]), addr a3)
cast[ptr uint64](addr result.address_v6[0])[] = a1.toBE()
cast[ptr uint64](addr result.address_v6[8])[] = a3.toBE()
proc inc*(address: var TransportAddress, v: uint = 1'u) =
## Increment IPv4/IPv6 transport ``address`` by unsigned integer ``v``.

View File

@ -6,7 +6,7 @@
# Apache License, version 2.0, (LICENSE-APACHEv2)
# MIT license (LICENSE-MIT)
import unittest
import ../chronos
import ../chronos/transports/[osnet, ipnet]
when defined(nimHasUsed): {.used.}
@ -480,3 +480,20 @@ suite "Network utilities test suite":
route.dest.isUnspecified() == false
route.ifIndex != 0
echo route
test "TransportAddress arithmetic operations test":
var ip4 = initTAddress("192.168.1.0:1024")
var ip6 = initTAddress("[::1]:1024")
when sizeof(int) == 8:
ip4 = ip4 + uint(0xFFFF_FFFF_FFFF_FFFF'u64)
ip6 = ip6 + uint(0xFFFF_FFFF_FFFF_FFFF'u64)
var ip6e = initTAddress("[::1:0000:0000:0000:1]:1024")
else:
ip4 = ip4 + uint(0xFFFF_FFFF'u32)
ip6 = ip6 + uint(0xFFFF_FFFF'u32)
var ip6e = initTAddress("[::1:0000:1]:1024")
inc(ip4)
inc(ip6)
check:
ip4 == initTAddress("192.168.1.0:1024")
ip6 == ip6e